ARLocationProvider.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. using System;
  2. using System.Collections;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. using UnityEngine.Serialization;
  6. // ReSharper disable UnusedMember.Global
  7. namespace ARLocation
  8. {
  9. using Utils;
  10. [AddComponentMenu("AR+GPS/AR Location Provider")]
  11. [HelpURL("https://http://docs.unity-ar-gps-location.com/guide/#arlocationprovider")]
  12. [DisallowMultipleComponent]
  13. public class ARLocationProvider : Singleton<ARLocationProvider>
  14. {
  15. [Serializable]
  16. public class LocationEnabledUnityEvent : UnityEvent<Location> {}
  17. [Serializable]
  18. public class LocationUpdatedUnityEvent : UnityEvent<Location> {}
  19. [Serializable]
  20. public class CompassUpdatedUnityEvent: UnityEvent<HeadingReading> {}
  21. [FormerlySerializedAs("LocationUpdateSettings")]
  22. [Tooltip("The options for the Location Provider.")]
  23. [Header("Update Settings")]
  24. public LocationProviderOptions LocationProviderSettings = new LocationProviderOptions();
  25. [Tooltip("The data of mock location. If present, overrides the Mock Location above.")]
  26. [Header("Mock Data")]
  27. public LocationData MockLocationData;
  28. [Tooltip("The maximum wait time to wait for location initialization.")]
  29. [Header("Initialization")]
  30. public uint MaxWaitTime = 200;
  31. [Tooltip("Wait this many seconds before starting location services. Useful when using Unity Remote.")]
  32. public uint StartUpDelay;
  33. [Header("Debug")]
  34. [Tooltip("When debug mode is enabled, this component will print relevant messages to the console. Filter by 'ARLocationProvider' in the log output to see the messages.")]
  35. public bool DebugMode;
  36. [Header("Events")]
  37. [Tooltip("Called after the first location is read.")]
  38. public LocationEnabledUnityEvent OnEnabled = new LocationEnabledUnityEvent();
  39. [Tooltip("Called after each new location update.")]
  40. public LocationUpdatedUnityEvent OnLocationUpdated = new LocationUpdatedUnityEvent();
  41. [Tooltip("Called after each new raw device GPS data is obtained.")]
  42. public LocationUpdatedUnityEvent OnRawLocationUpdated = new LocationUpdatedUnityEvent();
  43. [Tooltip("Called after each new compass update.")]
  44. public CompassUpdatedUnityEvent OnCompassUpdated = new CompassUpdatedUnityEvent();
  45. /// <summary>
  46. /// Returns the current location provider.
  47. /// </summary>
  48. public ILocationProvider Provider { get; private set; }
  49. /// <summary>
  50. /// If true, the location provider has received the first location data.
  51. /// </summary>
  52. public bool IsEnabled => Provider.IsEnabled;
  53. /// <summary>
  54. /// If true, the location provider has started, but no location data has been read.
  55. /// </summary>
  56. public bool HasStarted => Provider.HasStarted;
  57. /// <summary>
  58. /// The number of location updates so far.
  59. /// </summary>
  60. public int LocationUpdateCount => Provider.LocationUpdateCount;
  61. /// <summary>
  62. /// If true, updates are paused.
  63. /// </summary>
  64. public bool IsPaused => Provider.Paused;
  65. /// <summary>
  66. /// The latest location data.
  67. /// </summary>
  68. public LocationReading CurrentLocation => Provider.CurrentLocation;
  69. /// <summary>
  70. /// The previous location data.
  71. /// </summary>
  72. public LocationReading LastLocation => Provider.LastLocation;
  73. /// <summary>
  74. /// The current heading data.
  75. /// </summary>
  76. public HeadingReading CurrentHeading => Provider.CurrentHeading;
  77. /// <summary>
  78. /// Time since the location provider has started.
  79. /// </summary>
  80. public float TimeSinceStart => Time.time - Provider.StartTime;
  81. /// <summary>
  82. /// The distance from the initial measured position.
  83. /// </summary>
  84. public double DistanceFromStartPoint => Provider.DistanceFromStartPoint;
  85. private int measurementCount;
  86. private bool mute;
  87. public event LocationUpdatedDelegate OnLocationUpdatedDelegate;
  88. public event CompassUpdateDelegate OnCompassUpdateDelegate;
  89. public event Action OnRestartDelegate;
  90. public override void Awake()
  91. {
  92. base.Awake();
  93. #if UNITY_EDITOR
  94. Provider = new MockLocationProvider();
  95. if (MockLocationData != null)
  96. {
  97. Logger.LogFromMethod("ARLocationProvider", "Awake", $"Using mock location {MockLocationData}", DebugMode);
  98. ((MockLocationProvider) Provider).mockLocation = MockLocationData.Location;
  99. }
  100. #elif ARGPS_CUSTOM_PROVIDER
  101. // If you want to use a custom location provider, add 'ARGPS_CUSTOM_PROVIDER' to the define symbols in the Player
  102. // settings, create a implementation of ILocationProvider, and instantiate it in the line below.
  103. Provider = new ARGpsCustomLocationProvider();
  104. #else
  105. Provider = new UnityLocationProvider();
  106. #endif
  107. Logger.LogFromMethod("ARLocationProvider", "Awake",": Using provider " + Provider.Name, DebugMode);
  108. }
  109. private void InitProviderEventListeners()
  110. {
  111. Logger.LogFromMethod("ARLocationProvider", "InitProviderEventListeners","Initializing location provider listeners.", DebugMode);
  112. Provider.LocationUpdated += Provider_LocationUpdated;
  113. Provider.CompassUpdated += Provider_CompassUpdated;
  114. Provider.LocationUpdatedRaw += ProviderOnLocationUpdatedRaw;
  115. Provider.OnEnabled(OnProviderEnabledDelegate);
  116. if (Provider.IsEnabled)
  117. {
  118. ForceLocationUpdate();
  119. }
  120. }
  121. private void ProviderOnLocationUpdatedRaw(LocationReading currentLocation, LocationReading lastLocation)
  122. {
  123. OnRawLocationUpdated?.Invoke(currentLocation.ToLocation());
  124. }
  125. private void OnProviderEnabledDelegate()
  126. {
  127. Logger.LogFromMethod("ARLocationProvider", "OnProviderEnabledDelegate","Provider enabled; emitting 'OnEnabled' event.", DebugMode);
  128. OnEnabled?.Invoke(CurrentLocation.ToLocation());
  129. }
  130. IEnumerator Start()
  131. {
  132. InitProviderEventListeners();
  133. Provider.Options = LocationProviderSettings;
  134. Logger.LogFromMethod("ARLocationProvider", "Start","Starting the location provider", DebugMode);
  135. yield return StartCoroutine(Provider.Start(MaxWaitTime, StartUpDelay));
  136. }
  137. public void Mute()
  138. {
  139. Logger.LogFromMethod("ARLocationProvider", "Mute","Muting ARLocationProvider.", DebugMode);
  140. mute = true;
  141. }
  142. public void Unmute(bool emit = true)
  143. {
  144. Logger.LogFromMethod("ARLocationProvider", "Mute","Un-muting ARLocationProvider.", DebugMode);
  145. mute = false;
  146. if (Provider.IsEnabled && emit) ForceLocationUpdate();
  147. }
  148. private void Provider_CompassUpdated(HeadingReading heading, HeadingReading lastReading)
  149. {
  150. if (mute) return;
  151. OnCompassUpdateDelegate?.Invoke(heading, lastReading);
  152. OnCompassUpdated?.Invoke(heading);
  153. }
  154. private void Provider_LocationUpdated(LocationReading currentLocation, LocationReading lastLocation)
  155. {
  156. if (mute) return;
  157. measurementCount++;
  158. if ((LocationProviderSettings.MaxNumberOfUpdates > 0) && (measurementCount >= LocationProviderSettings.MaxNumberOfUpdates))
  159. {
  160. Provider.Pause();
  161. }
  162. Logger.LogFromMethod("ARLocationProvider", "Provider_LocationUpdated",$"New location {currentLocation}.", DebugMode);
  163. OnLocationUpdatedDelegate?.Invoke(currentLocation, lastLocation);
  164. OnLocationUpdated?.Invoke(currentLocation.ToLocation());
  165. }
  166. /// <summary>
  167. /// Force the provider to emit a location update event. This wont force a new read of location, just emit
  168. /// the last available measurement.
  169. /// </summary>
  170. public void ForceLocationUpdate()
  171. {
  172. Logger.LogFromMethod("ARLocationProvider", "ForceLocationUpdate","Emitting a forced location update", DebugMode);
  173. Provider.ForceLocationUpdate();
  174. }
  175. void Update()
  176. {
  177. if (Provider == null || !Provider.HasStarted)
  178. {
  179. return;
  180. }
  181. Provider.Update();
  182. }
  183. /// <summary>
  184. /// Pauses location updates
  185. /// </summary>
  186. public void Pause()
  187. {
  188. Logger.LogFromMethod("ARLocationProvider", "Pause","Pausing the location provider.", DebugMode);
  189. Provider?.Pause();
  190. }
  191. /// <summary>
  192. /// Resumes location updates
  193. /// </summary>
  194. public void Resume()
  195. {
  196. Logger.LogFromMethod("ARLocationProvider", "Resume","Resuming the location provider.", DebugMode);
  197. Provider?.Resume();
  198. }
  199. /// <summary>
  200. /// Resets the location provider.
  201. /// </summary>
  202. public void Restart()
  203. {
  204. Logger.LogFromMethod("ARLocationProvider", "Restart","Restarting the location provider.", DebugMode);
  205. Provider?.Restart();
  206. OnRestartDelegate?.Invoke();
  207. }
  208. /// <summary>
  209. /// Register a delegate to location updates.
  210. ///
  211. /// The `useRawIfEnabled` method if for situations where we want the latest data,
  212. /// like when we are adding objects at runtime.
  213. ///
  214. /// </summary>
  215. /// <param name="locationUpdatedDelegate"></param>
  216. /// <param name="useRawIfEnabled"></param>
  217. public void OnLocationUpdatedEvent(LocationUpdatedDelegate locationUpdatedDelegate, bool useRawIfEnabled = false)
  218. {
  219. if (IsEnabled)
  220. {
  221. locationUpdatedDelegate(CurrentLocation, useRawIfEnabled ? Provider.LastLocationRaw : LastLocation);
  222. }
  223. OnLocationUpdatedDelegate += locationUpdatedDelegate;
  224. }
  225. public void OnProviderRestartEvent(Action del)
  226. {
  227. OnRestartDelegate += del;
  228. }
  229. /// <summary>
  230. /// Register a delegate to compass/heading updates.
  231. /// </summary>
  232. /// <param name="compassUpdateDelegate"></param>
  233. public void OnCompassUpdatedEvent(CompassUpdateDelegate compassUpdateDelegate)
  234. {
  235. OnCompassUpdateDelegate += compassUpdateDelegate;
  236. }
  237. /// <summary>
  238. /// RegisterRegister delegate for when the provider enables location updates.
  239. /// </summary>
  240. /// <param name="del">Del.</param>
  241. public void OnEnabledEvent(LocationEnabledDelegate del)
  242. {
  243. Provider.OnEnabled(del);
  244. }
  245. /// <summary>
  246. /// Register a delegate for when the provider fails to initialize location services.
  247. /// </summary>
  248. /// <param name="del">Del.</param>
  249. public void OnFailedEvent(LocationFailedDelegate del)
  250. {
  251. Provider.OnFail(del);
  252. }
  253. }
  254. }