kybs0

如何在一条曲线上,获取到距离指定点最近的点位置?

 

与上一篇 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         }
41 
42         private static Point GetClosestPointOnLine(Point start, Point end, Point p)
43         {
44             double length = (start - end).LengthSquared;
45             if (Math.Abs(length) < 0.01)
46             {
47                 return start;
48             }
49             Vector v = end - start;
50             double param = (p - start) * v / length;
51             return (param < 0.0) ? start : (param > 1.0) ? end : (start + param * v);
52         }

效果图:

 

相关文章: