Example #1
0
        /// <summary>
        /// Distance in metres between two points expressed as longitude/latitude
        /// </summary>
        /// <param name="longLat0">longitude and latitude for first point</param>
        /// <param name="longLat1">longitude and latitude for second point</param>
        /// <returns></returns>
        public static double DistancePointToPointLongLat(LongLat longLat0, LongLat longLat1)
        {
            // use spherical coordinates: rho, phi, theta
            const double rho = 6378200; // earth radius in metres

            double sinPhi0   = Math.Sin(0.5 * Math.PI + longLat0.Latitude / 180.0 * Math.PI);
            double cosPhi0   = Math.Cos(0.5 * Math.PI + longLat0.Latitude / 180.0 * Math.PI);
            double sinTheta0 = Math.Sin(longLat0.Longitude / 180.0 * Math.PI);
            double cosTheta0 = Math.Cos(longLat0.Longitude / 180.0 * Math.PI);

            double sinPhi1   = Math.Sin(0.5 * Math.PI + longLat1.Latitude / 180.0 * Math.PI);
            double cosPhi1   = Math.Cos(0.5 * Math.PI + longLat1.Latitude / 180.0 * Math.PI);
            double sinTheta1 = Math.Sin(longLat1.Longitude / 180.0 * Math.PI);
            double cosTheta1 = Math.Cos(longLat1.Longitude / 180.0 * Math.PI);

            var p0 = new GeneralMatrix(3, 1);

            p0.SetElement(0, 0, rho * sinPhi0 * cosTheta0);
            p0.SetElement(1, 0, rho * sinPhi0 * sinTheta0);
            p0.SetElement(2, 0, rho * cosPhi0);

            var p1 = new GeneralMatrix(3, 1);

            p1.SetElement(0, 0, rho * sinPhi1 * cosTheta1);
            p1.SetElement(1, 0, rho * sinPhi1 * sinTheta1);
            p1.SetElement(2, 0, rho * cosPhi1);

            double distance = DistancePointToPoint(p0, p1);

            return(distance);
        }
Example #2
0
        private static LongLat ReadLongLat(BinaryReader br)
        {
            var longLat = new LongLat();

            longLat.Longitude = (double)br.ReadInt32() / 3600000;
            longLat.Latitude  = (double)br.ReadInt32() / 3600000;
            return(longLat);
        }
Example #3
0
 public bool Equals(LongLat other)
 {
     if (other == null)
     {
         return(false);
     }
     return(longitude == other.Longitude && latitude == other.Latitude);
 }
Example #4
0
        public static GeneralMatrix To3x1Matrix(LongLat longLat)
        {
            GeneralMatrix m = new GeneralMatrix(3, 1);

            m.SetElement(0, 0, longLat.Longitude);
            m.SetElement(1, 0, longLat.Latitude);
            m.SetElement(2, 0, 1);
            return(m);
        }
Example #5
0
        /// <summary>
        /// Speed in metres per second
        /// </summary>
        /// <param name="longLat0">longitude and latitude for first point</param>
        /// <param name="longLat1">longitude and latitude for second point</param>
        /// <param name="t0">time for first point</param>
        /// <param name="t1">time for first point</param>
        /// <returns></returns>
        public static double CalculateSpeed(LongLat longLat0, LongLat longLat1, DateTime t0, DateTime t1)
        {
            double   distance = DistancePointToPointLongLat(longLat0, longLat1);
            TimeSpan timeSpan = t1.Subtract(t0);

            double speed = distance / timeSpan.TotalSeconds;

            return(speed);
        }
Example #6
0
        public static byte[] GetExifGpsPosition(LongLat longLat)
        {
            var lng    = BitConverter.GetBytes(Convert.ToInt32(longLat.Longitude * 3600000));
            var lat    = BitConverter.GetBytes(Convert.ToInt32(longLat.Latitude * 3600000));
            var x      = BitConverter.GetBytes((int)int.MinValue + 1);
            var result = new byte[8];

            lng.CopyTo(result, 0);
            lat.CopyTo(result, 4);
            return(result);
        }
