13

Bug introduced in version 10.0 and fixed in version 12.0
DiscretizeGraphics is new in 10.0.


I need to create a discretized region from a BezierCurve.

This is one of my curves:

pt = {{93.2759`, 277.0452`}, {90.6249`, 
      273.3252`}, {79.7499`, 255.70020000000002`}, {76.9999`, 
      250.70020000000002`}, {74.2499`, 
      245.70020000000002`}, {70.2499`, 
      237.70020000000002`}, {69.9999`, 235.32520000000002`}};
g = Graphics[{BezierCurve[pt]}];

DiscretizeGraphics creates points which are close to the curve, but clearly not on it.

Please try

Show[g, DiscretizeGraphics[g]]

This is a magnified portion of the result:

enter image description here

There is a small but consistent difference between the discretized version and the original graphics.

What is going on?

Which one is wrong? The BezierCurve rendering or the discretization? If it's the discretization, then:

What workarounds are there for the problem? Could I sample the points on the curve using BezierFunction? If yes, how exactly? BezierFunction[points] and BezierCurve[points] don't seem to represent the same curve.


My ultimate aim is to discretize some objects imported from a PDF. One of them is a closed JoinedCurve (or FilledCurve) and I need to use it to filter certain points which are inside the region. The other one (shown above) is a non-closed JoinedCurve, consisting of BezierCurve[..., SplineDegree -> 3] and Line[...] segments. DiscretizeGraphics does not work on JoinedCurve/FilledCurve.


Additional information:

BezierFunction and BezierCurve do not give the same result in the following test:

ParametricPlot[BezierFunction[pt][x], {x, 0, 1}, Epilog -> {BezierCurve[pt]}]

Again there is a small but consistent difference. Why?

Here's a different point set where BezierCurve and BezierFunction give very different results. How can I use BezierFunction to reproduce the same thing I see with BezierCurve?

pt = {{85.6699, 270.639}, {81.4849, 265.53}, {72.1939, 247.082}, {69.5059, 
  244.27}, {66.8189, 241.46}, {65.3979, 237.927}, {64.1759, 
  236.649}, {62.9539, 235.372}, {75.0969, 229.142}, {76.6069, 
  228.676}, {78.1179, 228.21}, {75.1319, 234.644}, {75.2469, 
  237.147}, {75.3609, 239.65}, {80.5859, 252.02}, {82.9949, 
  256.076}, {85.4049, 260.131}, {92.1679, 270.779}, {93.5919, 
  274.19}, {95.0159, 277.6}, {92.9719, 279.555}, {85.6699, 270.639}}

Posted a related question on Wolfram Community.

