--- old/modules/javafx.graphics/src/main/java/com/sun/marlin/RendererNoAA.java 2016-11-30 22:48:57.654420905 +0100 +++ new/modules/javafx.graphics/src/main/java/com/sun/marlin/RendererNoAA.java 2016-11-30 22:48:57.426420888 +0100 @@ -90,12 +90,19 @@ // quad break into lines // quadratic error in subpixels private static final float QUAD_DEC_ERR_SUBPIX - = 1f * (1f / 8f); // 1 pixel for typical 1x1 subpixels + = 0.5f * (1f / 8f); // 1 pixel for typical 1x1 subpixels // quadratic bind length to decrement step = 8 * error in subpixels public static final float QUAD_DEC_BND = 8f * QUAD_DEC_ERR_SUBPIX; + public static final boolean USE_SUBDIVIDE_QUAD = false; + public static final int SUBDIVIDE_MAX = 30; + + public static final float QUAD_ERR_SUBPIX = 1f / 16f; + public static final float MAX_FLAT_SQ + = 4f * QUAD_ERR_SUBPIX * QUAD_ERR_SUBPIX; // x4 + ////////////////////////////////////////////////////////////////////////////// // SCAN LINE ////////////////////////////////////////////////////////////////////////////// @@ -683,15 +690,120 @@ } @Override - public void quadTo(float x1, float y1, float x2, float y2) { - final float xe = tosubpixx(x2); - final float ye = tosubpixy(y2); - curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye); - quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); + public void quadTo(float pix_x1, float pix_y1, + float pix_x2, float pix_y2) + { + final float cx1 = tosubpixx(pix_x1); + final float cy1 = tosubpixy(pix_y1); + + final float xe = tosubpixx(pix_x2); + final float ye = tosubpixy(pix_y2); + + if (USE_SUBDIVIDE_QUAD) { + subdivideQuad(0, x0, y0, cx1, cy1, xe, ye); + } else { + curve.set(x0, y0, cx1, cy1, xe, ye); + quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye); + } x0 = xe; y0 = ye; } + void subdivideQuad(final int level, + final float x0, final float y0, + final float x1, final float y1, + final float x2, final float y2) + { + if (level < SUBDIVIDE_MAX) { + + /* Test if the curve is flat enough for insertion. */ + + // use Roger Willcocks bezier flatness criterion +// var tolerance:Number = 4*tol*tol; + + final float ux = 2f * x1 - x0 - x2; + + final float uy = 2f * y1 - y0 - y2; + + if (ux * ux + uy * uy > MAX_FLAT_SQ) { +/* + AGG + float dx = x2 - x0; + float dy = y2 - y0; + final float dist = Math.abs( (x1 - x2) * dy - (y1 - y2) * dx); + // TODO: check collinearity ? +*/ + +// if (level == 0 || dist * dist > MAX_FLAT_SQ * (dx * dx + dy * dy)) { +// if (ptSegDistSq(x0, y0, x2, y2, x1, y1) > MAX_FLAT_SQ) { + final float cx01 = (x0 + x1) / 2.0f; + final float cx12 = (x1 + x2) / 2.0f; + final float cx012 = (cx01 + cx12) / 2.0f; + + final float cy01 = (y0 + y1) / 2.0f; + final float cy12 = (y1 + y2) / 2.0f; + final float cy012 = (cy01 + cy12) / 2.0f; + + subdivideQuad(level + 1, x0, y0, cx01, cy01, cx012, cy012); + subdivideQuad(level + 1, cx012, cy012, cx12, cy12, x2, y2); + return; + } + } + + addLine(x0, y0, x2, y2); + } + + public static float ptSegDistSq(float x1, float y1, + float x2, float y2, + float px, float py) + { + // Adjust vectors relative to x1,y1 + // x2,y2 becomes relative vector from x1,y1 to end of segment + x2 -= x1; + y2 -= y1; + // px,py becomes relative vector from x1,y1 to test point + px -= x1; + py -= y1; + float dotprod = px * x2 + py * y2; + float projlenSq; + if (dotprod <= 0f) { + // px,py is on the side of x1,y1 away from x2,y2 + // distance to segment is length of px,py vector + // "length of its (clipped) projection" is now 0.0 + projlenSq = 0f; + } else { + // switch to backwards vectors relative to x2,y2 + // x2,y2 are already the negative of x1,y1=>x2,y2 + // to get px,py to be the negative of px,py=>x2,y2 + // the dot product of two negated vectors is the same + // as the dot product of the two normal vectors + px = x2 - px; + py = y2 - py; + dotprod = px * x2 + py * y2; + if (dotprod <= 0f) { + // px,py is on the side of x2,y2 away from x1,y1 + // distance to segment is length of (backwards) px,py vector + // "length of its (clipped) projection" is now 0.0 + projlenSq = 0f; + } else { + // px,py is between x1,y1 and x2,y2 + // dotprod is the length of the px,py vector + // projected on the x2,y2=>x1,y1 vector times the + // length of the x2,y2=>x1,y1 vector + projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2); + } + } + // Distance to line is now the length of the relative point + // vector minus the length of its projection onto the line + // (which is zero if the projection falls outside the range + // of the line segment). + float lenSq = px * px + py * py - projlenSq; + if (lenSq < 0f) { + lenSq = 0f; + } + return lenSq; + } + @Override public void closePath() { addLine(x0, y0, sx0, sy0);