C# 曲線上的點(二) 獲取距離最近的點


如何在一條曲線上,獲取到距離指定點最近的點位置?

 

與上一篇 C# 曲線上的點(一) 獲取指定橫坐標對應的縱坐標值 類似,

我們通過曲線上獲取的密集點,通過倆點之間連線,獲取連線上最近的點。我們能夠獲取到一系列最近的點集,最近只取距離最小的點即可。

我們這樣的算法是否精確呢?不算太精確,但是對於獲取曲線上最近點,基本能滿足。

斜率變化不大的線段,點不密集;斜率變化較大的線段,點相當密集,所以由此點集得到的最近點,是相對准確的。

實現方案,以下代碼可以直接復用:

 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     }

倆點之間的連線,如果當前點在此方向的投影為負或者大於當前長度,則取倆側的點:

 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     }

效果圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM