.NET 曲线上的点- 获取距离最近的点

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

 

与上一篇 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     }
复制代码

效果图:

 

posted @   唐宋元明清2188  阅读(1904)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示
哥伦布
01:11发布
哥伦布
01:11发布
8°
西北风
2级
空气质量
相对湿度
81%
今天
中雨
3°/15°
周四
大雨
2°/14°
周五
小雨
4°/10°