< prev index next >

modules/javafx.graphics/src/main/java/com/sun/marlin/DTransformingPathConsumer2D.java

Print this page




  80     public DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
  81         return tracerCPDetector.init(out);
  82     }
  83 
  84     public DPathConsumer2D traceFiller(DPathConsumer2D out) {
  85         return tracerFiller.init(out);
  86     }
  87 
  88     public DPathConsumer2D traceStroker(DPathConsumer2D out) {
  89         return tracerStroker.init(out);
  90     }
  91 
  92     public DPathConsumer2D traceDasher(DPathConsumer2D out) {
  93         return tracerDasher.init(out);
  94     }
  95 
  96     public DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
  97         return cpDetector.init(out);
  98     }
  99 
 100     public DPathConsumer2D pathClipper(DPathConsumer2D out,
 101                                        final double rdrOffX,
 102                                        final double rdrOffY)
 103     {
 104         return pathClipper.init(out, rdrOffX, rdrOffY);
 105     }
 106 
 107     public DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
 108                                                   BaseTransform at,
 109                                                   final double rdrOffX,
 110                                                   final double rdrOffY)
 111     {
 112         if (at == null) {
 113             return out;
 114         }
 115         final double mxx = at.getMxx();
 116         final double mxy = at.getMxy();
 117         final double myx = at.getMyx();
 118         final double myy = at.getMyy();
 119 
 120         if (mxy == 0.0d && myx == 0.0d) {
 121             if (mxx == 1.0d && myy == 1.0d) {
 122                 return out;
 123             } else {
 124                 // Scale only
 125                 if (rdrCtx.doClip) {
 126                     // adjust clip rectangle (ymin, ymax, xmin, xmax):
 127                     adjustClipOffset(rdrCtx.clipRect, rdrOffX, rdrOffY);
 128                     adjustClipScale(rdrCtx.clipRect, mxx, myy);
 129                 }
 130                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 131             }
 132         } else {
 133             if (rdrCtx.doClip) {
 134                 // adjust clip rectangle (ymin, ymax, xmin, xmax):
 135                 adjustClipOffset(rdrCtx.clipRect, rdrOffX, rdrOffY);
 136                 adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
 137             }
 138             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 139         }
 140     }
 141 
 142     private static void adjustClipOffset(final double[] clipRect,
 143                                          final double rdrOffX,
 144                                          final double rdrOffY)
 145     {
 146         clipRect[0] += rdrOffY;
 147         clipRect[1] += rdrOffY;
 148         clipRect[2] += rdrOffX;
 149         clipRect[3] += rdrOffX;
 150     }
 151 
 152     private static void adjustClipScale(final double[] clipRect,
 153                                         final double mxx, final double myy)
 154     {
 155         // Adjust the clipping rectangle (iv_DeltaScaleFilter):
 156         clipRect[0] /= myy;
 157         clipRect[1] /= myy;
 158         clipRect[2] /= mxx;
 159         clipRect[3] /= mxx;




 160     }
 161 
 162     private static void adjustClipInverseDelta(final double[] clipRect,

















 163                                                final double mxx, final double mxy,
 164                                                final double myx, final double myy)
 165     {
 166         // Adjust the clipping rectangle (iv_DeltaTransformFilter):
 167         final double det = mxx * myy - mxy * myx;
 168         final double imxx =  myy / det;
 169         final double imxy = -mxy / det;
 170         final double imyx = -myx / det;
 171         final double imyy =  mxx / det;
 172 
 173         double xmin, xmax, ymin, ymax;
 174         double x, y;
 175         // xmin, ymin:
 176         x = clipRect[2] * imxx + clipRect[0] * imxy;
 177         y = clipRect[2] * imyx + clipRect[0] * imyy;
 178 
 179         xmin = xmax = x;
 180         ymin = ymax = y;
 181 
 182         // xmax, ymin:


 187         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 188 
 189         // xmin, ymax:
 190         x = clipRect[2] * imxx + clipRect[1] * imxy;
 191         y = clipRect[2] * imyx + clipRect[1] * imyy;
 192 
 193         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 194         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 195 
 196         // xmax, ymax:
 197         x = clipRect[3] * imxx + clipRect[1] * imxy;
 198         y = clipRect[3] * imyx + clipRect[1] * imyy;
 199 
 200         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 201         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 202 
 203         clipRect[0] = ymin;
 204         clipRect[1] = ymax;
 205         clipRect[2] = xmin;
 206         clipRect[3] = xmax;










 207     }
 208 
 209     public DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
 210                                                         BaseTransform at)
 211     {
 212         if (at == null) {
 213             return out;
 214         }
 215         double mxx = at.getMxx();
 216         double mxy = at.getMxy();
 217         double myx = at.getMyx();
 218         double myy = at.getMyy();
 219 
 220         if (mxy == 0.0d && myx == 0.0d) {
 221             if (mxx == 1.0d && myy == 1.0d) {
 222                 return out;
 223             } else {
 224                 return iv_DeltaScaleFilter.init(out, 1.0d/mxx, 1.0d/myy);
 225             }
 226         } else {
 227             final double det = mxx * myy - mxy * myx;
 228             return iv_DeltaTransformFilter.init(out,
 229                                                 myy / det,
 230                                                -mxy / det,
 231                                                -myx / det,
 232                                                 mxx / det);
 233         }
 234     }
 235 
 236     static final class DeltaScaleFilter implements DPathConsumer2D {
 237         private DPathConsumer2D out;
 238         private double sx, sy;
 239 
 240         DeltaScaleFilter() {}
 241 
 242         DeltaScaleFilter init(DPathConsumer2D out,
 243                               double mxx, double myy)
 244         {


 499         private double cx0, cy0;
 500 
 501         // The current point OUTSIDE
 502         private double cox0, coy0;
 503 
 504         private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
 505         private final CurveClipSplitter curveSplitter;
 506 
 507         PathClipFilter(final DRendererContext rdrCtx) {
 508             this.clipRect = rdrCtx.clipRect;
 509             this.curveSplitter = rdrCtx.curveClipSplitter;
 510 
 511             this.stack = (rdrCtx.stats != null) ?
 512                 new IndexStack(rdrCtx,
 513                         rdrCtx.stats.stat_pcf_idxstack_indices,
 514                         rdrCtx.stats.hist_pcf_idxstack_indices,
 515                         rdrCtx.stats.stat_array_pcf_idxstack_indices)
 516                 : new IndexStack(rdrCtx);
 517         }
 518 
 519         PathClipFilter init(final DPathConsumer2D out,
 520                             final double rdrOffX,
 521                             final double rdrOffY)
 522         {
 523             this.out = out;
 524 
 525             // add a small rounding error:
 526             final double margin = 1e-3d;
 527 
 528             final double[] _clipRect = this.clipRect;
 529             // Adjust the clipping rectangle with the renderer offsets
 530             _clipRect[0] -= margin - rdrOffY;
 531             _clipRect[1] += margin + rdrOffY;
 532             _clipRect[2] -= margin - rdrOffX;
 533             _clipRect[3] += margin + rdrOffX;
 534 
 535             if (MarlinConst.DO_CLIP_SUBDIVIDER) {
 536                 // adjust padded clip rectangle:
 537                 curveSplitter.init();
 538             }
 539 
 540             this.init_corners = true;
 541             this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
 542 
 543             return this; // fluent API
 544         }
 545 
 546         /**
 547          * Disposes this instance:
 548          * clean up before reusing this instance
 549          */
 550         void dispose() {
 551             stack.dispose();
 552         }
 553 
 554         private void finishPath() {


 832 
 833             if (outside) {
 834                 finish();
 835             }
 836             // clipping disabled:
 837             out.quadTo(x1, y1, xe, ye);
 838             this.cx0 = xe;
 839             this.cy0 = ye;
 840         }
 841     }
 842 
 843     static final class CurveClipSplitter {
 844 
 845         static final double LEN_TH = MarlinProperties.getSubdividerMinLength();
 846         static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0d);
 847 
 848         private static final boolean TRACE = false;
 849 
 850         private static final int MAX_N_CURVES = 3 * 4;
 851 





 852         // clip rectangle (ymin, ymax, xmin, xmax):
 853         final double[] clipRect;
 854 
 855         // clip rectangle (ymin, ymax, xmin, xmax) including padding:
 856         final double[] clipRectPad = new double[4];
 857         private boolean init_clipRectPad = false;
 858 
 859         // This is where the curve to be processed is put. We give it
 860         // enough room to store all curves.
 861         final double[] middle = new double[MAX_N_CURVES * 8 + 2];
 862         // t values at subdivision points
 863         private final double[] subdivTs = new double[MAX_N_CURVES];
 864 
 865         // dirty curve
 866         private final DCurve curve;
 867 
 868         CurveClipSplitter(final DRendererContext rdrCtx) {

 869             this.clipRect = rdrCtx.clipRect;
 870             this.curve = rdrCtx.curve;
 871         }
 872 
 873         void init() {
 874             this.init_clipRectPad = true;










 875         }
 876 
 877         private void initPaddedClip() {
 878             // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
 879             // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
 880             // add a rounding error (curve subdivision ~ 0.1px):
 881             final double[] _clipRect = clipRect;
 882             final double[] _clipRectPad = clipRectPad;
 883 
 884             _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
 885             _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
 886             _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
 887             _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
 888 
 889             if (TRACE) {
 890                 MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
 891                                         + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
 892             }
 893         }
 894 
 895         boolean splitLine(final double x0, final double y0,
 896                           final double x1, final double y1,
 897                           final int outCodeOR,
 898                           final DPathConsumer2D out)
 899         {
 900             if (TRACE) {
 901                 MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
 902             }
 903 
 904             if (DO_CHECK_LENGTH && DHelpers.fastLineLen(x0, y0, x1, y1) <= LEN_TH) {
 905                 return false;
 906             }
 907 
 908             final double[] mid = middle;
 909             mid[0] = x0;  mid[1] = y0;
 910             mid[2] = x1;  mid[3] = y1;
 911 
 912             return subdivideAtIntersections(4, outCodeOR, out);
 913         }
 914 
 915         boolean splitQuad(final double x0, final double y0,
 916                           final double x1, final double y1,
 917                           final double x2, final double y2,
 918                           final int outCodeOR,
 919                           final DPathConsumer2D out)
 920         {
 921             if (TRACE) {
 922                 MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
 923             }
 924 
 925             if (DO_CHECK_LENGTH && DHelpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= LEN_TH) {
 926                 return false;
 927             }
 928 
 929             final double[] mid = middle;
 930             mid[0] = x0;  mid[1] = y0;
 931             mid[2] = x1;  mid[3] = y1;
 932             mid[4] = x2;  mid[5] = y2;
 933 
 934             return subdivideAtIntersections(6, outCodeOR, out);
 935         }
 936 
 937         boolean splitCurve(final double x0, final double y0,
 938                            final double x1, final double y1,
 939                            final double x2, final double y2,
 940                            final double x3, final double y3,
 941                            final int outCodeOR,
 942                            final DPathConsumer2D out)
 943         {
 944             if (TRACE) {
 945                 MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
 946             }
 947 
 948             if (DO_CHECK_LENGTH && DHelpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= LEN_TH) {
 949                 return false;
 950             }
 951 
 952             final double[] mid = middle;
 953             mid[0] = x0;  mid[1] = y0;
 954             mid[2] = x1;  mid[3] = y1;
 955             mid[4] = x2;  mid[5] = y2;
 956             mid[6] = x3;  mid[7] = y3;
 957 
 958             return subdivideAtIntersections(8, outCodeOR, out);
 959         }
 960 
 961         private boolean subdivideAtIntersections(final int type, final int outCodeOR,
 962                                                  final DPathConsumer2D out)
 963         {
 964             final double[] mid = middle;
 965             final double[] subTs = subdivTs;
 966 
 967             if (init_clipRectPad) {
 968                 init_clipRectPad = false;
 969                 initPaddedClip();
 970             }
 971 
 972             final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
 973                                                         outCodeOR, clipRectPad);
 974 
 975             if (TRACE) {
 976                 MarlinUtils.logInfo("nSplits: "+ nSplits);
 977                 MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
 978             }
 979             if (nSplits == 0) {
 980                 // only curve support shortcut
 981                 return false;
 982             }
 983             double prevT = 0.0d;
 984 
 985             for (int i = 0, off = 0; i < nSplits; i++, off += type) {
 986                 final double t = subTs[i];
 987 
 988                 DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
 989                                      mid, off, mid, off, type);
 990                 prevT = t;
 991             }
 992 
 993             for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
 994                 if (TRACE) {
 995                     MarlinUtils.logInfo("Part Curve " + Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
 996                 }




  80     public DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
  81         return tracerCPDetector.init(out);
  82     }
  83 
  84     public DPathConsumer2D traceFiller(DPathConsumer2D out) {
  85         return tracerFiller.init(out);
  86     }
  87 
  88     public DPathConsumer2D traceStroker(DPathConsumer2D out) {
  89         return tracerStroker.init(out);
  90     }
  91 
  92     public DPathConsumer2D traceDasher(DPathConsumer2D out) {
  93         return tracerDasher.init(out);
  94     }
  95 
  96     public DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
  97         return cpDetector.init(out);
  98     }
  99 
 100     public DPathConsumer2D pathClipper(DPathConsumer2D out)


 101     {
 102         return pathClipper.init(out);
 103     }
 104 
 105     public DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
 106                                                   BaseTransform at)


 107     {
 108         if (at == null) {
 109             return out;
 110         }
 111         final double mxx = at.getMxx();
 112         final double mxy = at.getMxy();
 113         final double myx = at.getMyx();
 114         final double myy = at.getMyy();
 115 
 116         if (mxy == 0.0d && myx == 0.0d) {
 117             if (mxx == 1.0d && myy == 1.0d) {
 118                 return out;
 119             } else {
 120                 // Scale only
 121                 if (rdrCtx.doClip) {
 122                     // adjust clip rectangle (ymin, ymax, xmin, xmax):
 123                     rdrCtx.clipInvScale = adjustClipScale(rdrCtx.clipRect,
 124                         mxx, myy);
 125                 }
 126                 return dt_DeltaScaleFilter.init(out, mxx, myy);
 127             }
 128         } else {
 129             if (rdrCtx.doClip) {
 130                 // adjust clip rectangle (ymin, ymax, xmin, xmax):
 131                 rdrCtx.clipInvScale = adjustClipInverseDelta(rdrCtx.clipRect,
 132                     mxx, mxy, myx, myy);
 133             }
 134             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
 135         }
 136     }
 137 
 138     private static double adjustClipScale(final double[] clipRect,










 139                                           final double mxx, final double myy)
 140     {
 141         // Adjust the clipping rectangle (iv_DeltaScaleFilter):
 142         final double scaleY = 1.0d / myy;
 143         clipRect[0] *= scaleY;
 144         clipRect[1] *= scaleY;
 145 
 146         if (clipRect[1] < clipRect[0]) {
 147             double tmp = clipRect[0];
 148             clipRect[0] = clipRect[1];
 149             clipRect[1] = tmp;
 150         }
 151 
 152         final double scaleX = 1.0d / mxx;
 153         clipRect[2] *= scaleX;
 154         clipRect[3] *= scaleX;
 155 
 156         if (clipRect[3] < clipRect[2]) {
 157             double tmp = clipRect[2];
 158             clipRect[2] = clipRect[3];
 159             clipRect[3] = tmp;
 160         }
 161 
 162         if (MarlinConst.DO_LOG_CLIP) {
 163                 MarlinUtils.logInfo("clipRect (ClipScale): "
 164                                     + Arrays.toString(clipRect));
 165         }
 166         return 0.5d * (Math.abs(scaleX) + Math.abs(scaleY));
 167     }
 168 
 169     private static double adjustClipInverseDelta(final double[] clipRect,
 170                                                  final double mxx, final double mxy,
 171                                                  final double myx, final double myy)
 172     {
 173         // Adjust the clipping rectangle (iv_DeltaTransformFilter):
 174         final double det = mxx * myy - mxy * myx;
 175         final double imxx =  myy / det;
 176         final double imxy = -mxy / det;
 177         final double imyx = -myx / det;
 178         final double imyy =  mxx / det;
 179 
 180         double xmin, xmax, ymin, ymax;
 181         double x, y;
 182         // xmin, ymin:
 183         x = clipRect[2] * imxx + clipRect[0] * imxy;
 184         y = clipRect[2] * imyx + clipRect[0] * imyy;
 185 
 186         xmin = xmax = x;
 187         ymin = ymax = y;
 188 
 189         // xmax, ymin:


 194         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 195 
 196         // xmin, ymax:
 197         x = clipRect[2] * imxx + clipRect[1] * imxy;
 198         y = clipRect[2] * imyx + clipRect[1] * imyy;
 199 
 200         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 201         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 202 
 203         // xmax, ymax:
 204         x = clipRect[3] * imxx + clipRect[1] * imxy;
 205         y = clipRect[3] * imyx + clipRect[1] * imyy;
 206 
 207         if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
 208         if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
 209 
 210         clipRect[0] = ymin;
 211         clipRect[1] = ymax;
 212         clipRect[2] = xmin;
 213         clipRect[3] = xmax;
 214 
 215         if (MarlinConst.DO_LOG_CLIP) {
 216                 MarlinUtils.logInfo("clipRect (ClipInverseDelta): "
 217                                     + Arrays.toString(clipRect));
 218         }
 219 
 220         final double scaleX = Math.sqrt(imxx * imxx + imxy * imxy);
 221         final double scaleY = Math.sqrt(imyx * imyx + imyy * imyy);
 222 
 223         return 0.5d * (scaleX + scaleY);
 224     }
 225 
 226     public DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
 227                                                         BaseTransform at)
 228     {
 229         if (at == null) {
 230             return out;
 231         }
 232         double mxx = at.getMxx();
 233         double mxy = at.getMxy();
 234         double myx = at.getMyx();
 235         double myy = at.getMyy();
 236 
 237         if (mxy == 0.0d && myx == 0.0d) {
 238             if (mxx == 1.0d && myy == 1.0d) {
 239                 return out;
 240             } else {
 241                 return iv_DeltaScaleFilter.init(out, 1.0d / mxx, 1.0d / myy);
 242             }
 243         } else {
 244             final double det = mxx * myy - mxy * myx;
 245             return iv_DeltaTransformFilter.init(out,
 246                                                 myy / det,
 247                                                -mxy / det,
 248                                                -myx / det,
 249                                                 mxx / det);
 250         }
 251     }
 252 
 253     static final class DeltaScaleFilter implements DPathConsumer2D {
 254         private DPathConsumer2D out;
 255         private double sx, sy;
 256 
 257         DeltaScaleFilter() {}
 258 
 259         DeltaScaleFilter init(DPathConsumer2D out,
 260                               double mxx, double myy)
 261         {


 516         private double cx0, cy0;
 517 
 518         // The current point OUTSIDE
 519         private double cox0, coy0;
 520 
 521         private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
 522         private final CurveClipSplitter curveSplitter;
 523 
 524         PathClipFilter(final DRendererContext rdrCtx) {
 525             this.clipRect = rdrCtx.clipRect;
 526             this.curveSplitter = rdrCtx.curveClipSplitter;
 527 
 528             this.stack = (rdrCtx.stats != null) ?
 529                 new IndexStack(rdrCtx,
 530                         rdrCtx.stats.stat_pcf_idxstack_indices,
 531                         rdrCtx.stats.hist_pcf_idxstack_indices,
 532                         rdrCtx.stats.stat_array_pcf_idxstack_indices)
 533                 : new IndexStack(rdrCtx);
 534         }
 535 
 536         PathClipFilter init(final DPathConsumer2D out) {



 537             this.out = out;
 538 










 539             if (MarlinConst.DO_CLIP_SUBDIVIDER) {
 540                 // adjust padded clip rectangle:
 541                 curveSplitter.init();
 542             }
 543 
 544             this.init_corners = true;
 545             this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
 546 
 547             return this; // fluent API
 548         }
 549 
 550         /**
 551          * Disposes this instance:
 552          * clean up before reusing this instance
 553          */
 554         void dispose() {
 555             stack.dispose();
 556         }
 557 
 558         private void finishPath() {


 836 
 837             if (outside) {
 838                 finish();
 839             }
 840             // clipping disabled:
 841             out.quadTo(x1, y1, xe, ye);
 842             this.cx0 = xe;
 843             this.cy0 = ye;
 844         }
 845     }
 846 
 847     static final class CurveClipSplitter {
 848 
 849         static final double LEN_TH = MarlinProperties.getSubdividerMinLength();
 850         static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0d);
 851 
 852         private static final boolean TRACE = false;
 853 
 854         private static final int MAX_N_CURVES = 3 * 4;
 855 
 856         private final DRendererContext rdrCtx;
 857 
 858         // scaled length threshold:
 859         private double minLength;
 860 
 861         // clip rectangle (ymin, ymax, xmin, xmax):
 862         final double[] clipRect;
 863 
 864         // clip rectangle (ymin, ymax, xmin, xmax) including padding:
 865         final double[] clipRectPad = new double[4];
 866         private boolean init_clipRectPad = false;
 867 
 868         // This is where the curve to be processed is put. We give it
 869         // enough room to store all curves.
 870         final double[] middle = new double[MAX_N_CURVES * 8 + 2];
 871         // t values at subdivision points
 872         private final double[] subdivTs = new double[MAX_N_CURVES];
 873 
 874         // dirty curve
 875         private final DCurve curve;
 876 
 877         CurveClipSplitter(final DRendererContext rdrCtx) {
 878             this.rdrCtx = rdrCtx;
 879             this.clipRect = rdrCtx.clipRect;
 880             this.curve = rdrCtx.curve;
 881         }
 882 
 883         void init() {
 884             this.init_clipRectPad = true;
 885 
 886             if (DO_CHECK_LENGTH) {
 887                 this.minLength = (this.rdrCtx.clipInvScale == 0.0d) ? LEN_TH
 888                                     : (LEN_TH * this.rdrCtx.clipInvScale);
 889 
 890                 if (MarlinConst.DO_LOG_CLIP) {
 891                     MarlinUtils.logInfo("CurveClipSplitter.minLength = "
 892                                             + minLength);
 893                 }
 894             }
 895         }
 896 
 897         private void initPaddedClip() {
 898             // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
 899             // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
 900             // add a rounding error (curve subdivision ~ 0.1px):
 901             final double[] _clipRect = clipRect;
 902             final double[] _clipRectPad = clipRectPad;
 903 
 904             _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
 905             _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
 906             _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
 907             _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
 908 
 909             if (TRACE) {
 910                 MarlinUtils.logInfo("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
 911                                         + "Y [" + _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
 912             }
 913         }
 914 
 915         boolean splitLine(final double x0, final double y0,
 916                           final double x1, final double y1,
 917                           final int outCodeOR,
 918                           final DPathConsumer2D out)
 919         {
 920             if (TRACE) {
 921                 MarlinUtils.logInfo("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
 922             }
 923 
 924             if (DO_CHECK_LENGTH && DHelpers.fastLineLen(x0, y0, x1, y1) <= minLength) {
 925                 return false;
 926             }
 927 
 928             final double[] mid = middle;
 929             mid[0] = x0;  mid[1] = y0;
 930             mid[2] = x1;  mid[3] = y1;
 931 
 932             return subdivideAtIntersections(4, outCodeOR, out);
 933         }
 934 
 935         boolean splitQuad(final double x0, final double y0,
 936                           final double x1, final double y1,
 937                           final double x2, final double y2,
 938                           final int outCodeOR,
 939                           final DPathConsumer2D out)
 940         {
 941             if (TRACE) {
 942                 MarlinUtils.logInfo("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
 943             }
 944 
 945             if (DO_CHECK_LENGTH && DHelpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= minLength) {
 946                 return false;
 947             }
 948 
 949             final double[] mid = middle;
 950             mid[0] = x0;  mid[1] = y0;
 951             mid[2] = x1;  mid[3] = y1;
 952             mid[4] = x2;  mid[5] = y2;
 953 
 954             return subdivideAtIntersections(6, outCodeOR, out);
 955         }
 956 
 957         boolean splitCurve(final double x0, final double y0,
 958                            final double x1, final double y1,
 959                            final double x2, final double y2,
 960                            final double x3, final double y3,
 961                            final int outCodeOR,
 962                            final DPathConsumer2D out)
 963         {
 964             if (TRACE) {
 965                 MarlinUtils.logInfo("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
 966             }
 967 
 968             if (DO_CHECK_LENGTH && DHelpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= minLength) {
 969                 return false;
 970             }
 971 
 972             final double[] mid = middle;
 973             mid[0] = x0;  mid[1] = y0;
 974             mid[2] = x1;  mid[3] = y1;
 975             mid[4] = x2;  mid[5] = y2;
 976             mid[6] = x3;  mid[7] = y3;
 977 
 978             return subdivideAtIntersections(8, outCodeOR, out);
 979         }
 980 
 981         private boolean subdivideAtIntersections(final int type, final int outCodeOR,
 982                                                  final DPathConsumer2D out)
 983         {
 984             final double[] mid = middle;
 985             final double[] subTs = subdivTs;
 986 
 987             if (init_clipRectPad) {
 988                 init_clipRectPad = false;
 989                 initPaddedClip();
 990             }
 991 
 992             final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
 993                                                         outCodeOR, clipRectPad);
 994 
 995             if (TRACE) {
 996                 MarlinUtils.logInfo("nSplits: " + nSplits);
 997                 MarlinUtils.logInfo("subTs: " + Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
 998             }
 999             if (nSplits == 0) {
1000                 // only curve support shortcut
1001                 return false;
1002             }
1003             double prevT = 0.0d;
1004 
1005             for (int i = 0, off = 0; i < nSplits; i++, off += type) {
1006                 final double t = subTs[i];
1007 
1008                 DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
1009                                      mid, off, mid, off, type);
1010                 prevT = t;
1011             }
1012 
1013             for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
1014                 if (TRACE) {
1015                     MarlinUtils.logInfo("Part Curve " + Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
1016                 }


< prev index next >