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.
This commit is contained in:
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
|
||||
// unhappy when their circles turn into squares, but maybe less
|
||||
// unhappy with octagons.
|
||||
MakePwlWorker(l, 0.0, 0.5, chordTol);
|
||||
MakePwlWorker(l, 0.5, 1.0, chordTol);
|
||||
MakePwlInitialWorker(l, 0.0, 0.5, chordTol);
|
||||
MakePwlInitialWorker(l, 0.5, 1.0, chordTol);
|
||||
}
|
||||
}
|
||||
void SBezier::MakePwlWorker(List<Vector> *l, double ta, double tb,
|
||||
double chordTol)
|
||||
void SBezier::MakePwlWorker(List<Vector> *l, double ta, double tb, double chordTol)
|
||||
{
|
||||
Vector pa = PointAt(ta);
|
||||
Vector pb = PointAt(tb);
|
||||
|
||||
// Can't test in the middle, or certain cubics would break.
|
||||
double tm1 = (2*ta + tb) / 3;
|
||||
double tm2 = (ta + 2*tb) / 3;
|
||||
Vector pm = PointAt((ta + tb) / 2.0);
|
||||
double d = pm.DistanceToLine(pa, pb.Minus(pa));
|
||||
|
||||
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 pm2 = PointAt(tm2);
|
||||
Vector pm3 = PointAt(tm3);
|
||||
Vector dir = pb.Minus(pa);
|
||||
|
||||
double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
|
||||
pm2.DistanceToLine(pa, pb.Minus(pa)));
|
||||
double d = max({
|
||||
pm1.DistanceToLine(pa, dir),
|
||||
pm2.DistanceToLine(pa, dir),
|
||||
pm3.DistanceToLine(pa, dir)
|
||||
});
|
||||
|
||||
double step = 1.0/SS.maxSegments;
|
||||
if((tb - ta) < step || d < chordTol) {
|
||||
|
@ -93,6 +93,7 @@ public:
|
||||
void MakePwlInto(SContour *sc, double chordTol=0);
|
||||
void MakePwlInto(List<Vector> *l, double chordTol=0);
|
||||
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 GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax);
|
||||
|
Loading…
Reference in New Issue
Block a user