# 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:= f[0.5] Out= {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:= g[t_]:={t,t} In:= ArcLength[g[t], {t,0,1}] Out= ???SqrtBox["2"]? What's the correct way to do this? Answer
7 Replies
Sort By:
Posted 4 months ago
 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? Answer
Posted 3 months ago
 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] Answer
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? Answer
Posted 3 months ago
 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 : 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 Answer
Posted 3 months ago
 This is so much better! Clearly replacing ArcLength is the easier route to take. Answer
Posted 3 months ago
 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}] Answer
Posted 3 months ago
 Thank you, Gianluca,now I understand the concept of BernsteinBasis and the like! pts = CirclePoints; (* 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}]  Answer