In[1]:= (* Square of the distance between two points *)
distsqr[{{x1_, y1_}, {x2_, y2_}}] = (x1 - x2)^2 + (y1 - y2)^2;
In[2]:= (* Derivative of the distance squared between a point {x,y} \
and a point on a line passing through {x1,y1} and {x2,y2}, \
parameterizing the point on the line with the variable t *)
eqs = D[distsqr[{{x, y}, { x1 + t (x2 - x1), y1 + t (y2 - y1)}}], {t}]
Out[2]= 2 (x1 - x2) (x - x1 - t (-x1 + x2)) +
2 (y1 - y2) (y - y1 - t (-y1 + y2))
(* Minimize the distance squared by setting the derivative equal to 0 \
*)
ln = Solve[eqs == 0, t] // FullSimplify
Out[3]= {{t -> -(((x - x1) (x1 - x2) + (y - y1) (y1 - y2))/((x1 -
x2)^2 + (y1 - y2)^2))}}
In[4]:= (* The value of t, the distance between the point and \
infinite line and the point on the infinite line *)
dsqrpos[{{x1_, y1_}, {x2_, y2_}}][{x_,
y_}] = {t,
distsqr[{{x, y}, {xt, yt}}], {xt, yt}} /. {xt ->
x1 + t (x2 - x1), yt -> y1 + t (y2 - y1)} /. ln[[1]] //
FullSimplify
Out[4]= {-(((x - x1) (x1 - x2) + (y - y1) (y1 - y2))/((x1 -
x2)^2 + (y1 - y2)^2)), (x1 y - x2 y - x y1 + x2 y1 + x y2 -
x1 y2)^2/((x1 - x2)^2 + (y1 - y2)^2), {(
x (x1 - x2)^2 + (x2 (-y + y1) + x1 (y - y2)) (y1 - y2))/((x1 -
x2)^2 + (y1 - y2)^2),
y1 - (((x - x1) (x1 - x2) + (y - y1) (y1 - y2)) (-y1 + y2))/((x1 -
x2)^2 + (y1 - y2)^2)}}
In[5]:= (* The distance between a point {x,y} and a line segment \
between {x1,y1} and {x2,y2} and the point on the line. If t is <= 0 \
then the point on the line is {x1,y1}. If t >= 1, the point on the \
line is {x2,y2}. Otherwise it is the solution from dsqrpos *)
dsqrposl[{{x1_, y1_}, {x2_, y2_}}][{x_, y_}] :=
Block[{dsqposv, res},
dsqposv = dsqrpos[{{x1, y1}, {x2, y2}}][{x, y}];
res = Which[
dsqposv[[1]] <= 0, {distsqr[{{x1, y1}, {x, y}}]^(1/2), {x1, y1}},
0 < dsqposv[[1]] < 1, {dsqposv[[2]]^(1/2), dsqposv[[3]]},
dsqposv[[1]] >= 1, {distsqr[{{x2, y2}, {x, y}}]^(1/2), {x2, y2}}
]
]
In[6]:= (* test case *)
AbsoluteTiming @ dsqrposl[{{2, 3}, {3, 4}}][{5/2, 3}]
Out[6]= {0.0000716, {1/(2 Sqrt[2]), {9/4, 13/4}}}
In[7]:= (* compare to Mathematica function RegionDistance *)
AbsoluteTiming @ RegionDistance[Line[{{2, 3}, {3, 4}}], {5/2, 3}]
Out[7]= {0.0095428, 1/(2 Sqrt[2])}
In[8]:= (* compare to Mathematica function RegionNearest \
*)AbsoluteTiming @ RegionNearest[Line[{{2, 3}, {3, 4}}], {5/2, 3}]
Out[8]= {0.0070957, {9/4, 13/4}}