|
|
|
|
namespace Mapbox.Unity.Location
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using Mapbox.Utils;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parses location data and returns Location objects.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class LocationLogReader : LocationLogAbstractBase, IDisposable
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public LocationLogReader(byte[] contents)
|
|
|
|
|
{
|
|
|
|
|
MemoryStream ms = new MemoryStream(contents);
|
|
|
|
|
_textReader = new StreamReader(ms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private bool _disposed;
|
|
|
|
|
private TextReader _textReader;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region idisposable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~LocationLogReader()
|
|
|
|
|
{
|
|
|
|
|
Dispose(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposeManagedResources)
|
|
|
|
|
{
|
|
|
|
|
if (!_disposed)
|
|
|
|
|
{
|
|
|
|
|
if (disposeManagedResources)
|
|
|
|
|
{
|
|
|
|
|
if (null != _textReader)
|
|
|
|
|
{
|
|
|
|
|
#if !NETFX_CORE
|
|
|
|
|
_textReader.Close();
|
|
|
|
|
#endif
|
|
|
|
|
_textReader.Dispose();
|
|
|
|
|
_textReader = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_disposed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns 'Location' objects from the data passed in. Loops through the data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>'Location' objects and loops through the data.</returns>
|
|
|
|
|
public IEnumerator<Location> GetLocations()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
string line = string.Empty;
|
|
|
|
|
|
|
|
|
|
while (1 == 1)
|
|
|
|
|
{
|
|
|
|
|
line = _textReader.ReadLine();
|
|
|
|
|
// rewind if end of log (or last empty line) reached
|
|
|
|
|
if (null == line || string.IsNullOrEmpty(line))
|
|
|
|
|
{
|
|
|
|
|
((StreamReader)_textReader).BaseStream.Position = 0;
|
|
|
|
|
((StreamReader)_textReader).DiscardBufferedData();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip comments
|
|
|
|
|
if (line.StartsWith("#")) { continue; } else { break; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string[] tokens = line.Split(Delimiter.ToCharArray());
|
|
|
|
|
//simple safety net: check if number of columns matches
|
|
|
|
|
if (tokens.Length != HeaderNames.Length)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("unsupported log file");
|
|
|
|
|
yield return new Location();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Location location = new Location();
|
|
|
|
|
|
|
|
|
|
location.IsLocationServiceEnabled = bool.Parse(tokens[(int)LogfileColumns.LocationServiceEnabled]);
|
|
|
|
|
location.IsLocationServiceInitializing = bool.Parse(tokens[(int)LogfileColumns.LocationServiceInitializing]);
|
|
|
|
|
location.IsLocationUpdated = bool.Parse(tokens[(int)LogfileColumns.LocationUpdated]);
|
|
|
|
|
location.IsUserHeadingUpdated = bool.Parse(tokens[(int)LogfileColumns.UserHeadingUpdated]);
|
|
|
|
|
location.Provider = tokens[(int)LogfileColumns.LocationProvider];
|
|
|
|
|
location.ProviderClass = tokens[(int)LogfileColumns.LocationProviderClass];
|
|
|
|
|
|
|
|
|
|
DateTime dtDevice;
|
|
|
|
|
string dtDeviceTxt = tokens[(int)LogfileColumns.UtcTimeDevice];
|
|
|
|
|
if (DateTime.TryParseExact(dtDeviceTxt, "yyyyMMdd-HHmmss.fff", _invariantCulture, DateTimeStyles.AssumeUniversal, out dtDevice))
|
|
|
|
|
{
|
|
|
|
|
location.TimestampDevice = UnixTimestampUtils.To(dtDevice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DateTime dtLocation;
|
|
|
|
|
string dtLocationTxt = tokens[(int)LogfileColumns.UtcTimeOfLocation];
|
|
|
|
|
if (DateTime.TryParseExact(dtLocationTxt, "yyyyMMdd-HHmmss.fff", _invariantCulture, DateTimeStyles.AssumeUniversal, out dtLocation))
|
|
|
|
|
{
|
|
|
|
|
location.Timestamp = UnixTimestampUtils.To(dtLocation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double lat;
|
|
|
|
|
string latTxt = tokens[(int)LogfileColumns.Latitude];
|
|
|
|
|
double lng;
|
|
|
|
|
string lngTxt = tokens[(int)LogfileColumns.Longitude];
|
|
|
|
|
if (
|
|
|
|
|
!double.TryParse(latTxt, NumberStyles.Any, _invariantCulture, out lat)
|
|
|
|
|
|| !double.TryParse(lngTxt, NumberStyles.Any, _invariantCulture, out lng)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
location.LatitudeLongitude = Vector2d.zero;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
location.LatitudeLongitude = new Vector2d(lat, lng);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float accuracy;
|
|
|
|
|
location.Accuracy = float.TryParse(tokens[(int)LogfileColumns.Accuracy], NumberStyles.Any, _invariantCulture, out accuracy) ? accuracy : 0;
|
|
|
|
|
float userHeading;
|
|
|
|
|
location.UserHeading = float.TryParse(tokens[(int)LogfileColumns.UserHeading], NumberStyles.Any, _invariantCulture, out userHeading) ? userHeading : 0;
|
|
|
|
|
float deviceOrientation;
|
|
|
|
|
location.DeviceOrientation = float.TryParse(tokens[(int)LogfileColumns.DeviceOrientation], NumberStyles.Any, _invariantCulture, out deviceOrientation) ? deviceOrientation : 0;
|
|
|
|
|
float speed;
|
|
|
|
|
location.SpeedMetersPerSecond = float.TryParse(tokens[(int)LogfileColumns.Speed], NumberStyles.Any, _invariantCulture, out speed) ? speed / 3.6f : (float?)null;
|
|
|
|
|
bool hasGpsFix;
|
|
|
|
|
location.HasGpsFix = bool.TryParse(tokens[(int)LogfileColumns.HasGpsFix], out hasGpsFix) ? hasGpsFix : (bool?)null;
|
|
|
|
|
int satellitesUsed;
|
|
|
|
|
location.SatellitesUsed = int.TryParse(tokens[(int)LogfileColumns.SatellitesUsed], out satellitesUsed) ? satellitesUsed : (int?)null;
|
|
|
|
|
int satellitesInView;
|
|
|
|
|
location.SatellitesInView = int.TryParse(tokens[(int)LogfileColumns.SatellitesInView], out satellitesInView) ? satellitesInView : (int?)null;
|
|
|
|
|
|
|
|
|
|
yield return location;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|