Skip to content

Commit

Permalink
fixed clip rect padding to ensure proper clip intersection computatio…
Browse files Browse the repository at this point in the history
…n (0.5px) for huge path elements
  • Loading branch information
bourgesl committed Jan 18, 2018
1 parent 62c522f commit 3d59806
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 76 deletions.
27 changes: 12 additions & 15 deletions src/main/java/org/marlin/pisces/DCurve.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,19 @@ final class DCurve {
}

void set(final double[] points, final int type) {
switch(type) {
case 8:
// if instead of switch (perf + most probable cases first)
if (type == 8) {
set(points[0], points[1],
points[2], points[3],
points[4], points[5],
points[6], points[7]);
return;
case 6:
} else if (type == 4) {
set(points[0], points[1],
points[2], points[3]);
} else {
set(points[0], points[1],
points[2], points[3],
points[4], points[5]);
return;
case 4:
set(points[0], points[1],
points[2], points[3]);
return;
default:
throw new InternalError("Curves can only be cubic or quadratic");
}
}

Expand Down Expand Up @@ -111,10 +106,12 @@ void set(final double x1, final double y1,
cy = dy21;
dx = x1; // D = P1
dy = y1;
dax = 0.0d; // USELESS
day = 0.0d;
dbx = 0.0d;
dby = 0.0d;
if (false) {
dax = 0.0d;
day = 0.0d;
dbx = 0.0d;
dby = 0.0d;
}
}

int dxRoots(final double[] roots, final int off) {
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/org/marlin/pisces/DDasher.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
*/
final class DDasher implements DPathConsumer2D, MarlinConst {

private static final boolean TRACE = false;

/* huge circle with radius ~ 2E9 only needs 12 subdivision levels */
static final int REC_LIMIT = 16;
static final double ERR = 0.01d;
Expand Down Expand Up @@ -376,11 +378,11 @@ public void lineTo(final double x1, final double y1) {

this.cOutCode = outcode1;
}
_lineTo(x1, y1);
}

private void _lineTo(final double x1, final double y1)
{
if (TRACE) {
System.out.println("Dasher _lineTo P0(" + cx0 + ", " + cy0 + ") P1(" + x1 + ", " + y1 + ")");
}

final double dx = x1 - cx0;
final double dy = y1 - cy0;

Expand Down Expand Up @@ -900,7 +902,7 @@ public void quadTo(final double x1, final double y1,
// avoid reentrance
subdivide = false;
// subdivide curve => call lineTo() with subdivided curves:
boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
x2, y2, orCode, this);
// reentrance is done:
subdivide = true;
Expand All @@ -923,7 +925,7 @@ public void quadTo(final double x1, final double y1,

private void _quadTo(final double x1, final double y1,
final double x2, final double y2)
{
{
final double[] _curCurvepts = curCurvepts;

// monotonize quad:
Expand Down
17 changes: 3 additions & 14 deletions src/main/java/org/marlin/pisces/DHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,6 @@ static int filterOutNotInAB(final double[] nums, final int off, final int len,
return ret;
}

static double length(final double[] pts, final int type) {
// if instead of switch (perf + most probable cases first)
if (type == 4) {
return linelen (pts[0], pts[1], pts[2], pts[3]);
} else if (type == 8) {
return curvelen(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5], pts[6], pts[7]);
} else {
return quadlen (pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
}
}

static double linelen(final double x0, final double y0,
final double x1, final double y1)
{
Expand Down Expand Up @@ -562,10 +551,10 @@ static void subdivideAt(final double t,
final double[] pts, final int offL, final int type)
{
// if instead of switch (perf + most probable cases first)
if (type == 4) {
subdivideLineAt(t, src, offS, pts, offL, offL + type);
} else if (type == 8) {
if (type == 8) {
subdivideCubicAt(t, src, offS, pts, offL, offL + type);
} else if (type == 4) {
subdivideLineAt(t, src, offS, pts, offL, offL + type);
} else {
subdivideQuadAt(t, src, offS, pts, offL, offL + type);
}
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/org/marlin/pisces/DMarlinRenderingEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,14 @@ void strokeTo(final DRendererContext rdrCtx,
pc2d = rdrCtx.dasher.init(pc2d, dashesD, dashLen, dashphase,
recycleDashes);

rdrCtx.stroker.disableClipping();

// Curve Monotizer:
rdrCtx.monotonizer.init(width);

// TODO decide (not ?)
if (false) {
rdrCtx.stroker.disableClipping();
}

} else if (rdrCtx.doClip && (caps != Stroker.CAP_BUTT)) {
if (DO_TRACE_PATH) {
pc2d = transformerPC2D.traceClosedPathDetector(pc2d);
Expand Down Expand Up @@ -1168,10 +1171,10 @@ private static void logSettings(final String reClass) {
+ MarlinProperties.getQuadDecD2());

logInfo("Renderer settings:");

logInfo("MAX_LEN (CurveClipSplitter) = "
+ DTransformingPathConsumer2D.CurveClipSplitter.MAX_LEN); // TODO: use system property

logInfo("CUB_DEC_BND = " + DRenderer.CUB_DEC_BND);
logInfo("CUB_INC_BND = " + DRenderer.CUB_INC_BND);
logInfo("QUAD_DEC_BND = " + DRenderer.QUAD_DEC_BND);
Expand Down
25 changes: 11 additions & 14 deletions src/main/java/org/marlin/pisces/DStroker.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ DStroker init(final DPathConsumer2D pc2d,
rdrOffY = scale * DRenderer.RDR_OFFSET_Y;
}
// add a rounding error (curve subdivision ~ 0.1px):
margin += DTransformingPathConsumer2D.CLIP_RECT_PADDING;
margin += 1e-3d;

// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust clip rectangle (ymin, ymax, xmin, xmax):
Expand All @@ -194,6 +194,10 @@ DStroker init(final DPathConsumer2D pc2d,
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;
this.clipRect = _clipRect;

// adjust padded clip rectangle:
curveSplitter.init();

} else {
this.clipRect = null;
this.cOutCode = 0;
Expand All @@ -203,11 +207,9 @@ DStroker init(final DPathConsumer2D pc2d,
}

void disableClipping() {
if (false) {
this.clipRect = null;
this.cOutCode = 0;
this.sOutCode = 0;
}
this.clipRect = null;
this.cOutCode = 0;
this.sOutCode = 0;
}

/**
Expand Down Expand Up @@ -568,12 +570,7 @@ private void lineTo(final double x1, final double y1,

this.cOutCode = outcode1;
}
_lineTo(x1, y1, outcode0);
}

private void _lineTo(final double x1, final double y1,
final int outcode0)
{
double dx = x1 - cx0;
double dy = y1 - cy0;
if (dx == 0.0d && dy == 0.0d) {
Expand Down Expand Up @@ -1072,8 +1069,8 @@ public void curveTo(final double x1, final double y1,
// avoid reentrance
subdivide = false;
// subdivide curve => callback with subdivided parts:
boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
x2, y2, x3, y3,
boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
x2, y2, x3, y3,
orCode, this);
// reentrance is done:
subdivide = true;
Expand Down Expand Up @@ -1220,7 +1217,7 @@ public void quadTo(final double x1, final double y1,
// avoid reentrance
subdivide = false;
// subdivide curve => call lineTo() with subdivided curves:
boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
x2, y2, orCode, this);
// reentrance is done:
subdivide = true;
Expand Down
58 changes: 41 additions & 17 deletions src/main/java/org/marlin/pisces/DTransformingPathConsumer2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ PathClipFilter init(final DPathConsumer2D out) {
_clipRect[2] -= margin - rdrOffX;
_clipRect[3] += margin + rdrOffX;

// adjust padded clip rectangle:
curveSplitter.init();

this.init_corners = true;
this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;

Expand Down Expand Up @@ -648,10 +651,10 @@ public void lineTo(final double xe, final double ye) {
boolean ret;
// subdivide curve => callback with subdivided parts:
if (outside) {
ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
orCode, this);
} else {
ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
orCode, this);
}
// reentrance is done:
Expand Down Expand Up @@ -747,12 +750,12 @@ public void curveTo(final double x1, final double y1,
// subdivide curve => callback with subdivided parts:
boolean ret;
if (outside) {
ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
x2, y2, xe, ye,
ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
x2, y2, xe, ye,
orCode, this);
} else {
ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
x2, y2, xe, ye,
ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
x2, y2, xe, ye,
orCode, this);
}
// reentrance is done:
Expand Down Expand Up @@ -809,10 +812,10 @@ public void quadTo(final double x1, final double y1,
// subdivide curve => callback with subdivided parts:
boolean ret;
if (outside) {
ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
xe, ye, orCode, this);
} else {
ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
xe, ye, orCode, this);
}
// reentrance is done:
Expand Down Expand Up @@ -861,12 +864,15 @@ static final class CurveClipSplitter {

private static final int MAX_N_CURVES = 3 * 4;

// Bounds of the drawing region, at pixel precision.
private final double[] clipRect;
// clip rectangle (ymin, ymax, xmin, xmax):
final double[] clipRect;

// clip rectangle (ymin, ymax, xmin, xmax) including padding:
final double[] clipRectPad = new double[4];

// This is where the curve to be processed is put. We give it
// enough room to store all curves.
final double[] middle = new double[MAX_N_CURVES * 6 + 2];
final double[] middle = new double[MAX_N_CURVES * 8 + 2];
// t values at subdivision points
private final double[] subdivTs = new double[MAX_N_CURVES];

Expand All @@ -878,6 +884,24 @@ static final class CurveClipSplitter {
this.curve = rdrCtx.curve;
}

void init() {
// bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
// adjust padded clip rectangle (ymin, ymax, xmin, xmax):
// add a rounding error (curve subdivision ~ 0.1px):
final double[] _clipRect = clipRect;
final double[] _clipRectPad = clipRectPad;

_clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
_clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
_clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
_clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;

if (TRACE) {
System.out.println("clip: X [" + clipRectPad[2] + " .. " + clipRectPad[3] +"] "
+ "Y ["+ clipRectPad[0] + " .. " + clipRectPad[1] +"]");
}
}

boolean splitLine(final double x0, final double y0,
final double x1, final double y1,
final int outCodeOR,
Expand Down Expand Up @@ -911,7 +935,7 @@ boolean splitQuad(final double x0, final double y0,
if (DHelpers.quadlen(x0, y0, x1, y1, x2, y2) <= MAX_LEN) {
return false;
}

final double[] mid = middle;
mid[0] = x0; mid[1] = y0;
mid[2] = x1; mid[3] = y1;
Expand Down Expand Up @@ -951,10 +975,9 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
final double[] subTs = subdivTs;

final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
outCodeOR, clipRect);
outCodeOR, clipRectPad);

if (TRACE) {
System.out.println("clip: X [" + clipRect[2] + " .. " + clipRect[3] +"] Y ["+ clipRect[0] + " .. " + clipRect[1] +"]");
System.out.println("nSplits: "+ nSplits);
System.out.println("subTs: "+Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
}
Expand All @@ -963,6 +986,7 @@ private boolean subdivideAtIntersections(final int type, final int outCodeOR,
return false;
}
double prevT = 0.0d;

for (int i = 0, off = 0; i < nSplits; i++, off += type) {
final double t = subTs[i];

Expand All @@ -985,12 +1009,12 @@ static void emitCurrent(final int type, final double[] pts,
final int off, final DPathConsumer2D out)
{
// if instead of switch (perf + most probable cases first)
if (type == 4) {
out.lineTo(pts[off + 2], pts[off + 3]);
} else if (type == 8) {
if (type == 8) {
out.curveTo(pts[off + 2], pts[off + 3],
pts[off + 4], pts[off + 5],
pts[off + 6], pts[off + 7]);
} else if (type == 4) {
out.lineTo(pts[off + 2], pts[off + 3]);
} else {
out.quadTo(pts[off + 2], pts[off + 3],
pts[off + 4], pts[off + 5]);
Expand Down
Loading

0 comments on commit 3d59806

Please sign in to comment.