Flattenerpublic class Flattener extends PathSink The Flattener class rewrites a general path, which
may include curved segments, into one containing only linear
segments suitable for sending to a LineSink .
Curved segments specified by quadTo and
curveTo commands will be subdivided into two pieces.
When the control points of a segment lie sufficiently close
togther, such that max(x_i) - min(x_i) < flatness and
max(y_i) - min(y_i) < flatness for a user-supplied
flatness parameter, a lineTo command is
emitted between the first and last points of the curve. |
Fields Summary |
---|
public static final long | MAX_CHORD_LENGTH_SQ | public static final long | MIN_CHORD_LENGTH_SQ | public static final int | LG_FLATNESS | public static final int | FLATNESS_SQ_SHIFT | LineSink | output | int | flatness | int | flatnessSq | int | x0 | int | y0 |
Constructors Summary |
---|
public Flattener()Empty constructor. setOutput and
setFlatness must be called prior to calling any
other methods.
| public Flattener(LineSink output, int flatness)Constructs a Flattener that will rewrite any
incoming quadTo and curveTo commands
into a series of lineTo commands with maximum X
and Y extents no larger than the supplied flatness
value. The flat segments will be sent as commands to the given
LineSink .
setOutput(output);
setFlatness(flatness);
|
Methods Summary |
---|
public void | close()
output.lineJoin();
output.close();
| public void | cubicTo(int x1, int y1, int x2, int y2, int x3, int y3)
output.lineJoin();
cubicToHelper(x1, y1, x2, y2, x3, y3);
| private void | cubicToHelper(int x1, int y1, int x2, int y2, int x3, int y3)
if (flatEnough(x0, y0, x1, y1, x2, y2, x3, y3)) {
output.lineTo(x1, y1);
output.lineTo(x2, y2);
output.lineTo(x3, y3);
} else {
long lx1 = (long)x1;
long ly1 = (long)y1;
long lx2 = (long)x2;
long ly2 = (long)y2;
long x01 = x0 + lx1; // >> 1
long y01 = y0 + ly1; // >> 1
long x12 = lx1 + lx2; // >> 1
long y12 = ly1 + ly2; // >> 1
long x23 = lx2 + x3; // >> 1
long y23 = ly2 + y3; // >> 1
long x012 = x01 + x12; // >> 2
long y012 = y01 + y12; // >> 2
long x123 = x12 + x23; // >> 2
long y123 = y12 + y23; // >> 2
long x0123 = x012 + x123; // >> 3
long y0123 = y012 + y123; // >> 3
cubicToHelper((int)(x01 >> 1), (int)(y01 >> 1),
(int)(x012 >> 2), (int)(y012 >> 2),
(int)(x0123 >> 3), (int)(y0123 >> 3));
cubicToHelper((int)(x123 >> 2), (int)(y123 >> 2),
(int)(x23 >> 1), (int)(y23 >> 1),
x3, y3);
}
this.x0 = x3;
this.y0 = y3;
| public void | end()
output.end();
| private boolean | flatEnough(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3)
long dx = (long)x3 - (long)x0; // S47.16
long dy = (long)y3 - (long)y0; // S47.16
long denom2 = dx*dx + dy*dy; // S31.32
// Always subdivide curves with a large chord length
if (denom2 > MAX_CHORD_LENGTH_SQ) {
return false;
}
// Stop dividing if all control points are close together
if (denom2 < MIN_CHORD_LENGTH_SQ) {
int minx = Math.min(Math.min(Math.min(x0, x1), x2), x3);
int miny = Math.min(Math.min(Math.min(y0, y1), y2), y3);
int maxx = Math.max(Math.max(Math.max(x0, x1), x2), x3);
int maxy = Math.max(Math.max(Math.max(y0, y1), y2), y3);
long dx1 = (long)maxx - (long)minx;
long dy1 = (long)maxy - (long)miny;
long l2 = dx1*dx1 + dy1*dy1;
if (l2 < MIN_CHORD_LENGTH_SQ) {
return true;
}
}
// Want to know if num/denom < flatness, so compare
// numerator^2 against (denominator*flatness)^2 to avoid a square root
long df2 = denom2*flatnessSq >> 16; // S31.32
long cross = (long)x0*y3 - (long)x3*y0; // S31.32
long num1 = dx*y1 - dy*x1 + cross; // S31.32
num1 >>= 16; // S47.16
long num1sq = num1*num1; // S31.32
if (num1sq > df2) {
return false;
}
long num2 = dx*y2 - dy*x2 + cross; // S31.32
num2 >>= 16; // S47.16
long num2sq = num2*num2; // S31.32
return num2sq < df2;
| private boolean | flatEnough(int x0, int y0, int x1, int y1, int x2, int y2)
long dx = (long)x2 - (long)x0;
long dy = (long)y2 - (long)y0;
long denom2 = dx*dx + dy*dy;
if (denom2 > MAX_CHORD_LENGTH_SQ) {
return false;
}
// Stop dividing if all control points are close together
if (denom2 < MIN_CHORD_LENGTH_SQ) {
int minx = Math.min(Math.min(x0, x1), x2);
int miny = Math.min(Math.min(y0, y1), y2);
int maxx = Math.max(Math.max(x0, x1), x2);
int maxy = Math.max(Math.max(y0, y1), y2);
long dx1 = (long)maxx - (long)minx;
long dy1 = (long)maxy - (long)miny;
long l2 = dx1*dx1 + dy1*dy1;
if (l2 < MIN_CHORD_LENGTH_SQ) {
return true;
}
}
long num = -dy*x1 + dx*y1 + ((long)x0*y2 - (long)x2*y0);
num >>= 16;
long numsq = num*num;
long df2 = denom2*flatnessSq >> 16;
return numsq < df2;
| public void | lineJoin()
output.lineJoin();
| public void | lineTo(int x1, int y1)
output.lineJoin();
output.lineTo(x1, y1);
this.x0 = x1;
this.y0 = y1;
| public void | moveTo(int x0, int y0)
output.moveTo(x0, y0);
this.x0 = x0;
this.y0 = y0;
| public void | quadTo(int x1, int y1, int x2, int y2)
output.lineJoin();
quadToHelper(x1, y1, x2, y2);
| private void | quadToHelper(int x1, int y1, int x2, int y2)
if (flatEnough(x0, y0, x1, y1, x2, y2)) {
output.lineTo(x1, y1);
output.lineTo(x2, y2);
} else {
long lx1 = (long)x1;
long ly1 = (long)y1;
long x01 = x0 + lx1; // >> 1
long y01 = y0 + ly1; // >> 1
long x12 = lx1 + x2; // >> 1
long y12 = ly1 + y2; // >> 1
long x012 = x01 + x12; // >> 2
long y012 = y01 + y12; // >> 2
quadToHelper((int)(x01 >> 1), (int)(y01 >> 1),
(int)(x012 >> 2), (int)(y012 >> 2));
quadToHelper((int)(x12 >> 1), (int)(y12 >> 1),
x2, y2);
}
this.x0 = x2;
this.y0 = y2;
| public void | setFlatness(int flatness)Sets the desired output flatness for this Flattener .
this.flatness = flatness;
this.flatnessSq = (int)((long)flatness*flatness >> 16);
| public void | setOutput(LineSink output)Sets the output LineSink of this
Flattener .
this.output = output;
|
|