How to calculate the closest point on a segment to a point
Hi, below there is a little snippet that calculates the closest point on a segment to a determined point.
It is written in C++ but can be easily translated to any other language.
Disclaimer: given its age, it uses hungarian notation, and some names are in Spanish, but it was thoroughly tested and works as expected.
1//--------------------------------------------------------------------------------------------------------
2//author: Adrián Deccico - http://adrian.org.ar
3/*
4Description: calculate the closest point on a segment to a point.
5Parameters:
6nSx1, nSy1 = First point of the segment
7nSx2, int nSy2 = Second point of the segment
8nPx, int nPy = The point to analize
9*nCercaX, *nCercaY = The closest point to the given point (nPx,nPy) that belongs to the segment
10Returns: The distance between the given point and the point found of the segment
11*/
12double ElPuntoMasCercanoAUnSegmento(double nSx1, double nSy1, double nSx2,
13double nSy2, double nPx, double nPy,
14double *nCercaX, double *nCercaY)
15{
16
17//caracterizo la recta del segmento dado Y=m*X + b
18double m, b;
19
20bool bEsHorizontalOVertical = false;
21
22//el segmento es vertical
23if (nSx2 == nSx1){
24 *nCercaX = nSx1;
25 *nCercaY = nPy;
26 bEsHorizontalOVertical = true;
27}
28
29//el segmento es horizontal
30if (nSy2 == nSy1){
31 *nCercaY = nSy1;
32 *nCercaX = nPx;
33 bEsHorizontalOVertical = true;
34}
35
36//el segmento está caracterizado por una recta "AX + BY + C = 0" con
37// A y B distintos de cero
38if (!bEsHorizontalOVertical)
39{
40 m= (nSy2 - nSy1) / (nSx2 - nSx1);
41 b = nSy1 - (nSx1 * m);
42
43 //caracterizo la recta que une al punto dado con el punto más
44 // cercano dentro del segmento Y=m1*X + b1
45 double m1, b1;
46
47 m1 = -1 / m;
48 b1 = -m1 * nPx + nPy;
49
50 //encuentro el punto de intersección
51 *nCercaX = (b1 - b) / (m - m1);
52 *nCercaY = m * *nCercaX + b;
53}
54
55//verificar que el punto encontrado está dentro del segmento
56if (*nCercaX < min(nSx1,nSx2)
57|| *nCercaX > max(nSx1,nSx2)
58|| *nCercaY < min(nSy1,nSy2)
59|| *nCercaY > max(nSy1,nSy2) )
60{
61 //el punto más cercano será uno de los dos extremos (el más cercano al punto)
62 if (dDistanciaEntrePuntos(nSx1, nSy1, nPx, nPy) <= dDistanciaEntrePuntos(nSx2, nSy2, nPx, nPy))
63 {
64 *nCercaX = nSx1;
65 *nCercaY = nSy1;
66 }
67 else
68 {
69 *nCercaX = nSx2;
70 *nCercaY = nSy2;
71 }
72}
73
74return dDistanciaEntrePuntos(nPx, nPy, *nCercaX , *nCercaY);
75
76}
77//--------------------------------------------------------------------------------------------
78
79//------------------------------------------------------------------------
80//return the distance between two points in a x,y plane.
81double dDistanciaEntrePuntos(double lOldX, double lOldY,
82double lNewX, double lNewY)
83{
84 double x = lNewX - lOldX;
85 double y = lNewY - lOldY;
86
87 return sqrt(pow(x,2) + pow(y,2));
88}
89//------------------------------------------------------------------------