Message Boards Message Boards

Computing arch length of a spline curve

GROUPS:
I have a project where I need to color spline curves according to their arch length. How can I find spline arch length efficiently? Spline is a parametric curve, so arch length is defined as



I see two ways to do this. One is to use NIntegrate (I heard that Integrate will not return a closed form solution). The other way is to discretize manually and add lengths of line segments:



We start from some points and a BSplineFunction:

pts = {{1, 1}, {2, -1}, {3, 0}, {2, 1}, {1, 0}};
f = BSplineFunction[pts];

Then we sample BSplineFunction to get close points along its curve:

steps = Table[f[t], {t, 0, 1, .1}];

Show[Graphics[{Red, Point[pts], Green, Line[pts], Orange, PointSize[.02], Point[steps], Green}],
     ParametricPlot[f[t], {t, 0, 1}], Axes -> False]




Now we can see that even we that few points along the curve values of integral and sum are close:

NIntegrate[Norm[D[f[t], t]], {t, 0, 1}]
Out ==> 4.57294

Total[EuclideanDistance @@@ Partition[steps, 2, 1]]
Out ==> 4.53213

So my questions are the following:
  1. Do our spline functions contain somehow information about arch their length?
  2. Will NIntegrate method always work or will it break for some splines (at pinching curve points for example)?
  3. Are there more efficient numeric methods?
  4. As much as I know symbolic solution is not known in closed form – is this true?
I was trying to break NIntegrate with this app, but could not (at least with MaxRecursion -> 12). 

 Manipulate[
  BSF = BSplineFunction[pt, SplineClosed -> clsd];
  SPS = Table[BSF[t], {t, 0, 1, stp}];
 
  Show[
   Graphics[{Red, PointSize[.015], Point[SPS]}],
   ParametricPlot[BSF[t], {t, 0, 1}, PlotStyle -> Black],
   PlotRange -> 1, ImageSize -> 400 {1, 1}, Axes -> False,
   BaseStyle -> Directive[FontSize -> 15, Blue, Bold],
  Epilog ->
   {Text["INTEGRAL = " <>
          ToString[NIntegrate[Norm[D[BSF[t], t]], {t, 0, 1}, MaxRecursion -> 12]], {-.55, -.95}],
    Text["SUM = " <> ToString [Total[EuclideanDistance @@@ Partition[SPS, 2, 1]]], {.25, -.95}]}],

{{pt, .8 Tuples[{0, 1, -1}, 2]}, Locator, LocatorAutoCreate -> True},

Row[{Control@{{clsd, False, "Closed?"}, {False, True}}, Spacer[20],
      Control@{{stp, .01, "step"}, .001, .1}}],

FrameMargins -> 0, SaveDefinitions -> True]

POSTED BY: Vitaliy Kaurov
Answer
5 years ago
I like to use NDSolve to do these kinds of computations:

In[118]:=
nds=NDSolve[{s'[t] == Norm[f'[t]], s[0]==0},s,{t,0,1}];
arclength=s/.First@nds;

In[120]:= arclength[1]

Out[120]= 4.57294
POSTED BY: Carl Woll
Answer
5 years ago
This is a very nice approach, Carl, thank you. I found it to be more robust than integration for a large number of points.
POSTED BY: Vitaliy Kaurov
Answer
5 years ago
By the way, Plot and ParametricPlot/ParametricPlot3D for curves, can take as MeshFunctions the values "ArcLength" and "CurveLength". So, for example:

pts = {{1, 1}, {2, -1}, {3, 0}, {2, 1}, {1, 0}};
BSF = BSplineFunction[pts]
mpoints = Table[t, {t, 0, 5, 0.5}]

ParametricPlot[BSF[t], {t, 0, 1}, MeshFunctions -> {"CurveLength"},
Mesh -> {mpoints}, MeshStyle -> {PointSize[0.02], Red}]

will create mesh points at the corresponding curve lengths, so from the plot we see that the length is a little bigger than 4.5.

Now, try:
mpoints = Table[t, {t, 0, 1, 0.1}]
ParametricPlot[BSF[t], {t, 0, 1}, MeshFunctions -> {"ArcLength"},
Mesh -> {mpoints}, MeshStyle -> {PointSize[0.02], Red}]

In this case the curve length is normlized between (0,1). We do not have a MeshScaling option, that is why we use "CurveLength" vs "ArcLength".


These predefined mesh functions allow for very simple examples, like your own dashing styles:


mpoints = Table[t, {t, 0, 1, 0.05}];

ParametricPlot[BSF[t], {t, 0, 1}, MeshFunctions -> {"ArcLength"},
Mesh -> {mpoints}, MeshStyle -> {PointSize[0.015], Blue},
MeshShading -> {Red, Green}]


Hope this helps.
Answer
5 years ago

With the release of computational geometry we can simply do RegionMeasure:

pts = {{1, 1}, {2, -1}, {3, 0}, {2, 1}, {1, 0}};
RegionMeasure[DiscretizeGraphics[Graphics[BSplineCurve[pts]]]]
(*4.435030548461937`*)
POSTED BY: Vitaliy Kaurov
Answer
1 year ago

Group Abstract Group Abstract