4 using UnityEngine.Events;
13 [Tooltip(
"If true, override the LocationData's altitude options.")]
14 public bool OverrideAltitude;
16 [Tooltip(
"The override altitude value.")]
17 public double Altitude;
19 [Tooltip(
"The override altitude mode.")]
20 public AltitudeMode AltitudeMode = AltitudeMode.GroundRelative;
27 public enum LocationPropertyType
33 [Tooltip(
"The type of location coordinate input used. Either 'Location' to directly input location " +
34 "coordinates, or 'LocationData' to use a ScriptableObject.")]
35 public LocationPropertyType LocationInputType = LocationPropertyType.
Location;
37 [Tooltip(
"A LocationData ScriptableObject storing the desired GPS coordinates to place the object.")]
40 [Tooltip(
"Input the desired GPS coordinates here.")]
43 [Tooltip(
"Use this to override the LocationData's altitude options.")]
50 [AddComponentMenu(
"AR+GPS/Place At Location")]
51 [HelpURL(
"https://http://docs.unity-ar-gps-location.com/guide/#placeatlocation")]
52 [DisallowMultipleComponent]
64 "The smoothing factor for movement due to GPS location adjustments; if set to zero it is disabled."),
66 public float MovementSmoothing = 0.05f;
69 "The maximum number of times this object will be affected by GPS location updates. Zero means no limits are imposed.")]
70 public int MaxNumberOfLocationUpdates = 4;
72 [Tooltip(
"If true, use a moving average filter.")]
73 public bool UseMovingAverage;
76 "If true, the object will be hidden until the object is placed at the geolocation. If will enable/disable the MeshRenderer or SkinnedMeshRenderer " +
77 "when available, and enable/disable all child game objects.")]
78 public bool HideObjectUntilItIsPlaced =
true;
81 [Tooltip(
"The number of location updates to wait until the object is shown after being initially " +
82 "hidden from view. Only works when 'Hide Object Until It Is Placed' is set to true. If this "+
83 "is set to 0, 'Hide Object Until It Is Placed' will be disabled.")]
84 public uint ShowObjectAfterThisManyUpdates = 1;
96 if (LocationInput.LocationInputType ==
99 if (LocationInput.LocationData ==
null)
101 Debug.LogWarning(
"[AR+GPS][LocationSettingsData#GetLocation]: " +
102 "Null LocationData; falling back to Location. When using `Location Input Type = Location Data` " +
103 "make sure you associate a LocationData ScriptableObject to it.");
105 location = LocationInput.Location.
Clone();
111 if (LocationInput.OverrideAltitudeData.OverrideAltitude)
113 location.Altitude = LocationInput.OverrideAltitudeData.Altitude;
114 location.AltitudeMode = LocationInput.OverrideAltitudeData.AltitudeMode;
120 location = LocationInput.Location.
Clone();
131 public uint LocationUpdatedCount;
132 public uint PositionUpdatedCount;
143 [Tooltip(
"When debug mode is enabled, this component will print relevant messages to the console. Filter by 'PlateAtLocation' in the log output to see the messages. It will also " +
144 "display the direction from the user to the object on the screen, as well as a line renderer from the camera to the object location. To customize how this line looks, add " +
145 "a Line Renderer component to this game object.")]
146 public bool DebugMode;
153 "Event called when the object's location is updated. The arguments are the current GameObject, the location, and the number of location updates received " +
154 "by the object so far.")]
158 "Event called when the object's position is updated after a location update. " +
159 "If the Movement Smoothing is larger than 0, this will fire at a later time than the Location Updated event. The arguments are the current GameObject, the location, and the number of position updates received " +
160 "by the object so far.")]
166 get => state.Location;
172 LocationOptions.LocationInput.LocationInputType =
175 LocationOptions.LocationInput.LocationData =
null;
176 LocationOptions.LocationInput.Location = value.
Clone();
181 if (groundHeight !=
null)
183 groundHeight.Settings.Altitude = (float) value.Altitude;
186 state.Location = value.
Clone();
191 public float SceneDistance
195 var cameraPos = mainCameraTransform.position;
197 return Vector3.Distance(cameraPos, transform.position);
201 public double RawGpsDistance =>
202 Location.HorizontalDistance(locationProvider.Provider.CurrentLocationRaw.ToLocation(),
208 set => state.Paused = value;
211 public bool UseGroundHeight => state.Location.AltitudeMode == AltitudeMode.GroundRelative;
213 private StateData state =
new StateData();
215 private ARLocationProvider locationProvider;
216 private Transform arLocationRoot;
217 private SmoothMove smoothMove;
218 private MovingAveragePosition movingAverageFilter;
219 private GameObject debugPanel;
220 private ARLocationManager arLocationManager;
221 private Transform mainCameraTransform;
222 private bool hasInitialized;
223 private GroundHeight groundHeight;
228 locationProvider = ARLocationProvider.Instance;
229 arLocationManager = ARLocationManager.Instance;
230 arLocationRoot = arLocationManager.gameObject.transform;
231 mainCameraTransform = arLocationManager.MainCamera.transform;
233 if (locationProvider ==
null)
235 Debug.LogError(
"[AR+GPS][PlaceAtLocation]: LocationProvider GameObject or Component not found.");
241 hasInitialized =
true;
244 public void Restart()
246 Logger.LogFromMethod(
"PlaceAtLocation",
"Restart", $
"({gameObject.name}) - Restarting!", DebugMode);
248 RemoveLocationProviderListeners();
250 state =
new StateData();
253 if (locationProvider.IsEnabled)
255 locationUpdatedHandler(locationProvider.CurrentLocation, locationProvider.LastLocation);
261 state.Location = LocationOptions.GetLocation();
263 Transform transform1;
264 (transform1 = transform).SetParent(arLocationRoot.transform,
false);
265 transform1.localPosition = Vector3.zero;
269 if (PlacementOptions.HideObjectUntilItIsPlaced)
271 Misc.HideGameObject(gameObject);
274 if (PlacementOptions.MovementSmoothing > 0)
276 smoothMove = SmoothMove.AddSmoothMove(gameObject, PlacementOptions.MovementSmoothing);
281 groundHeight = gameObject.AddComponent<GroundHeight>();
282 groundHeight.Settings.Altitude = (float) state.Location.Altitude;
285 if (PlacementOptions.UseMovingAverage)
287 movingAverageFilter =
new MovingAveragePosition
289 aMax = locationProvider.Provider.Options.AccuracyRadius > 0
290 ? locationProvider.Provider.Options.AccuracyRadius
300 if (PlacementOptions.ShowObjectAfterThisManyUpdates == 0)
302 PlacementOptions.HideObjectUntilItIsPlaced =
false;
305 RegisterLocationProviderListeners();
308 Logger.LogFromMethod(
"PlaceAtLocation",
"Initialize", $
"({gameObject.name}) initialized object with geo-location {state.Location}", DebugMode);
311 private void RegisterLocationProviderListeners()
315 locationProvider.OnLocationUpdatedEvent(locationUpdatedHandler,
true);
317 locationProvider.OnProviderRestartEvent(ProviderRestarted);
320 private void RemoveLocationProviderListeners()
322 locationProvider.OnLocationUpdatedDelegate -= locationUpdatedHandler;
323 locationProvider.OnRestartDelegate -= ProviderRestarted;
326 private void ProviderRestarted()
328 Logger.LogFromMethod(
"PlaceAtLocation",
"ProviderRestarted", $
"({gameObject.name})", DebugMode);
330 state.LocationUpdatedCount = 0;
331 state.PositionUpdatedCount = 0;
334 private void locationUpdatedHandler(LocationReading currentLocation, LocationReading lastLocation)
336 UpdatePosition(currentLocation.ToLocation());
339 public void UpdatePosition(Location deviceLocation,
bool forceUpdate =
false)
341 Logger.LogFromMethod(
"PlaceAtLocation",
"UpdatePosition", $
"({gameObject.name}): Received location update, location = {deviceLocation}", DebugMode);
345 Logger.LogFromMethod(
"PlaceAtLocation",
"UpdatePosition", $
"({gameObject.name}): Updates are paused; returning", DebugMode);
349 Vector3 targetPosition;
350 var location = state.Location;
351 var useSmoothMove = smoothMove !=
null;
352 var isHeightRelative = location.AltitudeMode == AltitudeMode.DeviceRelative;
354 if ((PlacementOptions.MaxNumberOfLocationUpdates > 0) &&
355 (state.LocationUpdatedCount >= PlacementOptions.MaxNumberOfLocationUpdates) && !forceUpdate)
361 if (movingAverageFilter !=
null)
364 arLocationRoot, mainCameraTransform, deviceLocation, location, isHeightRelative
367 var accuracy = locationProvider.CurrentLocation.accuracy;
369 movingAverageFilter.AddEntry(
new DVector3(position), accuracy);
371 targetPosition = movingAverageFilter.CalculateAveragePosition().toVector3();
376 arLocationRoot, mainCameraTransform, deviceLocation, location, isHeightRelative
383 targetPosition.y = transform.position.y;
387 smoothMove.SmoothMoveMode = SmoothMove.Mode.Horizontal;
391 Logger.LogFromMethod(
"PlaceAtLocation",
"UpdatePosition", $
"({gameObject.name}): Moving object to target position {targetPosition}", DebugMode);
393 if (useSmoothMove && state.PositionUpdatedCount > 0)
395 Logger.LogFromMethod(
"PlaceAtLocation",
"UpdatePosition", $
"({gameObject.name}): Using smooth move...", DebugMode);
396 smoothMove.Move(targetPosition, PositionUpdated);
400 transform.position = targetPosition;
404 state.LocationUpdatedCount++;
405 ObjectLocationUpdated?.Invoke(gameObject, location, (
int) state.LocationUpdatedCount);
408 private void PositionUpdated()
410 if (PlacementOptions.HideObjectUntilItIsPlaced)
412 if (state.PositionUpdatedCount == (PlacementOptions.ShowObjectAfterThisManyUpdates - 1))
414 Misc.ShowGameObject(gameObject);
418 state.PositionUpdatedCount++;
420 Logger.LogFromMethod(
"PlaceAtLocation",
"PositionUpdated", $
"({gameObject.name}): Object position updated! PositionUpdatedCount = {state.PositionUpdatedCount}, transform.position = {transform.position}", DebugMode);
422 ObjectPositionUpdated?.Invoke(gameObject, state.Location, (
int) state.PositionUpdatedCount);
425 public static GameObject CreatePlacedInstance(GameObject go, Location location, PlaceAtOptions options,
bool useDebugMode =
false)
427 var instance = Instantiate(go, ARLocationManager.Instance.gameObject.transform);
429 AddPlaceAtComponent(instance, location, options, useDebugMode);
434 public static PlaceAtLocation AddPlaceAtComponent(GameObject go, Location location, PlaceAtOptions options,
435 bool useDebugMode =
false)
437 var placeAt = go.AddComponent<PlaceAtLocation>();
439 placeAt.PlacementOptions = options;
440 placeAt.LocationOptions.LocationInput.LocationInputType =
441 LocationPropertyData.LocationPropertyType.Location;
442 placeAt.LocationOptions.LocationInput.Location = location.Clone();
443 placeAt.DebugMode = useDebugMode;
448 public static GameObject CreatePlacedInstanceAtWorldPosition(GameObject go, Vector3 worldPosition, PlaceAtOptions options, out Location location,
bool useDebugMode =
false)
450 location = ARLocationProvider.Instance.GetLocationForWorldPosition(worldPosition);
452 return CreatePlacedInstance(go, location, options, useDebugMode);
456 private void OnDestroy()
458 RemoveLocationProviderListeners();