如何在一條曲線上,獲取到距離指定點最近的點位置?html
與上一篇 C# 曲線上的點(一) 獲取指定橫座標對應的縱座標值 相似,算法
咱們經過曲線上獲取的密集點,經過倆點之間連線,獲取連線上最近的點。咱們可以獲取到一系列最近的點集,最近只取距離最小的點便可。post
咱們這樣的算法是否精確呢?不算太精確,可是對於獲取曲線上最近點,基本能知足。url
斜率變化不大的線段,點不密集;斜率變化較大的線段,點至關密集,因此由此點集獲得的最近點,是相對準確的。spa
實現方案,如下代碼能夠直接複用:code
1 public static Point GetClosestPointOnPath(Point p, Geometry geometry) 2 { 3 PathGeometry pathGeometry = geometry.GetFlattenedPathGeometry(); 4 5 var points = pathGeometry.Figures.Select(f => GetClosestPointOnPathFigure(f, p)) 6 .OrderBy(t => t.Item2).FirstOrDefault(); 7 return points?.Item1 ?? new Point(0, 0); 8 } 9 10 private static Tuple<Point, double> GetClosestPointOnPathFigure(PathFigure figure, Point p) 11 { 12 List<Tuple<Point, double>> closePoints = new List<Tuple<Point, double>>(); 13 Point current = figure.StartPoint; 14 foreach (PathSegment s in figure.Segments) 15 { 16 PolyLineSegment segment = s as PolyLineSegment; 17 LineSegment line = s as LineSegment; 18 Point[] points; 19 if (segment != null) 20 { 21 points = segment.Points.ToArray(); 22 } 23 else if (line != null) 24 { 25 points = new[] { line.Point }; 26 } 27 else 28 { 29 throw new InvalidOperationException(); 30 } 31 foreach (Point next in points) 32 { 33 Point closestPoint = GetClosestPointOnLine(current, next, p); 34 double d = (closestPoint - p).LengthSquared; 35 closePoints.Add(new Tuple<Point, double>(closestPoint, d)); 36 current = next; 37 } 38 } 39 return closePoints.OrderBy(t => t.Item2).First(); 40 }
倆點之間的連線,若是當前點在此方向的投影爲負或者大於當前長度,則取倆側的點:htm
1 private static Point GetClosestPointOnLine(Point start, Point end, Point p) 2 { 3 double length = (start - end).LengthSquared; 4 if (Math.Abs(length) < 0.01) 5 { 6 return start; 7 } 8 Vector v = end - start; 9 double param = (p - start) * v / length; 10 return (param < 0.0) ? start : (param > 1.0) ? end : (start + param * v); 11 }
效果圖:blog