Example #7
0
        /// <summary>
        /// Applies an ortographic projection to the coordinate.
        /// http://en.wikipedia.org/wiki/Orthographic_projection_%28cartography%29
        /// </summary>
        /// <param name="projectionOrigin">The origin longitude/latitude coordinate of the projection</param>
        /// <returns>A point that gives the distance in meters from the projection origin</returns>
        public PointD Project(LongLat projectionOrigin)
        {
            const double rho     = 6378200; // earth radius in metres
            double       lambda0 = projectionOrigin.Longitude * Math.PI / 180.0;
            double       phi0    = projectionOrigin.Latitude * Math.PI / 180.0;

            double lambda = longitude * Math.PI / 180.0;
            double phi    = latitude * Math.PI / 180.0;

            return(new PointD(rho * Math.Cos(phi) * Math.Sin(lambda - lambda0),
                              rho * (Math.Cos(phi0) * Math.Sin(phi) - Math.Sin(phi0) * Math.Cos(phi) * Math.Cos(lambda - lambda0))));
        }
Example #8
0
 protected Document(SerializationInfo info, StreamingContext context)
 {
     Map              = (Map)(info.GetValue("map", typeof(Map)));
     settings         = (DocumentSettings)(info.GetValue("settings", typeof(DocumentSettings)));
     sessions         = (SessionCollection)(info.GetValue("sessions", typeof(SessionCollection)));
     projectionOrigin = (LongLat)(info.GetValue("projectionOrigin", typeof(LongLat)));
     // todo: how handle non-existing properties field?
     try
     {
         properties = (DocumentProperties)(info.GetValue("properties", typeof(DocumentProperties)));
     }
     catch (Exception)
     { }
 }
Example #9
0
        public Transformation(LongLatBox longLatBox, Size imageSize)
        {
            // calculate projection origin
            ProjectionOrigin = new LongLat((longLatBox.East + longLatBox.West) / 2,
                                           (longLatBox.North + longLatBox.South) / 2);

            // get image corners from kml file
            var imageCornerLongLats = longLatBox.GetRotatedBoxCornerLongLats();

            // project them on flat surface
            var projectedImageCorners = new Dictionary <Corner, PointD>();

            projectedImageCorners[Corner.NorthWest] = imageCornerLongLats[Corner.NorthWest].Project(ProjectionOrigin);
            projectedImageCorners[Corner.SouthEast] = imageCornerLongLats[Corner.SouthEast].Project(ProjectionOrigin);

            // calculate transformation matrix
            TransformationMatrix = LinearAlgebraUtil.CalculateTransformationMatrix(
                projectedImageCorners[Corner.NorthWest], new PointD(0, 0),
                projectedImageCorners[Corner.SouthEast], new PointD(imageSize.Width - 1, imageSize.Height - 1), null, true);
        }
Example #10
0
        public static LongLat Deproject(PointD coordinate, LongLat projectionOrigin)
        {
            if (LinearAlgebraUtil.DistancePointToPoint(coordinate, new PointD(0, 0)) < 0.0000001)
            {
                return(new LongLat(projectionOrigin.Longitude, projectionOrigin.Latitude));
            }
            const double r       = 6378200; // earth radius in metres
            var          longLat = new LongLat();
            var          rho     = Math.Sqrt(coordinate.X * coordinate.X + coordinate.Y * coordinate.Y);
            var          c       = Math.Asin(rho / r);
            var          lambda0 = projectionOrigin.Longitude * Math.PI / 180.0;
            var          phi1    = projectionOrigin.Latitude * Math.PI / 180.0;

            longLat.Latitude =
                Math.Asin(Math.Cos(c) * Math.Sin(phi1) +
                          (coordinate.Y * Math.Sin(c) * Math.Cos(phi1) / rho)) / Math.PI * 180.0;
            longLat.Longitude = (lambda0 +
                                 Math.Atan(coordinate.X * Math.Sin(c) /
                                           (rho * Math.Cos(phi1) * Math.Cos(c) -
                                            coordinate.Y * Math.Sin(phi1) * Math.Sin(c)))) / Math.PI * 180.0;
            return(longLat);
        }
