Set of 2D-points connected by a polyline B-spline function:
p = RandomReal[{-1, 1}, {20, 2}];
f = BSplineFunction[p,
SplineDegree -> 1,
SplineClosed -> True];
This is neatly defined polyline function. However, as the spline parameter goes from 0 to 1 with some constant step, calculated points are somewhere denser than at other regions. (I can see the density decreases with distance between points.)
Graphics[{
Point[p], Opacity[.2],
Point[f /@ Range[0, 1, .001]]}]

Me I need a function that returns equidistant points for equidistant parameter values.
Graphics[{
Point[p], Opacity[.2],
Point[g /@ Range[0, 1, .001]]}]

Where g I constructed like this:
g[t_] := Evaluate[
With[{u = With[{
d = EuclideanDistance @@@ Partition[p, 2, 1, 1]},
Accumulate[d]/Total[d]]},
Piecewise[Table[{
p[[i]] + (t - If[i > 1, u[[i - 1]], 0])/
(u[[i]] - If[i > 1, u[[i - 1]], 0])*
(p[[If[i != Length@p, i + 1, 1]]] - p[[i]]),
t <= u[[i]]}, {i, Length@p}]]]]
This can be made more elegantly, right, with Mathematica? With some option that samples equidistant points? Because say I have some smooth curve function. I don't know how I would tackle this then. I guess one would have to integrate and findroot some.
Answer
p = RandomReal[{-1, 1}, {5, 2}];
f = BSplineFunction[p, SplineDegree -> 1, SplineClosed -> True];
A very simple approach:
np[u_, dt_] := u + dt/ Norm[D[f[t], t]] /. t -> u;
ListPlot[Table[f[t], {t, NestWhileList[np[#, .03] &, 0, # < 1 &]}], AspectRatio -> 1]

Testing that the points are equidistant:
ListLinePlot[EuclideanDistance @@@
Partition[Table[f[t], {t, NestWhileList[np[#, .03] &, 0, # < 1 &]}], 2, 1],
AxesOrigin -> {0, 0}]

The only small exceptions are at the original points, as expected.
Edit
For a higher degree interpolation:
p = RandomReal[{-1, 1}, {7, 2}];
f = BSplineFunction[p, SplineDegree -> 5, SplineClosed -> True];
GraphicsRow@{
ListPlot[Table[f[t], {t, NestWhileList[np[#, .003] &, 0, # < 1 &]}], AspectRatio -> 1],
ListLinePlot[EuclideanDistance @@@
Partition[Table[f[t], {t, NestWhileList[np[#, .003] &, 0, # < 1 &]}], 2, 1],
AxesOrigin -> {0, 0}, PlotRange -> All]}

Comments
Post a Comment