예제 #1
0
        /// <summary>
        /// Gets the distance (in km) from Point A to Point B (both A and B must lie on a polyline defined by a list of points).
        /// If B is before A, the distance is negative!
        /// </summary>
        /// <param name="A">First point</param>
        /// <param name="B">Second point</param>
        /// <param name="points">List of Points that define the polyline</param>
        /// <returns></returns>
        public static double GetDistanceOnPolyline(PointLatLng A, PointLatLng B, List<PointLatLng> points)
        {
            double dist = 0d;

            //If both points are the same return 0!
            if (A == B)
                return dist;

            bool foundA = false;
            bool foundB = false;
            double distP1toA, distP2toA, distP1toB, distP2toB, distP1toP2;

            for (int i = 0; i < points.Count - 1; i++)
            {
                var p1 = points[i];
                var p2 = points[i + 1];

                bool AisBetween = GMapUtils.IsPointOnLineSegment(p1, p2, A, out distP1toA, out distP2toA, out distP1toP2);
                if (AisBetween)
                    foundA = true;

                bool BisBetween = GMapUtils.IsPointOnLineSegment(p1, p2, B, out distP1toB, out distP2toB, out distP1toP2);
                if (BisBetween)
                    foundB = true;

                if (AisBetween && BisBetween)
                {
                    dist = GMapProviders.EmptyProvider.Projection.GetDistance(A, B);
                    if (distP1toB < distP1toA)
                        dist *= -1d;
                    return dist;
                }

                //Point A was found, but not B:
                if (AisBetween && !foundB)
                    dist += distP2toA;
                else if (foundA && !AisBetween && !foundB)
                    dist += distP1toP2;
                else if (foundA && !AisBetween && BisBetween)
                {
                    dist += distP1toB;
                    break;
                }
                //Point B was found, but not A:
                else if (BisBetween && !foundA)
                    dist += distP2toB;
                else if (foundB && !BisBetween && !foundA)
                    dist += distP1toP2;
                else if (foundB && !BisBetween && AisBetween)
                {
                    dist += distP1toA;
                    dist *= -1d;
                    break;
                }
            }
            if (!foundA || !foundB)
                throw new Exception("Point A or Point B (or both) are not on the polyline!");

            return dist;
        }
예제 #2
0
 /// <summary>
 /// Returns the point that lies on the polyline and is closest to a given point.
 /// </summary>
 /// <param name="points">A List of Vectors/Points that define the polyline</param>
 /// <param name="pos">The given point</param>
 /// <returns>Closest point that is on the polyline.</returns>
 public static PointLatLng GetClosestPointOnPolyline(List<PointLatLng> points, PointLatLng pos)
 {
     SortedDictionary<double, Vector> distances = new SortedDictionary<double, Vector>();
     Vector v0 = new Vector(pos.Lng, pos.Lat);
     for (int i = 0; i < points.Count - 1; i++)
     {
         double dist;
         Vector v1 = new Vector(points[i].Lng, points[i].Lat);
         Vector v2 = new Vector(points[i + 1].Lng, points[i + 1].Lat);
         var point = GMapUtils.GetClosestPointOnLinesegment(v1, v2, v0, out dist);
         if (!distances.ContainsKey(dist))
             distances.Add(dist, point);
     }
     return new PointLatLng(distances.First().Value.Y, distances.First().Value.X);
 }
예제 #3
0
        /// <summary>
        /// Returns a point that lies on the polyline defined by the point list, and is a certain distance (in km!) from point A (that must also lie on the polyline).
        /// If the point would lie outside of the polyline, the last point of the polyline is returned!
        /// If the distance is negative, the new point lies BEFORE the given point!
        /// </summary>
        /// <param name="A">The Start point</param>
        /// <param name="dist">The distance from the start point in km</param>
        /// <param name="points">The points defining the polyline</param>
        /// <returns></returns>
        public static PointLatLng GetDistantPointOnPolyline(PointLatLng A, double distance, List<PointLatLng> points)
        {
            if (distance == 0d)
                return A;

            PointLatLng newPoint = new PointLatLng();
            double distP1toA, distP2toA, distP1toP2;
            double fooDist = 0d, lastDist = 0d, newDist = 0d;

            if (distance > 0d)
            {
                for (int i = 0; i < points.Count - 1; i++)
                {
                    var p1 = points[i];
                    var p2 = points[i + 1];

                    if (GMapUtils.IsPointOnLineSegment(p1, p2, A, out distP1toA, out distP2toA, out distP1toP2))
                    {
                        fooDist = distP2toA;
                        while (i < points.Count - 2 && fooDist < distance)
                        {
                            i++;
                            p1 = points[i];
                            p2 = points[i + 1];
                            lastDist = GMapProviders.EmptyProvider.Projection.GetDistance(p1, p2);
                            fooDist += lastDist;
                        }

                        if (fooDist < distance)
                            return points.Last();

                        double bearing = GMapProviders.EmptyProvider.Projection.GetBearing(p1, p2);

                        //Case 1: Last Distance is greater than 0 (the while loop ran at least one time)
                        if (lastDist > 0d)
                        {
                            newDist = lastDist - (fooDist - distance);
                            newPoint = GMapUtils.GetClosestPointOnPolyline(points, GMapUtils.GetPointLatLngFromStartPoint(p1, bearing, newDist));
                        }
                        //Case 2: Last Distance is 0, the while loop was not called:
                        else
                        {
                            newPoint = GMapUtils.GetClosestPointOnPolyline(points, GMapUtils.GetPointLatLngFromStartPoint(A, bearing, distance));
                        }
                        break;
                    }
                }
            }
            else
            {
                for (int i = 0; i < points.Count - 1; i++)
                {
                    var p1 = points[i];
                    var p2 = points[i + 1];

                    if (GMapUtils.IsPointOnLineSegment(p1, p2, A, out distP1toA, out distP2toA, out distP1toP2))
                    {
                        fooDist = distP1toA;
                        while (i > 0 && fooDist < Math.Abs(distance))
                        {
                            i--;
                            p1 = points[i];
                            p2 = points[i + 1];
                            lastDist = GMapProviders.EmptyProvider.Projection.GetDistance(p1, p2);
                            fooDist += lastDist;
                        }

                        if (fooDist < Math.Abs(distance))
                            return points.First();

                        double bearing = GMapProviders.EmptyProvider.Projection.GetBearing(p2, p1);

                        //Case 1: Last Distance is greater than 0 (the while loop ran at least one time)
                        if (lastDist > 0d)
                        {
                            newDist = lastDist - (fooDist - Math.Abs(distance));
                            newPoint = GMapUtils.GetClosestPointOnPolyline(points, GMapUtils.GetPointLatLngFromStartPoint(p2, bearing, newDist));
                        }
                        //Case 2: Last Distance is 0, the while loop was not called:
                        else
                            newPoint = GMapUtils.GetClosestPointOnPolyline(points, GMapUtils.GetPointLatLngFromStartPoint(A, bearing, Math.Abs(distance)));

                        break;
                    }
                }
            }
            return newPoint;
        }