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
|
||||
// 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