Silvia
  • 27,556
  • 3
  • 84
  • 164
Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • You can export a bspline as pdf then import the pdf. See my answer here. – Silvia Oct 29 '15 at 11:42
  • The other possibility is to use ParametricPlot[] + BezierFunction[] to create a Line[] primitive that should now be easily discretized. Can you give an example where BezierCurve[] doesn't seem to give the same result as my proposal? – J. M.'s missing motivation Oct 29 '15 at 11:44
  • With respect to JoinedCurve[]/FilledCurve[]: if memory serves Simon Woods has a post somewhere on how to split those into components. – J. M.'s missing motivation Oct 29 '15 at 11:45
  • @J.M. The same example from this post doesn't. ParametricPlot[BezierFunction[pt][x], {x, 0, 1}, Epilog -> {BezierCurve[pt]}], where pt are the points from above. – Szabolcs Oct 29 '15 at 11:46
  • @Silvia If I export/import to/from PDF, I still get a JoinedCurve with a BezierCurve inside (after decoding using GeometricFunctions`DecodeJoinedCurve), so I'm back to the same problem. There's also an additional problem: the coordinates have all changed. I need to do measurements on these objects (imported form a single PDF), so they must all be in the same coordinate system. – Szabolcs Oct 29 '15 at 11:50
  • @J.M. With these different set of points, {{85.6699, 270.639}, {81.4849, 265.53}, {72.1939, 247.082}, {69.5059, 244.27}, {66.8189, 241.46}, {65.3979, 237.927}, {64.1759, 236.649}, {62.9539, 235.372}, {75.0969, 229.142}, {76.6069, 228.676}, {78.1179, 228.21}, {75.1319, 234.644}, {75.2469, 237.147}, {75.3609, 239.65}, {80.5859, 252.02}, {82.9949, 256.076}, {85.4049, 260.131}, {92.1679, 270.779}, {93.5919, 274.19}, {95.0159, 277.6}, {92.9719, 279.555}, {85.6699, 270.639}}, the above ParametricPlot also gives differing results. Is it because I need to set SplineDegrees? – Szabolcs Oct 29 '15 at 11:51
  • bfun = BezierFunction[pt]; ParametricPlot[bfun[t], {t, 0, 1}, PlotPoints -> 25, Prolog -> {Directive[AbsoluteThickness[3], ColorData[97, 2]], BezierCurve[pt]}] gives this for me. – J. M.'s missing motivation Oct 29 '15 at 11:52
  • It's one possibility, yes: you may want to ensure that the two curves do have the same degree, though honestly I can't think of a situation that doesn't produce cubic curves. – J. M.'s missing motivation Oct 29 '15 at 11:53
  • @J.M. Yes, I get the same. There is a small but persistent difference. I don't understand why and I worry it's going to turn into a big difference for some other input data. Sorry for having only this almost straight curv as an example ... – Szabolcs Oct 29 '15 at 11:57
  • Something doesn't seem right with BezierFunction[]; it seems it's not allowing an explicit SplineDegree setting. I don't remember this being the case in version 8... – J. M.'s missing motivation Oct 29 '15 at 11:57
  • @J.M. The only SplineDegree setting it accepts from me is Length[pt] - 1. – Szabolcs Oct 29 '15 at 11:58
  • Maybe we should try roping in somebody with an earlier version to check. I'm positive that discrepancy wasn't there before. – J. M.'s missing motivation Oct 29 '15 at 12:04
  • @Jacob, can you test Szabolcs's observations, please? – J. M.'s missing motivation Oct 29 '15 at 13:17
  • @Jacob, I was talking about comparing the result of BezierCurve[] and BezierFunction[] + ParametricPlot[], actually. As I mentioned, I don't believe there was a discrepancy like this in version 8, and was hoping for a confirmatory test. – J. M.'s missing motivation Oct 29 '15 at 13:22
  • I do see the same in v9. I don't have v8 handy. – Szabolcs Oct 29 '15 at 13:25
  • For the last example, things look pretty much identical in v8 and v10 – Jacob Akkerboom Oct 29 '15 at 13:41
  • That's funny... @Jacob, does it still happen after you increase the PlotPoints setting? – J. M.'s missing motivation Oct 29 '15 at 13:59
  • @J.M. yeah, the picture hardly changes with PlotPoints-> 10000 – Jacob Akkerboom Oct 29 '15 at 14:21
  • Could you tell me how to use the undocumented functions in the context ``GeometricFunctions```? I discovered that there are my useful functions. BTW, is it possible to see the internal code of these function by some method, like PrintDifitions[] that in package GeneralUtilities? Thanks. – xyz Oct 30 '15 at 05:56
  • @ShutaoTANG I only know this: http://mathematica.stackexchange.com/a/570/12 – Szabolcs Oct 30 '15 at 07:01
  • I think this has been fixed in 12.0. – Silvia Nov 16 '19 at 04:57
  • I tested this on Windows and the bug seems to be fixed in 12.0. If others find otherwise status please feel free to roll back. – Silvia Nov 22 '19 at 04:34

1 Answers1

12

This was solved with help from Shutao Tang, J.M., Sander Huisman and Eric Rimbey.

  1. Why do BezierFunction[pt] and BezierCurve[pt] not agree?

    Because BezierCurve uses SplineDegree -> 3 by default and BezierFunction always uses degree Length[pt] - 1 (not settable).

  2. Why does DiscretizeGraphics give a bad result?

    Because it appears to use (the equivalent of) BezierFunction[pt] internally. This is a bug. Witness:

    pt = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {2, 0}};
    g = Graphics[{BezierCurve[pt]}];
    Show[g, 
      ParametricPlot[BezierFunction[pt][x], {x, 0, 1}, 
       PlotStyle -> Directive[AbsoluteThickness[3], Yellow]], 
     DiscretizeGraphics[g]
    ]
    

    Mathematica graphics

  3. How can we reproduce a BezierCurve using BezierFunction?

    By stitching together several degree-3 (or less) BezierFunctions:

    funs = BezierFunction /@ Partition[pt, 4, 3, {1, 1}, {}];
    Show[Table[ParametricPlot[f[x], {x, 0, 1}], {f, funs}], PlotRange -> All]
    

    Mathematica graphics

    DiscretizeGraphics can then be applied to this.

xyz
  • 605
  • 4
  • 38
  • 117
Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • do you get an error when you enter the line funs = BezierFunction /@ Partition[pt, 4, 3, {1, 1}, {}];? I find that the Partition command creates a list whose last element only has one point. I can only get it to work without error if I add [[;;-2]] after the Partition – Jason B. Dec 11 '15 at 11:12