123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- using System.Collections;
- using UnityEngine;
- #if PLATFORM_ANDROID
- using UnityEngine.Android;
- #endif
- namespace ARLocation
- {
- /// <summary>
- /// Abstract location provider. All concrete location provider implementations
- /// should derive from this.
- /// </summary>
- public abstract class AbstractLocationProvider : ILocationProvider
- {
- protected double LowPassFilterFactor;
- /// <summary>
- /// The name of the location provider.
- /// </summary>
- /// <value>The name.</value>
- public abstract string Name { get; }
- /// <summary>
- /// The options of the location provider.
- /// </summary>
- /// <value>The options.</value>
- public LocationProviderOptions Options { get; set; }
- /// <summary>
- /// Gets or sets the current location.
- /// </summary>
- /// <value>The current location.</value>
- public LocationReading CurrentLocation { get; protected set; }
- /// <summary>
- /// Gets or sets the previous location.
- /// </summary>
- /// <value>The last location.</value>
- public LocationReading LastLocation { get; protected set; }
- public LocationReading LastLocationRaw { get; protected set; }
- /// <summary>
- /// Gets or sets the previous raw location reading.
- /// </summary>
- /// <value>The raw location last.</value>
- public LocationReading CurrentLocationRaw { get; protected set; }
- /// <summary>
- /// The current heading reading.
- /// </summary>
- /// <value>The current heading.</value>
- public HeadingReading CurrentHeading { get; protected set; }
- /// <summary>
- /// The previous heading reading.
- /// </summary>
- /// <value>The last heading.</value>
- public HeadingReading LastHeading { get; protected set; }
- /// <summary>
- /// The start point, i.e., the first measured location.
- /// </summary>
- /// <value>The start point.</value>
- public LocationReading FirstLocation { get; protected set; }
- /// <summary>
- /// Gets or sets the current status of the location provider.
- /// </summary>
- /// <value>The status.</value>
- public LocationProviderStatus Status { get; protected set; }
- /// <summary>
- /// If true, the location provider is enablied and getting regular location
- /// updated from the device.
- /// </summary>
- /// <value><c>true</c> if is enabled; otherwise, <c>false</c>.</value>
- public bool IsEnabled { get; protected set; }
- /// <summary>
- /// If true, the first reading has not occured yet.
- /// </summary>
- /// <value><c>true</c> if first reading; otherwise, <c>false</c>.</value>
- public bool FirstReading { get; protected set; }
- /// <summary>
- /// If true, the provider has a functioning magnetic compass sensor.
- /// </summary>
- /// <value><c>true</c> if is compass enabled; otherwise, <c>false</c>.</value>
- public abstract bool IsCompassEnabled { get; }
- /// <summary>
- /// The start time of the location provider.
- /// </summary>
- /// <value>The start time.</value>
- public float StartTime { get; protected set; }
- /// <summary>
- /// If true, location updates are paused.
- /// </summary>
- public bool Paused { get; protected set; }
- public int LocationUpdateCount { get; protected set; }
- public bool HasStarted => Status == LocationProviderStatus.Started;
- public bool ApplyCompassTiltCompensationOnAndroid { get; set; } = true;
- public double DistanceFromStartPoint
- {
- get { return LocationReading.HorizontalDistance(FirstLocation, CurrentLocation); }
- }
- /// <summary>
- /// Event for when a new location data is received.
- /// </summary>
- public event LocationUpdatedDelegate LocationUpdated;
- /// <summary>
- /// Event for when a new compass data is received.
- /// </summary>
- public event CompassUpdateDelegate CompassUpdated;
- public event LocationEnabledDelegate LocationEnabled;
- public event LocationFailedDelegate LocationFailed;
- public event LocationUpdatedDelegate LocationUpdatedRaw;
- /// <summary>
- /// Reads the location from the device; should be implemented by each
- /// provider.
- /// </summary>
- /// <returns>The location.</returns>
- protected abstract LocationReading? ReadLocation();
- /// <summary>
- /// Reads the heading from the device; should be implemented by each
- /// provider.
- /// </summary>
- /// <returns>The heading.</returns>
- protected abstract HeadingReading? ReadHeading();
- /// <summary>
- /// Requests the location and compass updates from the device; should be implemented by each
- /// provider.
- /// </summary>
- protected abstract void RequestLocationAndCompassUpdates();
- /// <summary>
- /// Updates the location service status from the device; should be implemented by each
- /// provider.
- /// </summary>
- protected abstract void UpdateLocationRequestStatus();
- protected AbstractLocationProvider()
- {
- IsEnabled = false;
- FirstReading = true;
- Paused = false;
- Status = LocationProviderStatus.Idle;
- }
- public virtual IEnumerator Start(uint maxWaitTime = 10000, uint delay = 0)
- {
- // Debug.Log("[AbstractLocationProvider]: Starting...");
- #if PLATFORM_ANDROID
- if (!Permission.HasUserAuthorizedPermission(Permission.FineLocation))
- {
- Permission.RequestUserPermission(Permission.FineLocation);
- }
- yield return new WaitForSeconds(1);
- #endif
- if (delay > 0)
- {
- yield return new WaitForSeconds(delay);
- }
- RequestLocationAndCompassUpdates();
- uint maxWait = maxWaitTime;
- UpdateLocationRequestStatus();
- while (Status == LocationProviderStatus.Initializing && maxWait > 0)
- {
- // Debug.Log("[AbstractLocationProvider]: Wait... " + maxWait);
- yield return new WaitForSeconds(1);
- maxWait--;
- UpdateLocationRequestStatus();
- }
- if (maxWait < 1)
- {
- // Debug.LogError("[AbstractLocationProvider]: Timed out.");
- LocationFailed?.Invoke("Timed out");
- yield break;
- }
- if (Status == LocationProviderStatus.Failed)
- {
- // Debug.LogError("[AbstractLocationProvider]: Falied to initialize location updates.");
- LocationFailed?.Invoke("Falied to initialize location updates.");
- yield break;
- }
- if (Status != LocationProviderStatus.Started)
- {
- // Debug.LogError("[AbstractLocationProvider]: Unknown error initializing location updates. " + Status);
- LocationFailed?.Invoke("Unknown error initializing location updates.");
- yield break;
- }
- // Debug.Log("[AbstractLocationProvider]: Started!");
- FirstReading = true;
- StartTime = Time.time;
- }
- public void ForceLocationUpdate()
- {
- LocationUpdated?.Invoke(CurrentLocation, LastLocation);
- LocationUpdatedRaw?.Invoke(CurrentLocationRaw, LastLocationRaw);
- }
- protected virtual void InnerOnEnabled()
- {
- }
- protected void EmitLocationUpdated()
- {
- LocationUpdated?.Invoke(CurrentLocation, LastLocation);
- }
- protected void EmitLocationUpdatedRaw()
- {
- LocationUpdatedRaw?.Invoke(CurrentLocationRaw, LastLocationRaw);
- }
- protected void EmitCompassUpdated()
- {
- CompassUpdated?.Invoke(CurrentHeading, LastHeading);
- }
- protected void UpdateLocation(LocationReading newLocation)
- {
- if (newLocation.timestamp == CurrentLocationRaw.timestamp)
- {
- return;
- }
- LastLocationRaw = CurrentLocationRaw;
- CurrentLocationRaw = newLocation;
- EmitLocationUpdatedRaw();
- if (!ShouldUpdateLocation(newLocation))
- {
- return;
- }
- LastLocation = CurrentLocation;
- CurrentLocation = newLocation;
- LocationUpdateCount++;
- EmitLocationUpdated();
- }
- protected void UpdateHeading(HeadingReading newHeading)
- {
- if (!ShouldUpdateHeading(newHeading))
- {
- return;
- }
- LastHeading = CurrentHeading;
- CurrentHeading = newHeading;
- EmitCompassUpdated();
- }
- protected bool ShouldUpdateHeading(HeadingReading newHeading)
- {
- if (newHeading.timestamp == CurrentHeading.timestamp)
- {
- return false;
- }
- return true;
- }
- protected bool ShouldUpdateLocation(LocationReading newLocation)
- {
- if (Paused)
- {
- return false;
- }
- if (newLocation.timestamp - CurrentLocation.timestamp < ((long) (Options.TimeBetweenUpdates * 1000)))
- {
- return false;
- }
- if (LocationReading.HorizontalDistance(newLocation, CurrentLocation) < Options.MinDistanceBetweenUpdates)
- {
- return false;
- }
- if ((newLocation.accuracy > Options.AccuracyRadius) && (Options.AccuracyRadius > 0))
- {
- return false;
- }
- return true;
- }
- public virtual void Update()
- {
- if (!HasStarted)
- {
- return;
- }
- var location = ReadLocation();
- var heading = ReadHeading();
- if (location == null || heading == null)
- {
- // Debug.Log("[AbstractLocationProvider]: Null reading");
- return;
- }
- if (FirstReading)
- {
- FirstLocation = location.Value;
- CurrentLocation = FirstLocation;
- CurrentLocationRaw = FirstLocation;
- CurrentHeading = heading.Value;
- IsEnabled = true;
- FirstReading = false;
- LocationEnabled?.Invoke();
- InnerOnEnabled();
- EmitCompassUpdated();
- EmitLocationUpdated();
- EmitLocationUpdatedRaw();
- return;
- }
- UpdateLocation(location.Value);
- UpdateHeading(heading.Value);
- }
- public void Restart()
- {
- LocationUpdateCount = 0;
- FirstReading = true;
- }
- public void ResetStartPoint()
- {
- FirstLocation = CurrentLocation;
- }
- public void SetCompassLowPassFactor(double factor)
- {
- LowPassFilterFactor = factor;
- }
- public string GetStatusString()
- {
- switch (Status)
- {
- case LocationProviderStatus.Idle:
- return "Idle";
- case LocationProviderStatus.Failed:
- return "Failed";
- case LocationProviderStatus.Initializing:
- return "Initializing";
- case LocationProviderStatus.Started:
- return "Started";
- }
- return "UnknownStatus";
- }
- public string GetInfoString()
- {
- return Name +
- "{ \n" +
- CurrentLocation + "\n" +
- CurrentHeading + "\n" +
- "Status = " + GetStatusString() + "\n" +
- "DistanceFromStartPoint = " + DistanceFromStartPoint + "\n" +
- "TimeSinceStart = " + (Time.time - StartTime) + "\n" +
- "}";
- }
- public void OnEnabled(LocationEnabledDelegate del)
- {
- LocationEnabled += del;
- if (IsEnabled)
- {
- del();
- }
- }
- public void OnFail(LocationFailedDelegate del)
- {
- LocationFailed += del;
- }
- /// <summary>
- /// Pauses location updates
- /// </summary>
- public void Pause()
- {
- Paused = true;
- }
- /// <summary>
- /// Resumes location updates
- /// </summary>
- public void Resume()
- {
- Paused = false;
- }
- }
- }
|