Find smallest distance from a point to a Bézier curve

g0 = Graphics[{BezierCurve[pts], Point[pts], Red, Point[pt]}, Frame -> True];
lines = MeshPrimitives[DiscretizeGraphics[g0], 1];

npt = RegionNearest[RegionUnion @@ lines][pt]
 {0.0805512, 0.671604}
Graphics[{Blue,lines, Red, Point[pt], Black, Point@pts, 
  Green, PointSize[Large], Point@npt}, Frame -> True]

enter image description here


Simply using BezierFunction is not enough. The BezierFunction will not match the BezierCurve because that curve is actually a composite of multiple splines - see here: BezierCurve is different from BezierFunction.

This below is adapted from the above and @J. M.'s technical difficulties solution:

You need to first chop your spline into its components and minimize over both, then find which closest point on each sub-spline is closer to your point. See here on how to produce the parts: How to construct BezierFunction for BezierCurve with npts>4 and SplineDegree -> 3?

pt = {-0.07194, 0.6342};
pts = {{-3, 0}, {-1, 3}, {1, -3}, {0, 1}, {0, 2}, {2, 2}, {-2, -2}};
bzsplinefns = BezierFunction /@ Partition[pts, 4, 3];
distance[p1_, p2_] := SquaredEuclideanDistance[p1, p2]
splineDistance[spline_, point_, t_?NumericQ] := 
 distance[spline[t], point]
closest[spline_, point_] := 
 NArgMin[{splineDistance[spline, point, t], 0 < t < 1}, t]
tvals = closest[#, pt] & /@ bzsplinefns;
finalNearestPoint = 
 MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], 
   distance[#, pt] &][[1]]
Graphics[{Point[pt], Thick, Gray, BezierCurve[pts], Thin,
  {RandomColor[], Line[Table[#[t], {t, 0, 1, 0.01}]]} & /@ 
   bzsplinefns, PointSize[Large], Point[finalNearestPoint]}]

bezier splines

If you choose BSplineCurve instead, you don't need to worry about breaking it into multiple BSplineFunctions - you can just minimize a single BSplineFunction that accounts for the whole curve.

pt = {-0.07194, 0.6342};
pts = {{-3, 0}, {-1, 3}, {1, -3}, {0, 1}, {0, 2}, {2, 2}, {-2, -2}};
distance[p1_, p2_] := SquaredEuclideanDistance[p1, p2]
splineDistance[spline_, point_, t_?NumericQ] := 
 distance[spline[t], point]
closest[spline_, point_] := 
 NArgMin[{splineDistance[spline, point, t], 0 < t < 1}, t]
bsp = BSplineFunction[pts];
result = bsp[closest[bsp, pt]]
Graphics[{BSplineCurve[pts], Point[pt], PointSize[Large], 
  Point[result]}]

bspline nearest point


Another way is to express the curve as a union of ParametricRegions and then use RegionNearest.

p1 = (List @@ Expand[(x + y)^3] /. {x -> 1 - t, y -> t}).pts[[1 ;; 4]];

p2 = (List @@ Expand[(x + y)^3] /. {x -> 1 - t, y -> t}).pts[[4 ;; 7]];

breg = RegionUnion[
  ParametricRegion[p1, {{t, 0, 1}}], 
  ParametricRegion[p2, {{t, 0, 1}}]
];

Region[Style[breg, Thick]]

RegionNearest[breg, pt]
{0.0808892, 0.67102}