137 * <code>CAP_SQUARE</code>. |
137 * <code>CAP_SQUARE</code>. |
138 * @param joinStyle the desired line join style, one of |
138 * @param joinStyle the desired line join style, one of |
139 * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or |
139 * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or |
140 * <code>JOIN_BEVEL</code>. |
140 * <code>JOIN_BEVEL</code>. |
141 * @param miterLimit the desired miter limit |
141 * @param miterLimit the desired miter limit |
142 * @param scale scaling factor applied to clip boundaries |
|
143 * @param subdivideCurves true to indicate to subdivide curves, false if dasher does |
142 * @param subdivideCurves true to indicate to subdivide curves, false if dasher does |
144 * @return this instance |
143 * @return this instance |
145 */ |
144 */ |
146 DStroker init(final DPathConsumer2D pc2d, |
145 DStroker init(final DPathConsumer2D pc2d, |
147 final double lineWidth, |
146 final double lineWidth, |
148 final int capStyle, |
147 final int capStyle, |
149 final int joinStyle, |
148 final int joinStyle, |
150 final double miterLimit, |
149 final double miterLimit, |
151 final double scale, |
|
152 final boolean subdivideCurves) |
150 final boolean subdivideCurves) |
153 { |
151 { |
154 this.out = pc2d; |
152 this.out = pc2d; |
155 |
153 |
156 this.lineWidth2 = lineWidth / 2.0d; |
154 this.lineWidth2 = lineWidth / 2.0d; |
167 |
165 |
168 rdrCtx.stroking = 1; |
166 rdrCtx.stroking = 1; |
169 |
167 |
170 if (rdrCtx.doClip) { |
168 if (rdrCtx.doClip) { |
171 // Adjust the clipping rectangle with the stroker margin (miter limit, width) |
169 // Adjust the clipping rectangle with the stroker margin (miter limit, width) |
172 double rdrOffX = 0.0d, rdrOffY = 0.0d; |
|
173 double margin = lineWidth2; |
170 double margin = lineWidth2; |
174 |
171 |
175 if (capStyle == CAP_SQUARE) { |
172 if (capStyle == CAP_SQUARE) { |
176 margin *= SQRT_2; |
173 margin *= SQRT_2; |
177 } |
174 } |
178 if ((joinStyle == JOIN_MITER) && (margin < limit)) { |
175 if ((joinStyle == JOIN_MITER) && (margin < limit)) { |
179 margin = limit; |
176 margin = limit; |
180 } |
177 } |
181 if (scale != 1.0d) { |
|
182 margin *= scale; |
|
183 rdrOffX = scale * DRenderer.RDR_OFFSET_X; |
|
184 rdrOffY = scale * DRenderer.RDR_OFFSET_Y; |
|
185 } |
|
186 // add a small rounding error: |
|
187 margin += 1e-3d; |
|
188 |
178 |
189 // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY |
179 // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY |
190 // adjust clip rectangle (ymin, ymax, xmin, xmax): |
180 // adjust clip rectangle (ymin, ymax, xmin, xmax): |
191 final double[] _clipRect = rdrCtx.clipRect; |
181 final double[] _clipRect = rdrCtx.clipRect; |
192 _clipRect[0] -= margin - rdrOffY; |
182 _clipRect[0] -= margin; |
193 _clipRect[1] += margin + rdrOffY; |
183 _clipRect[1] += margin; |
194 _clipRect[2] -= margin - rdrOffX; |
184 _clipRect[2] -= margin; |
195 _clipRect[3] += margin + rdrOffX; |
185 _clipRect[3] += margin; |
196 this.clipRect = _clipRect; |
186 this.clipRect = _clipRect; |
|
187 |
|
188 if (MarlinConst.DO_LOG_CLIP) { |
|
189 MarlinUtils.logInfo("clipRect (stroker): " |
|
190 + Arrays.toString(rdrCtx.clipRect)); |
|
191 } |
197 |
192 |
198 // initialize curve splitter here for stroker & dasher: |
193 // initialize curve splitter here for stroker & dasher: |
199 if (DO_CLIP_SUBDIVIDER) { |
194 if (DO_CLIP_SUBDIVIDER) { |
200 subdivide = subdivideCurves; |
195 subdivide = subdivideCurves; |
201 // adjust padded clip rectangle: |
196 // adjust padded clip rectangle: |
302 // (ext is the angle between omx,omy and mx,my). |
297 // (ext is the angle between omx,omy and mx,my). |
303 final double cosext = omx * mx + omy * my; |
298 final double cosext = omx * mx + omy * my; |
304 // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only |
299 // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only |
305 // need 1 curve to approximate the circle section that joins omx,omy |
300 // need 1 curve to approximate the circle section that joins omx,omy |
306 // and mx,my. |
301 // and mx,my. |
307 final int numCurves = (cosext >= 0.0d) ? 1 : 2; |
302 if (cosext >= 0.0d) { |
308 |
|
309 switch (numCurves) { |
|
310 case 1: |
|
311 drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev); |
303 drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev); |
312 break; |
304 } else { |
313 case 2: |
|
314 // we need to split the arc into 2 arcs spanning the same angle. |
305 // we need to split the arc into 2 arcs spanning the same angle. |
315 // The point we want will be one of the 2 intersections of the |
306 // The point we want will be one of the 2 intersections of the |
316 // perpendicular bisector of the chord (omx,omy)->(mx,my) and the |
307 // perpendicular bisector of the chord (omx,omy)->(mx,my) and the |
317 // circle. We could find this by scaling the vector |
308 // circle. We could find this by scaling the vector |
318 // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies |
309 // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies |
337 mmx = -mmx; |
328 mmx = -mmx; |
338 mmy = -mmy; |
329 mmy = -mmy; |
339 } |
330 } |
340 drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev); |
331 drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev); |
341 drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev); |
332 drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev); |
342 break; |
|
343 default: |
|
344 } |
333 } |
345 } |
334 } |
346 |
335 |
347 // the input arc defined by omx,omy and mx,my must span <= 90 degrees. |
336 // the input arc defined by omx,omy and mx,my must span <= 90 degrees. |
348 private void drawBezApproxForArc(final double cx, final double cy, |
337 private void drawBezApproxForArc(final double cx, final double cy, |