Example #11
0
        public Dictionary <Corner, LongLat> GetRotatedBoxCornerLongLats()
        {
            var rotation = -Rotation;

            var corners = new Dictionary <Corner, LongLat>();

            corners[Corner.NorthEast] = new LongLat(East, North);
            corners[Corner.NorthWest] = new LongLat(West, North);
            corners[Corner.SouthWest] = new LongLat(West, South);
            corners[Corner.SouthEast] = new LongLat(East, South);

            var projectionOrigin = new LongLat((East + West) / 2, (North + South) / 2);

            var projectedMapCenter = projectionOrigin.Project(projectionOrigin);

            var projectedCorners = new Dictionary <Corner, PointD>();

            projectedCorners[Corner.NorthEast] = corners[Corner.NorthEast].Project(projectionOrigin);
            projectedCorners[Corner.NorthWest] = corners[Corner.NorthWest].Project(projectionOrigin);
            projectedCorners[Corner.SouthWest] = corners[Corner.SouthWest].Project(projectionOrigin);
            projectedCorners[Corner.SouthEast] = corners[Corner.SouthEast].Project(projectionOrigin);

            var projectedRotatedCorners = new Dictionary <Corner, PointD>();

            projectedRotatedCorners[Corner.NorthEast] = LinearAlgebraUtil.Rotate(projectedCorners[Corner.NorthEast], projectedMapCenter, rotation);
            projectedRotatedCorners[Corner.NorthWest] = LinearAlgebraUtil.Rotate(projectedCorners[Corner.NorthWest], projectedMapCenter, rotation);
            projectedRotatedCorners[Corner.SouthWest] = LinearAlgebraUtil.Rotate(projectedCorners[Corner.SouthWest], projectedMapCenter, rotation);
            projectedRotatedCorners[Corner.SouthEast] = LinearAlgebraUtil.Rotate(projectedCorners[Corner.SouthEast], projectedMapCenter, rotation);

            var rotatedCorners = new Dictionary <Corner, LongLat>();

            rotatedCorners[Corner.NorthWest] = LongLat.Deproject(projectedRotatedCorners[Corner.NorthWest], projectionOrigin);
            rotatedCorners[Corner.NorthEast] = LongLat.Deproject(projectedRotatedCorners[Corner.NorthEast], projectionOrigin);
            rotatedCorners[Corner.SouthWest] = LongLat.Deproject(projectedRotatedCorners[Corner.SouthWest], projectionOrigin);
            rotatedCorners[Corner.SouthEast] = LongLat.Deproject(projectedRotatedCorners[Corner.SouthEast], projectionOrigin);
            return(rotatedCorners);
        }
Example #12
0
        public static GeneralMatrix CreateInitialTransformationMatrix(Route route, Size mapSize, LongLat projectionOrigin)
        {
            // create initial adjustment: route should fit in the 75% inner rectangle of the map
            RectangleD routeRectangle = route.BoundingProjectedRectangle(projectionOrigin);
            RectangleD mapRectangle   = new RectangleD(1.0 / 8.0 * mapSize.Width, 1.0 / 8.0 * mapSize.Height, 3.0 / 4.0 * mapSize.Width, 3.0 / 4.0 * mapSize.Height);

            // check width/height ratio for each of the rectangles, and adjust the map rectangle to have the same ratio as the route rectangle
            double routeRatio = routeRectangle.Width / routeRectangle.Height;
            double mapRatio   = mapRectangle.Width / mapRectangle.Height;

            if (mapRatio < routeRatio)
            {
                // too narrow
                mapRectangle = new RectangleD(mapRectangle.Left, mapRectangle.Center.Y - mapRectangle.Width / routeRatio / 2.0, mapRectangle.Width, mapRectangle.Width / routeRatio);
            }
            else
            {
                // too wide
                mapRectangle = new RectangleD(mapRectangle.Center.X - mapRectangle.Height * routeRatio / 2.0, mapRectangle.Top, mapRectangle.Height * routeRatio, mapRectangle.Height);
            }

            GeneralMatrix t = LinearAlgebraUtil.CalculateTransformationMatrix(routeRectangle.LowerLeft, mapRectangle.UpperLeft, routeRectangle.UpperRight, mapRectangle.LowerRight, null, false);

            return(t);
        }
