1

I am trying to correct Mathics' ability to draw Bézier curves properly in Asymptote, and I have a hard time understanding how to translate Mathematica's Specification into Asymptote. I haven't found an easy-to-understand description or tutorial of how to draw Bézier Curves in Asymptote.

So let me try show what I want to be able to do with a basic example:

Mathematica (actually, Mathics):

Graphics[BezierCurve[{{0,0}, {1,1}, {2, -1}, {3,0}}]]

BezierCurve of 3 points, showing control-points lines

Incorrect translation of first example above:

usepackage("amsmath");
size(5.8333cm, 5.8333cm);
// BezierCurveBox
draw(0,.0.0),  rgb(0, 0, 0)+linewidth(0.66667));
draw((0.,0.)..controls(155.56,213.89) and 
(194.44,194.44)..(233.33,116.67), 
rgb(0, 0, 0)+linewidth(0.66667));

zig-zag Bézier curve

Above, I have given how Mathics currently converts this. One of the bugs seen above seems to have to do with translating control-point coordinates to center the figure in overall image window, while not translating some of the non-control points. And there is what looks like a stray point drawn at the beginning.

I leave this in. But in giving a solution, feel free to totally disregard this and describe something from scratch that has the same shape as what is intended.

So how do I fix this, and how do I think about doing correct translations like the Mathematica-to-Asymptote example above?

Follow on:

I have implemented the accepted answer and that works for the more simplified example I gave, but when I extend the number of points to

pts = {{0, 0}, {1, 1}, {2, -1}, {3, 0}, {5, 2}, {6, -1}, {7, 3}};

it looks like the accepted answer differs from what Mathematica does here.

It looks like the output from the accepted answer:

accepted answer curve on 7 points

is more influenced by point 4 than what Mathematica does. And I also note that there is a SplineDegree:

With SplineDegree->d, BezierCurve with d+1 control points yields a simple degree-d Bézier curve. With fewer control points, a lower-degree curve is generated. With more control points, a composite Bézier curve is generated.

As found in the comment by @WillieWong what is going on is that Mathematica draws curves three points at a time which is also seems to be how SVG handles lists of points.

How to I handle curves of higher degree?

Lastly, I should mention that the next release of Mathics will incorporate the improvements due to the information and help found here.

rocky
  • 175
  • 8
  • How is this related to (La)TeX exactly? I mean, I see some tikz-esque code in your question, but I don't see the connection. – Markus G. Aug 11 '21 at 11:03
  • @MarkusG.: Hi Markus, Asymptote questions are definitely allowed on this site. – James Aug 11 '21 at 11:05
  • @James Ah, ok, I didn't know that. Sorry for the confusion. – Markus G. Aug 11 '21 at 11:06
  • 3
    you call the asymptote code a translation, but the coordinates are completely different, where did they come from? I'd expect to see the same numbers, the mathematics of the curve are the same whatever software you are using to generate the plot. – David Carlisle Aug 11 '21 at 11:35
  • @DavidCarlisle some of the coordinates have been translated to center the curve. In particular I suspect the control points have been translated while some of the points on the curve haven't and no doubt that is part of the existing bug. That is why on the correct SVG-based image the curve starts not at one of the edges.

    If it helps, any point(s) can be adjusted accordingly for the original or translated coordinated space. I am more interested having something having the right shape rather than where it is located in the graph.

    – rocky Aug 11 '21 at 11:57
  • 1
    The accepted answer generates a degree $d$ Bezier curve for $d+1$ inputs. The Mathematica version when given $3k+1$ inputs draws $k$ degree-3 bezier curves joined end to end. (Or, if the spline degree $d$ is set, it would require $kd+1$ inputs.) – Willie Wong Aug 13 '21 at 19:30
  • @WillieWong Ah - I was wondering about what was going on. If this is what is going on, I may be able to fix this up myself by just iterating over the given example d (or k) times. – rocky Aug 13 '21 at 20:15
  • @rocky You should post your questions to https://github.com/vectorgraphics/asymptote/issues, authors can help with more information. – Nguyen Van Chi Aug 14 '21 at 01:32
  • @NguyenVanChi1998 As someone who has a number of open source projects myself, I find that issues are for, well, issues and not for questions about how to use something. There are far more people who can answer a question about how to use Asymptote, than there are Asymptote developers. If after working things out, we find that there is a bug in Asymptote, or a desired feature, then that makes sense to open an issue. – rocky Aug 14 '21 at 12:42

1 Answers1

2

As far as I know, you can completely do this based on the formula of Bézier curve.

Like this,

import graph;

pair Bezier(pair P[], real t) { // https://tex.stackexchange.com/a/554290/236162 pair Bezi; for (int k=0; k <= P.length-1; ++k) {
Bezi=Bezi+choose(P.length-1,k)(1-t)^(P.length-1-k)t^k*P[k]; } return Bezi; }

unitsize(1cm); pair[] P={(0,0),(1,1),(2,-1)}; pair[] Q={(0,0),(1,1),(2,-1),(3,0)}; pair F(real t){return Bezier(P,t);} pair G(real t){return Bezier(Q,t);}

draw(graph(F,0,1,350),red); draw(operator --(... P)); draw(shift(0,-2)graph(G,0,1,350),red); draw(shift(0,-2)operator --(... Q));

enter image description here

See also in the documentation: 5 Bezier curves

The Bezier curve constructed in this manner has the following properties:

It is entirely contained in the convex hull of the given four points.

It starts heading from the first endpoint to the first control point and finishes heading from the second control point to the second endpoint.

  • @NguyenVanChi1988 I implemented this in Mathics https://github.com/mathics/Mathics/blob/master/mathics/format/asy_fns.py#L8-L22 but in testing further I see that it implements something slightly different from Mathematica. See https://reference.wolfram.com/language/ref/BezierCurve.html and the notes under "Follow on" in the question that I just added. – rocky Aug 13 '21 at 16:40