Improve Bezier to piecewise linear conversion.
Instead of always using two points on every curve, with a hack for some cubics edge case, use three points on the first iteration and one point on every further iteration. This both faster and more correct.pull/4/head
parent
1e2a899ba2
commit
139dd80b48
|
@ -269,25 +269,47 @@ void SBezier::MakePwlInto(List<Vector> *l, double chordTol) {
|
||||||
// Never do fewer than one intermediate point; people seem to get
|
// Never do fewer than one intermediate point; people seem to get
|
||||||
// unhappy when their circles turn into squares, but maybe less
|
// unhappy when their circles turn into squares, but maybe less
|
||||||
// unhappy with octagons.
|
// unhappy with octagons.
|
||||||
MakePwlWorker(l, 0.0, 0.5, chordTol);
|
MakePwlInitialWorker(l, 0.0, 0.5, chordTol);
|
||||||
MakePwlWorker(l, 0.5, 1.0, chordTol);
|
MakePwlInitialWorker(l, 0.5, 1.0, chordTol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void SBezier::MakePwlWorker(List<Vector> *l, double ta, double tb,
|
void SBezier::MakePwlWorker(List<Vector> *l, double ta, double tb, double chordTol)
|
||||||
double chordTol)
|
|
||||||
{
|
{
|
||||||
Vector pa = PointAt(ta);
|
Vector pa = PointAt(ta);
|
||||||
Vector pb = PointAt(tb);
|
Vector pb = PointAt(tb);
|
||||||
|
|
||||||
// Can't test in the middle, or certain cubics would break.
|
Vector pm = PointAt((ta + tb) / 2.0);
|
||||||
double tm1 = (2*ta + tb) / 3;
|
double d = pm.DistanceToLine(pa, pb.Minus(pa));
|
||||||
double tm2 = (ta + 2*tb) / 3;
|
|
||||||
|
double step = 1.0/SS.maxSegments;
|
||||||
|
if((tb - ta) < step || d < chordTol) {
|
||||||
|
// A previous call has already added the beginning of our interval.
|
||||||
|
l->Add(&pb);
|
||||||
|
} else {
|
||||||
|
double tm = (ta + tb) / 2;
|
||||||
|
MakePwlWorker(l, ta, tm, chordTol);
|
||||||
|
MakePwlWorker(l, tm, tb, chordTol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SBezier::MakePwlInitialWorker(List<Vector> *l, double ta, double tb, double chordTol)
|
||||||
|
{
|
||||||
|
Vector pa = PointAt(ta);
|
||||||
|
Vector pb = PointAt(tb);
|
||||||
|
|
||||||
|
double tm1 = ta + (tb - ta) * 0.25;
|
||||||
|
double tm2 = ta + (tb - ta) * 0.5;
|
||||||
|
double tm3 = ta + (tb - ta) * 0.75;
|
||||||
|
|
||||||
Vector pm1 = PointAt(tm1);
|
Vector pm1 = PointAt(tm1);
|
||||||
Vector pm2 = PointAt(tm2);
|
Vector pm2 = PointAt(tm2);
|
||||||
|
Vector pm3 = PointAt(tm3);
|
||||||
|
Vector dir = pb.Minus(pa);
|
||||||
|
|
||||||
double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
|
double d = max({
|
||||||
pm2.DistanceToLine(pa, pb.Minus(pa)));
|
pm1.DistanceToLine(pa, dir),
|
||||||
|
pm2.DistanceToLine(pa, dir),
|
||||||
|
pm3.DistanceToLine(pa, dir)
|
||||||
|
});
|
||||||
|
|
||||||
double step = 1.0/SS.maxSegments;
|
double step = 1.0/SS.maxSegments;
|
||||||
if((tb - ta) < step || d < chordTol) {
|
if((tb - ta) < step || d < chordTol) {
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
void MakePwlInto(SContour *sc, double chordTol=0);
|
void MakePwlInto(SContour *sc, double chordTol=0);
|
||||||
void MakePwlInto(List<Vector> *l, double chordTol=0);
|
void MakePwlInto(List<Vector> *l, double chordTol=0);
|
||||||
void MakePwlWorker(List<Vector> *l, double ta, double tb, double chordTol);
|
void MakePwlWorker(List<Vector> *l, double ta, double tb, double chordTol);
|
||||||
|
void MakePwlInitialWorker(List<Vector> *l, double ta, double tb, double chordTol);
|
||||||
|
|
||||||
void AllIntersectionsWith(SBezier *sbb, SPointList *spl);
|
void AllIntersectionsWith(SBezier *sbb, SPointList *spl);
|
||||||
void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax);
|
void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax);
|
||||||
|
|
Loading…
Reference in New Issue