Example #13
0
 /// <summary>
 /// Distance in longitude/latitude units, not meters
 /// </summary>
 /// <param name="p0"></param>
 /// <param name="p1"></param>
 /// <returns></returns>
 public static double DistancePointToPoint(LongLat p0, LongLat p1)
 {
     return(Math.Sqrt((p1.Longitude - p0.Longitude) * (p1.Longitude - p0.Longitude) + (p1.Latitude - p0.Latitude) * (p1.Latitude - p0.Latitude)));
 }
Example #14
0
 public Transformation(GeneralMatrix transformationMatrix, LongLat projectionOrigin)
 {
     TransformationMatrix = transformationMatrix;
     ProjectionOrigin     = projectionOrigin;
 }
Example #15
0
        private static Session ReadSession(BinaryReader reader, int length)
        {
            List <DateTime>  mapReadingList   = null;
            Route            route            = null;
            HandleCollection handles          = null;
            LongLat          projectionOrigin = null;
            LapCollection    laps             = null;
            var         startPos    = reader.BaseStream.Position;
            SessionInfo sessionInfo = null;
            DateTime    lastTime;

            while (reader.BaseStream.Position < startPos + length)
            {
                var tag       = (Tags)reader.ReadByte();
                var tagLength = Convert.ToInt32(reader.ReadUInt32());
                switch (tag)
                {
                case Tags.Route:
                    var attributes = reader.ReadUInt16();
                    var extraWaypointAttributesLength = reader.ReadUInt16();
                    var routeSegments = new List <RouteSegment>();
                    var segmentCount  = reader.ReadUInt32();
                    lastTime = DateTime.MinValue;
                    for (var i = 0; i < segmentCount; i++)
                    {
                        var rs            = new RouteSegment();
                        var waypointCount = reader.ReadUInt32();
                        for (var j = 0; j < waypointCount; j++)
                        {
                            var w = new Waypoint();
                            w.LongLat = ReadLongLat(reader);
                            w.Time    = ReadTime(lastTime, reader);
                            lastTime  = w.Time;
                            if ((attributes & (UInt16)WaypointAttribute.HeartRate) == (UInt16)WaypointAttribute.HeartRate)
                            {
                                w.HeartRate = reader.ReadByte();
                            }
                            if ((attributes & (UInt16)WaypointAttribute.Altitude) == (UInt16)WaypointAttribute.Altitude)
                            {
                                w.Altitude = reader.ReadInt16();
                            }
                            reader.BaseStream.Position += extraWaypointAttributesLength; // for forward compatibility
                            rs.Waypoints.Add(w);
                        }
                        routeSegments.Add(rs);
                    }
                    route = new Route(routeSegments);
                    break;

                case Tags.Handles:
                    handles = new HandleCollection();
                    var handleCount        = reader.ReadUInt32();
                    var handleMarkerDrawer = SessionSettings.CreateDefaultMarkerDrawers()[MarkerType.Handle];
                    for (var i = 0; i < handleCount; i++)
                    {
                        var handle = new Handle();
                        // transformation matrix
                        handle.TransformationMatrix = new GeneralMatrix(3, 3);
                        for (var j = 0; j < 9; j++)
                        {
                            handle.TransformationMatrix.SetElement(j / 3, j % 3, reader.ReadDouble());
                        }
                        // parameterized location
                        var segmentIndex = Convert.ToInt32(reader.ReadUInt32());
                        var value        = reader.ReadDouble();
                        handle.ParameterizedLocation = new ParameterizedLocation(segmentIndex, value);

                        // pixel location
                        handle.Location = new PointD(reader.ReadDouble(), reader.ReadDouble());
                        // type
                        handle.Type = (Handle.HandleType)reader.ReadInt16();
                        // use default marker drawer
                        handle.MarkerDrawer = handleMarkerDrawer;

                        handles.Add(handle);
                    }
                    break;

                case Tags.ProjectionOrigin:
                    projectionOrigin = ReadLongLat(reader);
                    break;

                case Tags.Laps:
                    laps = new LapCollection();
                    var lapCount = reader.ReadUInt32();
                    for (var i = 0; i < lapCount; i++)
                    {
                        var lap = new Lap();
                        lap.Time    = DateTime.FromBinary(reader.ReadInt64());
                        lap.LapType = (LapType)reader.ReadByte();
                        laps.Add(lap);
                    }
                    break;

                case Tags.SessionInfo:
                    sessionInfo             = new SessionInfo();
                    sessionInfo.Person      = new SessionPerson();
                    sessionInfo.Person.Name = ReadString(reader);
                    sessionInfo.Person.Club = ReadString(reader);
                    sessionInfo.Person.Id   = reader.ReadUInt32();
                    sessionInfo.Description = ReadString(reader);
                    // when more fields are added, check so that tagLength is not passed
                    break;

                case Tags.MapReadingInfo:
                    mapReadingList = new List <DateTime>();
                    lastTime       = DateTime.MinValue;
                    var startPosition = reader.BaseStream.Position;
                    while (reader.BaseStream.Position - startPosition < tagLength)
                    {
                        var time = ReadTime(lastTime, reader);
                        mapReadingList.Add(time);
                        lastTime = time;
                    }
                    break;

                default:
                    reader.BaseStream.Position += tagLength;
                    break;
                }
            }

            if (mapReadingList != null && route != null)
            {
                route = new Route(Route.AddMapReadingWaypoints(route.Segments, mapReadingList));
            }
            var session = new Session(
                route,
                laps,
                new Size(0, 0),
                handles != null && handles.Count > 0 ? handles[0].TransformationMatrix : null,
                projectionOrigin,
                new SessionSettings());

            if (handles != null)
            {
                foreach (var h in handles)
                {
                    session.AddHandle(h);
                }
            }
            if (sessionInfo != null)
            {
                session.SessionInfo = sessionInfo;
            }

            return(session);
        }
