Skip to main content
add bspline function
Source Link
flinty
  • 26.3k
  • 2
  • 23
  • 98

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

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

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

Add general solution for multi-part splines with more than two parts.
Source Link
flinty
  • 26.3k
  • 2
  • 23
  • 98

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]; minB[spline_distance[p1_, p2_] := SquaredEuclideanDistance[p1, p2] splineDistance[spline_, point_, t_?NumericQ] := SquaredEuclideanDistance[spline[t]distance[spline[t], point] closest[spline_, point_] := NArgMin[{minB[splinesplineDistance[spline, point, t], 0 < t < 1}, t] tvals = closest[#, pt] & /@ bzsplinefns; finalNearestPoint = MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], minB[#, pt] &][[ 1]] Graphics[{ (*Show the BezierFunctions on top of thedistance[#, BezierCurvept] *)&][[1]]  Graphics[{Point[pt], Thick, BlackGray, BezierCurve[pts],  Thin,  Red, Line[Table[bzsplinefns[[1]][t], {t, 0, 1, .01}]], GreenRandomColor[], Line[Table[bzsplinefns[[2]][t]Line[Table[#[t], {t, 0, 1, 0.01}]], } Orange, & /@ Point[pt], Black, PointSize[Medium]bzsplinefns,   PointSize[Large], Point[finalNearestPoint] }] 

bezier splines

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]; minB[spline_, point_, t_?NumericQ] := SquaredEuclideanDistance[spline[t], point] closest[spline_, point_] := NArgMin[{minB[spline, point, t], 0 < t < 1}, t] tvals = closest[#, pt] & /@ bzsplinefns; finalNearestPoint = MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], minB[#, pt] &][[ 1]] Graphics[{ (*Show the BezierFunctions on top of the BezierCurve *)   Thick, Black, BezierCurve[pts],  Thin,  Red, Line[Table[bzsplinefns[[1]][t], {t, 0, 1, .01}]], Green, Line[Table[bzsplinefns[[2]][t], {t, 0, 1, .01}]],  Orange,  Point[pt], Black, PointSize[Medium],   Point[finalNearestPoint] }] 

bezier splines

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

wording
Source Link
flinty
  • 26.3k
  • 2
  • 23
  • 98

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.

Minimize over the correct composite spline. 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 splinesub-spline is closer to your point. See here on how to produce the compositeparts: 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]; minB[spline_, point_, t_?NumericQ] := SquaredEuclideanDistance[spline[t], point] closest[spline_, point_] := NArgMin[{minB[spline, point, t], 0 < t < 1}, t] tvals = closest[#, pt] & /@ bzsplinefns; finalNearestPoint = MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], minB[#, pt] &][[ 1]] Graphics[{ (*Show the BezierFunctions on top of the BezierCurve *) Thick, Black, BezierCurve[pts], Thin, Red, Line[Table[bzsplinefns[[1]][t], {t, 0, 1, .01}]], Green, Line[Table[bzsplinefns[[2]][t], {t, 0, 1, .01}]], Orange, Point[pt], Black, PointSize[Medium], Point[finalNearestPoint] }] 

bezier splines

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.

Minimize over the correct composite spline. 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 spline is closer to your point. See here on how to produce the composite: 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]; minB[spline_, point_, t_?NumericQ] := SquaredEuclideanDistance[spline[t], point] closest[spline_, point_] := NArgMin[{minB[spline, point, t], 0 < t < 1}, t] tvals = closest[#, pt] & /@ bzsplinefns; finalNearestPoint = MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], minB[#, pt] &][[ 1]] Graphics[{ (*Show the BezierFunctions on top of the BezierCurve *) Thick, Black, BezierCurve[pts], Thin, Red, Line[Table[bzsplinefns[[1]][t], {t, 0, 1, .01}]], Green, Line[Table[bzsplinefns[[2]][t], {t, 0, 1, .01}]], Orange, Point[pt], Black, PointSize[Medium], Point[finalNearestPoint] }] 

bezier splines

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]; minB[spline_, point_, t_?NumericQ] := SquaredEuclideanDistance[spline[t], point] closest[spline_, point_] := NArgMin[{minB[spline, point, t], 0 < t < 1}, t] tvals = closest[#, pt] & /@ bzsplinefns; finalNearestPoint = MinimalBy[MapThread[#1[#2] &, {bzsplinefns, tvals}], minB[#, pt] &][[ 1]] Graphics[{ (*Show the BezierFunctions on top of the BezierCurve *) Thick, Black, BezierCurve[pts], Thin, Red, Line[Table[bzsplinefns[[1]][t], {t, 0, 1, .01}]], Green, Line[Table[bzsplinefns[[2]][t], {t, 0, 1, .01}]], Orange, Point[pt], Black, PointSize[Medium], Point[finalNearestPoint] }] 

bezier splines

Source Link
flinty
  • 26.3k
  • 2
  • 23
  • 98
Loading