63 MarlinRenderer.WIND_EVEN_ODD : MarlinRenderer.WIND_NON_ZERO;
64
65 // We use strokerat so that in Stroker and Dasher we can work only
66 // with the pre-transformation coordinates. This will repeat a lot of
67 // computations done in the path iterator, but the alternative is to
68 // work with transformed paths and compute untransformed coordinates
69 // as needed. This would be faster but I do not think the complexity
70 // of working with both untransformed and transformed coordinates in
71 // the same code is worth it.
72 // However, if a path's width is constant after a transformation,
73 // we can skip all this untransforming.
74
75 // As pathTo() will check transformed coordinates for invalid values
76 // (NaN / Infinity) to ignore such points, it is necessary to apply the
77 // transformation before the path processing.
78 BaseTransform strokerTx = null;
79
80 int dashLen = -1;
81 boolean recycleDashes = false;
82
83 float width = 0f, dashphase = 0f;
84 float[] dashes = null;
85
86 if (stroke != null) {
87 width = stroke.getLineWidth();
88 dashes = stroke.getDashArray();
89 dashphase = stroke.getDashPhase();
90
91 if (tx != null && !tx.isIdentity()) {
92 final double a = tx.getMxx();
93 final double b = tx.getMxy();
94 final double c = tx.getMyx();
95 final double d = tx.getMyy();
96
97 // If the transform is a constant multiple of an orthogonal transformation
98 // then every length is just multiplied by a constant, so we just
99 // need to transform input paths to stroker and tell stroker
100 // the scaled width. This condition is satisfied if
101 // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
102 // leave a bit of room for error.
103 if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
160 }
161
162 pc = transformerPC2D.inverseDeltaTransformConsumer(pc, strokerTx);
163
164 /*
165 * Pipeline seems to be:
166 * shape.getPathIterator(tx)
167 * -> (inverseDeltaTransformConsumer)
168 * -> (Dasher)
169 * -> Stroker
170 * -> (deltaTransformConsumer)
171 *
172 * -> (CollinearSimplifier) to remove redundant segments
173 *
174 * -> pc2d = Renderer (bounding box)
175 */
176 return pc;
177 }
178
179 private static boolean nearZero(final double num) {
180 return Math.abs(num) < 2.0 * Math.ulp(num);
181 }
182
183 public static MarlinRenderer setupRenderer(
184 final RendererContext rdrCtx,
185 final Shape shape,
186 final BasicStroke stroke,
187 final BaseTransform xform,
188 final Rectangle rclip,
189 final boolean antialiasedShape)
190 {
191 // Test if transform is identity:
192 final BaseTransform tf = (xform != null && !xform.isIdentity()) ? xform : null;
193
194 final PathIterator pi = shape.getPathIterator(tf);
195
196 final MarlinRenderer r = (!FORCE_NO_AA && antialiasedShape) ?
197 rdrCtx.renderer : rdrCtx.getRendererNoAA();
198
199 final PathConsumer2D pc2d = initRenderer(rdrCtx, stroke, tf, rclip, pi.getWindingRule(), r);
200
|
63 MarlinRenderer.WIND_EVEN_ODD : MarlinRenderer.WIND_NON_ZERO;
64
65 // We use strokerat so that in Stroker and Dasher we can work only
66 // with the pre-transformation coordinates. This will repeat a lot of
67 // computations done in the path iterator, but the alternative is to
68 // work with transformed paths and compute untransformed coordinates
69 // as needed. This would be faster but I do not think the complexity
70 // of working with both untransformed and transformed coordinates in
71 // the same code is worth it.
72 // However, if a path's width is constant after a transformation,
73 // we can skip all this untransforming.
74
75 // As pathTo() will check transformed coordinates for invalid values
76 // (NaN / Infinity) to ignore such points, it is necessary to apply the
77 // transformation before the path processing.
78 BaseTransform strokerTx = null;
79
80 int dashLen = -1;
81 boolean recycleDashes = false;
82
83 float width = 0.0f, dashphase = 0.0f;
84 float[] dashes = null;
85
86 if (stroke != null) {
87 width = stroke.getLineWidth();
88 dashes = stroke.getDashArray();
89 dashphase = stroke.getDashPhase();
90
91 if (tx != null && !tx.isIdentity()) {
92 final double a = tx.getMxx();
93 final double b = tx.getMxy();
94 final double c = tx.getMyx();
95 final double d = tx.getMyy();
96
97 // If the transform is a constant multiple of an orthogonal transformation
98 // then every length is just multiplied by a constant, so we just
99 // need to transform input paths to stroker and tell stroker
100 // the scaled width. This condition is satisfied if
101 // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
102 // leave a bit of room for error.
103 if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
160 }
161
162 pc = transformerPC2D.inverseDeltaTransformConsumer(pc, strokerTx);
163
164 /*
165 * Pipeline seems to be:
166 * shape.getPathIterator(tx)
167 * -> (inverseDeltaTransformConsumer)
168 * -> (Dasher)
169 * -> Stroker
170 * -> (deltaTransformConsumer)
171 *
172 * -> (CollinearSimplifier) to remove redundant segments
173 *
174 * -> pc2d = Renderer (bounding box)
175 */
176 return pc;
177 }
178
179 private static boolean nearZero(final double num) {
180 return Math.abs(num) < 2.0d * Math.ulp(num);
181 }
182
183 public static MarlinRenderer setupRenderer(
184 final RendererContext rdrCtx,
185 final Shape shape,
186 final BasicStroke stroke,
187 final BaseTransform xform,
188 final Rectangle rclip,
189 final boolean antialiasedShape)
190 {
191 // Test if transform is identity:
192 final BaseTransform tf = (xform != null && !xform.isIdentity()) ? xform : null;
193
194 final PathIterator pi = shape.getPathIterator(tf);
195
196 final MarlinRenderer r = (!FORCE_NO_AA && antialiasedShape) ?
197 rdrCtx.renderer : rdrCtx.getRendererNoAA();
198
199 final PathConsumer2D pc2d = initRenderer(rdrCtx, stroke, tf, rclip, pi.getWindingRule(), r);
200
|