Example #16
0
 /// <summary>
 /// Creating a new document using the specified map, route, laps, initial transformation matrix, projection origin and document settings, and adding one new session with the specified route and laps.
 /// </summary>
 /// <param name="map"></param>
 /// <param name="route"></param>
 /// <param name="laps"></param>
 /// <param name="initialTransformationMatrix"></param>
 /// <param name="projectionOrigin"></param>
 /// <param name="settings"></param>
 public Document(Map map, Route route, LapCollection laps, GeneralMatrix initialTransformationMatrix, LongLat projectionOrigin, DocumentSettings settings)
 {
     Map = map;
     sessions.Add(new Session(route, laps, map.Image.Size, initialTransformationMatrix, projectionOrigin, settings.DefaultSessionSettings));
     this.settings = settings;
     UpdateDocumentToCurrentVersion(this);
 }
Example #17
0
        /// <summary>
        /// Converts a map image pixel coordinate to a longitude and latitude coordinate
        /// </summary>
        /// <param name="mapImagePosition">Map pixel coordinate, referring to unzoomed map without any borders and image header</param>
        /// <returns></returns>
        public LongLat GetLongLatForMapImagePosition(PointD mapImagePosition, GeneralMatrix averageTransformationMatrixInverse)
        {
            var projectedPosition = LinearAlgebraUtil.Transform(mapImagePosition, averageTransformationMatrixInverse);

            return(LongLat.Deproject(projectedPosition, ProjectionOrigin));
        }
