I have a point and a path, polyline, or set of points to create lines.
How can I find the point on my path which closest to another disconnected point?
It\'
The following method GetClosestPointOnPath() is a generalization of @KirkBroadhurst's GetClosestPointOnLine() method, i.e. it works with any path geometry, i.e. lines, curves, ellipses, etc.
public Point GetClosestPointOnPath(Point p, Geometry geometry)
{
PathGeometry pathGeometry = geometry.GetFlattenedPathGeometry();
var points = pathGeometry.Figures.Select(f => GetClosestPointOnPathFigure(f, p))
.OrderBy(t => t.Item2).FirstOrDefault();
return (points == null) ? new Point(0, 0) : points.Item1;
}
private Tuple GetClosestPointOnPathFigure(PathFigure figure, Point p)
{
List> closePoints = new List>();
Point current = figure.StartPoint;
foreach (PathSegment s in figure.Segments)
{
PolyLineSegment segment = s as PolyLineSegment;
LineSegment line = s as LineSegment;
Point[] points;
if (segment != null)
{
points = segment.Points.ToArray();
}
else if (line != null)
{
points = new[] { line.Point };
}
else
{
throw new InvalidOperationException("Unexpected segment type");
}
foreach (Point next in points)
{
Point closestPoint = GetClosestPointOnLine(current, next, p);
double d = (closestPoint - p).LengthSquared;
closePoints.Add(new Tuple(closestPoint, d));
current = next;
}
}
return closePoints.OrderBy(t => t.Item2).First();
}
private Point GetClosestPointOnLine(Point start, Point end, Point p)
{
double length = (start - end).LengthSquared;
if (length == 0.0)
{
return start;
}
Vector v = end - start;
double param = (p - start) * v / length;
return (param < 0.0) ? start : (param > 1.0) ? end : (start + param * v);
}
Here is a small sample program that demonstrates how to use this method:

MainWindow.xaml:
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace PathHitTestSample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
Point p = e.GetPosition(canvas);
Point pointOnPath = GetClosestPointOnPath(p, path.Data);
marker.Visibility = Visibility.Visible;
Canvas.SetLeft(marker, pointOnPath.X);
Canvas.SetTop(marker, pointOnPath.Y);
}
... add above methods here ...
}
}