Skip to content

Commit

Permalink
Improve Bezier to piecewise linear conversion.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Evil-Spirit authored and whitequark committed Feb 13, 2016
1 parent 1e2a899 commit 139dd80
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 10 deletions.
42 changes: 32 additions & 10 deletions src/srf/ratpoly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
pm2.DistanceToLine(pa, pb.Minus(pa)));
Vector pm3 = PointAt(tm3);
Vector dir = 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) {
Expand Down
1 change: 1 addition & 0 deletions src/srf/surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class SBezier {
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);
Expand Down

0 comments on commit 139dd80

Please sign in to comment.