Example #18
0
        /// <summary>
        /// Using linear least squares algorithm described at http://en.wikipedia.org/wiki/Linear_least_squares
        /// </summary>
        /// <returns></returns>
        public Transformation CalculateAverageTransformation()
        {
            var averageProjectionOrigin = new LongLat();

            foreach (var session in this)
            {
                averageProjectionOrigin += session.ProjectionOrigin / Count;
            }

            if (Count == 0)
            {
                return(null);
            }
            var n   = 4;
            var XtX = new GeneralMatrix(n, n);
            var Xty = new GeneralMatrix(n, 1);
            var numberOfUnknowns = 0;

            foreach (var session in this)
            {
                var m = session.Handles.Length;
                if (m < 2)
                {
                    continue;
                }
                numberOfUnknowns += m;

                var startDistance = session.Route.GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, session.Route.FirstPL).Value;
                for (var i = 0; i < m; i++)
                {
                    var longLat     = session.Route.GetLocationFromParameterizedLocation(session.Handles[i].ParameterizedLocation);
                    var p           = longLat.Project(averageProjectionOrigin); // projected point on earth (metres)
                    var q           = session.Handles[i].Location;              // point on map image (pixels)
                    var endDistance = (i != m - 1)
                              ? (session.Route.GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, session.Handles[i].ParameterizedLocation).Value +
                                 session.Route.GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, session.Handles[i + 1].ParameterizedLocation).Value) / 2
                              : session.Route.GetAttributeFromParameterizedLocation(WaypointAttribute.Distance, session.Route.LastPL).Value;
                    var w = endDistance - startDistance; // weight
                    startDistance = endDistance;

                    XtX.SetElement(0, 0, XtX.GetElement(0, 0) + w * (p.X * p.X + p.Y * p.Y));
                    XtX.SetElement(0, 2, XtX.GetElement(0, 2) + w * p.X);
                    XtX.SetElement(0, 3, XtX.GetElement(0, 3) - w * p.Y);
                    XtX.SetElement(1, 1, XtX.GetElement(1, 1) + w * (p.X * p.X + p.Y * p.Y));
                    XtX.SetElement(1, 2, XtX.GetElement(1, 2) + w * p.Y);
                    XtX.SetElement(1, 3, XtX.GetElement(1, 3) + w * p.X);
                    XtX.SetElement(2, 0, XtX.GetElement(2, 0) + w * p.X);
                    XtX.SetElement(2, 1, XtX.GetElement(2, 1) + w * p.Y);
                    XtX.SetElement(2, 2, XtX.GetElement(2, 2) + w);
                    XtX.SetElement(3, 0, XtX.GetElement(3, 0) - w * p.Y);
                    XtX.SetElement(3, 1, XtX.GetElement(3, 1) + w * p.X);
                    XtX.SetElement(3, 3, XtX.GetElement(3, 3) + w);

                    Xty.SetElement(0, 0, Xty.GetElement(0, 0) + w * (q.X * p.X - q.Y * p.Y));
                    Xty.SetElement(1, 0, Xty.GetElement(1, 0) + w * (q.X * p.Y + q.Y * p.X));
                    Xty.SetElement(2, 0, Xty.GetElement(2, 0) + w * q.X);
                    Xty.SetElement(3, 0, Xty.GetElement(3, 0) + w * q.Y);
                }
            }

            var T = new GeneralMatrix(3, 3);

            if (numberOfUnknowns == 0)
            {
                T = this[0].InitialTransformationMatrix;
            }
            else if (numberOfUnknowns == 1)
            {
                T = this[0].Handles[0].TransformationMatrix;
            }
            else
            {
                var B = XtX.QRD().Solve(Xty);

                T.SetElement(0, 0, B.GetElement(0, 0));
                T.SetElement(0, 1, B.GetElement(1, 0));
                T.SetElement(0, 2, B.GetElement(2, 0));
                T.SetElement(1, 0, B.GetElement(1, 0));
                T.SetElement(1, 1, -B.GetElement(0, 0));
                T.SetElement(1, 2, B.GetElement(3, 0));
                T.SetElement(2, 0, 0);
                T.SetElement(2, 1, 0);
                T.SetElement(2, 2, 1);
            }
            return(new Transformation(T, averageProjectionOrigin));
        }
Example #19
0
 private static void WriteLongLat(LongLat longLat, BinaryWriter bw)
 {
     bw.Write(Convert.ToInt32(longLat.Longitude * 3600000));
     bw.Write(Convert.ToInt32(longLat.Latitude * 3600000));
 }