Message Boards Message Boards

GROUPS:

Passing BezierFunction to ArcLength?

Posted 4 months ago
926 Views
|
7 Replies
|
7 Total Likes
|

I have a cubic Bezier curve I've generated:

pts = RandomReal[1,{4,2}];
f = BezierFunction[pts];

For a particular value of t, f will return a 2D vector:

In[21]:= f[0.5]
Out[21]= {0.584105,0.651064}

However, if I pass f by itself to ArcLength, it fails to evaluate:

ArcLength[f[t], {t,0,1}] //N
NIntegrate: Integrand ... is not numerical at {t}={0.00795732}

The same general procedure works fine with other vector-valued functions I've defined myself:

In[30]:= g[t_]:={t,t}
In[31]:= ArcLength[g[t], {t,0,1}]
Out[31]= ???SqrtBox["2"]?

What's the correct way to do this?

7 Replies

I don't know of "an easy way". Mathematica has made a ton of things like this just too easy (like finding volume of a shape). But this one yet, right?

You can easily type in the Bezier polynomial (find on Mathworld or Wiki) and pass that function to arclength - which will certainly work. Only problem is there are many Bezier curve function "styles". which one?

In fact this appears to be strange: The value t = 0.007957319952578756 in the error message does not even depend on the choice and number of the Bezier points.

If you are basically interested in the value of length, and less in the syntax, you can get a result e.g. like so:

bezf = DiscretizeGraphics[ParametricPlot[f[t], {t, 0, 1}]];
ArcLength[bezf]
Posted 3 months ago

Thank you, Henrik! While it's disheartening to have what I hoped would be a sophisticated numerical integration method reduced to simple linearization, this at least works without resorting to manual specification of polynomials. What good are high-level primitives like BezierFunction if they must be discarded so easily when used with other parts of the language?

Hello Nicholas,

it is fun to search on the internet for the number ''0.007957312'' - one will get interesting hits (is this the mysterious "Wolfram constant"?). It mostly has to do with NIntegrate.

Well, I think, the problem comes like so :

enter image description here

Here we see, what the system is trying to calculate. The BezierFunction under the Sqrt[] is the derivative of the above f (its "velocity") - still a vector! For a "regular function" the expression of an arc element is in fact Sqrt[1 + func'[t]^2], but of course, this cannot work here!

A clean solution - probably more the way you like it - could therefore simply be:

NIntegrate[Norm[f'[t]], {t, 0, 1}]

Regards -- Henrik

Posted 3 months ago

This is so much better! Clearly replacing ArcLength is the easier route to take.

I also find that BezierFunction does not play well with other functions, such as FunctionExpand and PiecewiseExpand. I have made my own replacement:

BezierSymbolicFunction[pts_?MatrixQ] := 
  Apply[Function, 
   List@Sum[
     pts[[i + 1]] BernsteinBasis[Length[pts] - 1, i, #], {i, 0, 
      Length[pts] - 1}]];

With this I get ArcLength without trouble:

pts = RandomReal[1, {4, 2}];
f = BezierSymbolicFunction[pts];
ArcLength[f[t], {t, 0, 1}]

Thank you, Gianluca,

now I understand the concept of BernsteinBasis and the like!

pts = CirclePoints[5];

(* according to Gianluca Gorni: *)
bezierSymbolicFunction[pts_List] := 
  Sum[pts[[i]] BernsteinBasis[Length[pts] - 1, i - 1, #], {i, 1, Length[pts]}] &;
(* now the same, but with 'Table' instead of 'Sum' *)
bernBas = Table[pts[[i]] BernsteinBasis[Length[pts] - 1, i - 1, #], {i, 1, Length[pts]}] &;

bezsf = bezierSymbolicFunction[pts];

Manipulate[
 Show[ParametricPlot[bezsf[t], {t, 0, end}, PlotRange -> {-1, 1.1}], 
  Graphics[{MapThread[Arrow[{#1, #2}] &, {ConstantArray[{0, 0}, Length[pts]], 
      bernBas[end]}], {Red, PointSize[.03], Point[pts]}}]], {end, 0.01, 1}]

enter image description here

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract