001 /*
002 * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt;
027
028 /**
029 * The <code>BasicStroke</code> class defines a basic set of rendering
030 * attributes for the outlines of graphics primitives, which are rendered
031 * with a {@link Graphics2D} object that has its Stroke attribute set to
032 * this <code>BasicStroke</code>.
033 * The rendering attributes defined by <code>BasicStroke</code> describe
034 * the shape of the mark made by a pen drawn along the outline of a
035 * {@link Shape} and the decorations applied at the ends and joins of
036 * path segments of the <code>Shape</code>.
037 * These rendering attributes include:
038 * <dl compact>
039 * <dt><i>width</i>
040 * <dd>The pen width, measured perpendicularly to the pen trajectory.
041 * <dt><i>end caps</i>
042 * <dd>The decoration applied to the ends of unclosed subpaths and
043 * dash segments. Subpaths that start and end on the same point are
044 * still considered unclosed if they do not have a CLOSE segment.
045 * See {@link java.awt.geom.PathIterator#SEG_CLOSE SEG_CLOSE}
046 * for more information on the CLOSE segment.
047 * The three different decorations are: {@link #CAP_BUTT},
048 * {@link #CAP_ROUND}, and {@link #CAP_SQUARE}.
049 * <dt><i>line joins</i>
050 * <dd>The decoration applied at the intersection of two path segments
051 * and at the intersection of the endpoints of a subpath that is closed
052 * using {@link java.awt.geom.PathIterator#SEG_CLOSE SEG_CLOSE}.
053 * The three different decorations are: {@link #JOIN_BEVEL},
054 * {@link #JOIN_MITER}, and {@link #JOIN_ROUND}.
055 * <dt><i>miter limit</i>
056 * <dd>The limit to trim a line join that has a JOIN_MITER decoration.
057 * A line join is trimmed when the ratio of miter length to stroke
058 * width is greater than the miterlimit value. The miter length is
059 * the diagonal length of the miter, which is the distance between
060 * the inside corner and the outside corner of the intersection.
061 * The smaller the angle formed by two line segments, the longer
062 * the miter length and the sharper the angle of intersection. The
063 * default miterlimit value of 10.0f causes all angles less than
064 * 11 degrees to be trimmed. Trimming miters converts
065 * the decoration of the line join to bevel.
066 * <dt><i>dash attributes</i>
067 * <dd>The definition of how to make a dash pattern by alternating
068 * between opaque and transparent sections.
069 * </dl>
070 * All attributes that specify measurements and distances controlling
071 * the shape of the returned outline are measured in the same
072 * coordinate system as the original unstroked <code>Shape</code>
073 * argument. When a <code>Graphics2D</code> object uses a
074 * <code>Stroke</code> object to redefine a path during the execution
075 * of one of its <code>draw</code> methods, the geometry is supplied
076 * in its original form before the <code>Graphics2D</code> transform
077 * attribute is applied. Therefore, attributes such as the pen width
078 * are interpreted in the user space coordinate system of the
079 * <code>Graphics2D</code> object and are subject to the scaling and
080 * shearing effects of the user-space-to-device-space transform in that
081 * particular <code>Graphics2D</code>.
082 * For example, the width of a rendered shape's outline is determined
083 * not only by the width attribute of this <code>BasicStroke</code>,
084 * but also by the transform attribute of the
085 * <code>Graphics2D</code> object. Consider this code:
086 * <blockquote><tt>
087 * // sets the Graphics2D object's Tranform attribute
088 * g2d.scale(10, 10);
089 * // sets the Graphics2D object's Stroke attribute
090 * g2d.setStroke(new BasicStroke(1.5f));
091 * </tt></blockquote>
092 * Assuming there are no other scaling transforms added to the
093 * <code>Graphics2D</code> object, the resulting line
094 * will be approximately 15 pixels wide.
095 * As the example code demonstrates, a floating-point line
096 * offers better precision, especially when large transforms are
097 * used with a <code>Graphics2D</code> object.
098 * When a line is diagonal, the exact width depends on how the
099 * rendering pipeline chooses which pixels to fill as it traces the
100 * theoretical widened outline. The choice of which pixels to turn
101 * on is affected by the antialiasing attribute because the
102 * antialiasing rendering pipeline can choose to color
103 * partially-covered pixels.
104 * <p>
105 * For more information on the user space coordinate system and the
106 * rendering process, see the <code>Graphics2D</code> class comments.
107 * @see Graphics2D
108 * @version 1.50, 06/08/07
109 * @author Jim Graham
110 */
111 public class BasicStroke implements Stroke {
112
113 /**
114 * Joins path segments by extending their outside edges until
115 * they meet.
116 */
117 public final static int JOIN_MITER = 0;
118
119 /**
120 * Joins path segments by rounding off the corner at a radius
121 * of half the line width.
122 */
123 public final static int JOIN_ROUND = 1;
124
125 /**
126 * Joins path segments by connecting the outer corners of their
127 * wide outlines with a straight segment.
128 */
129 public final static int JOIN_BEVEL = 2;
130
131 /**
132 * Ends unclosed subpaths and dash segments with no added
133 * decoration.
134 */
135 public final static int CAP_BUTT = 0;
136
137 /**
138 * Ends unclosed subpaths and dash segments with a round
139 * decoration that has a radius equal to half of the width
140 * of the pen.
141 */
142 public final static int CAP_ROUND = 1;
143
144 /**
145 * Ends unclosed subpaths and dash segments with a square
146 * projection that extends beyond the end of the segment
147 * to a distance equal to half of the line width.
148 */
149 public final static int CAP_SQUARE = 2;
150
151 float width;
152
153 int join;
154 int cap;
155 float miterlimit;
156
157 float dash[];
158 float dash_phase;
159
160 /**
161 * Constructs a new <code>BasicStroke</code> with the specified
162 * attributes.
163 * @param width the width of this <code>BasicStroke</code>. The
164 * width must be greater than or equal to 0.0f. If width is
165 * set to 0.0f, the stroke is rendered as the thinnest
166 * possible line for the target device and the antialias
167 * hint setting.
168 * @param cap the decoration of the ends of a <code>BasicStroke</code>
169 * @param join the decoration applied where path segments meet
170 * @param miterlimit the limit to trim the miter join. The miterlimit
171 * must be greater than or equal to 1.0f.
172 * @param dash the array representing the dashing pattern
173 * @param dash_phase the offset to start the dashing pattern
174 * @throws IllegalArgumentException if <code>width</code> is negative
175 * @throws IllegalArgumentException if <code>cap</code> is not either
176 * CAP_BUTT, CAP_ROUND or CAP_SQUARE
177 * @throws IllegalArgumentException if <code>miterlimit</code> is less
178 * than 1 and <code>join</code> is JOIN_MITER
179 * @throws IllegalArgumentException if <code>join</code> is not
180 * either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER
181 * @throws IllegalArgumentException if <code>dash_phase</code>
182 * is negative and <code>dash</code> is not <code>null</code>
183 * @throws IllegalArgumentException if the length of
184 * <code>dash</code> is zero
185 * @throws IllegalArgumentException if dash lengths are all zero.
186 */
187 public BasicStroke(float width, int cap, int join,
188 float miterlimit, float dash[], float dash_phase) {
189 if (width < 0.0f) {
190 throw new IllegalArgumentException("negative width");
191 }
192 if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
193 throw new IllegalArgumentException("illegal end cap value");
194 }
195 if (join == JOIN_MITER) {
196 if (miterlimit < 1.0f) {
197 throw new IllegalArgumentException("miter limit < 1");
198 }
199 } else if (join != JOIN_ROUND && join != JOIN_BEVEL) {
200 throw new IllegalArgumentException(
201 "illegal line join value");
202 }
203 if (dash != null) {
204 if (dash_phase < 0.0f) {
205 throw new IllegalArgumentException(
206 "negative dash phase");
207 }
208 boolean allzero = true;
209 for (int i = 0; i < dash.length; i++) {
210 float d = dash[i];
211 if (d > 0.0) {
212 allzero = false;
213 } else if (d < 0.0) {
214 throw new IllegalArgumentException(
215 "negative dash length");
216 }
217 }
218 if (allzero) {
219 throw new IllegalArgumentException(
220 "dash lengths all zero");
221 }
222 }
223 this .width = width;
224 this .cap = cap;
225 this .join = join;
226 this .miterlimit = miterlimit;
227 if (dash != null) {
228 this .dash = (float[]) dash.clone();
229 }
230 this .dash_phase = dash_phase;
231 }
232
233 /**
234 * Constructs a solid <code>BasicStroke</code> with the specified
235 * attributes.
236 * @param width the width of the <code>BasicStroke</code>
237 * @param cap the decoration of the ends of a <code>BasicStroke</code>
238 * @param join the decoration applied where path segments meet
239 * @param miterlimit the limit to trim the miter join
240 * @throws IllegalArgumentException if <code>width</code> is negative
241 * @throws IllegalArgumentException if <code>cap</code> is not either
242 * CAP_BUTT, CAP_ROUND or CAP_SQUARE
243 * @throws IllegalArgumentException if <code>miterlimit</code> is less
244 * than 1 and <code>join</code> is JOIN_MITER
245 * @throws IllegalArgumentException if <code>join</code> is not
246 * either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER
247 */
248 public BasicStroke(float width, int cap, int join, float miterlimit) {
249 this (width, cap, join, miterlimit, null, 0.0f);
250 }
251
252 /**
253 * Constructs a solid <code>BasicStroke</code> with the specified
254 * attributes. The <code>miterlimit</code> parameter is
255 * unnecessary in cases where the default is allowable or the
256 * line joins are not specified as JOIN_MITER.
257 * @param width the width of the <code>BasicStroke</code>
258 * @param cap the decoration of the ends of a <code>BasicStroke</code>
259 * @param join the decoration applied where path segments meet
260 * @throws IllegalArgumentException if <code>width</code> is negative
261 * @throws IllegalArgumentException if <code>cap</code> is not either
262 * CAP_BUTT, CAP_ROUND or CAP_SQUARE
263 * @throws IllegalArgumentException if <code>join</code> is not
264 * either JOIN_ROUND, JOIN_BEVEL, or JOIN_MITER
265 */
266 public BasicStroke(float width, int cap, int join) {
267 this (width, cap, join, 10.0f, null, 0.0f);
268 }
269
270 /**
271 * Constructs a solid <code>BasicStroke</code> with the specified
272 * line width and with default values for the cap and join
273 * styles.
274 * @param width the width of the <code>BasicStroke</code>
275 * @throws IllegalArgumentException if <code>width</code> is negative
276 */
277 public BasicStroke(float width) {
278 this (width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
279 }
280
281 /**
282 * Constructs a new <code>BasicStroke</code> with defaults for all
283 * attributes.
284 * The default attributes are a solid line of width 1.0, CAP_SQUARE,
285 * JOIN_MITER, a miter limit of 10.0.
286 */
287 public BasicStroke() {
288 this (1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
289 }
290
291 /**
292 * Returns a <code>Shape</code> whose interior defines the
293 * stroked outline of a specified <code>Shape</code>.
294 * @param s the <code>Shape</code> boundary be stroked
295 * @return the <code>Shape</code> of the stroked outline.
296 */
297 public Shape createStrokedShape(Shape s) {
298 sun.java2d.pipe.RenderingEngine re = sun.java2d.pipe.RenderingEngine
299 .getInstance();
300 return re.createStrokedShape(s, width, cap, join, miterlimit,
301 dash, dash_phase);
302 }
303
304 /**
305 * Returns the line width. Line width is represented in user space,
306 * which is the default-coordinate space used by Java 2D. See the
307 * <code>Graphics2D</code> class comments for more information on
308 * the user space coordinate system.
309 * @return the line width of this <code>BasicStroke</code>.
310 * @see Graphics2D
311 */
312 public float getLineWidth() {
313 return width;
314 }
315
316 /**
317 * Returns the end cap style.
318 * @return the end cap style of this <code>BasicStroke</code> as one
319 * of the static <code>int</code> values that define possible end cap
320 * styles.
321 */
322 public int getEndCap() {
323 return cap;
324 }
325
326 /**
327 * Returns the line join style.
328 * @return the line join style of the <code>BasicStroke</code> as one
329 * of the static <code>int</code> values that define possible line
330 * join styles.
331 */
332 public int getLineJoin() {
333 return join;
334 }
335
336 /**
337 * Returns the limit of miter joins.
338 * @return the limit of miter joins of the <code>BasicStroke</code>.
339 */
340 public float getMiterLimit() {
341 return miterlimit;
342 }
343
344 /**
345 * Returns the array representing the lengths of the dash segments.
346 * Alternate entries in the array represent the user space lengths
347 * of the opaque and transparent segments of the dashes.
348 * As the pen moves along the outline of the <code>Shape</code>
349 * to be stroked, the user space
350 * distance that the pen travels is accumulated. The distance
351 * value is used to index into the dash array.
352 * The pen is opaque when its current cumulative distance maps
353 * to an even element of the dash array and transparent otherwise.
354 * @return the dash array.
355 */
356 public float[] getDashArray() {
357 if (dash == null) {
358 return null;
359 }
360
361 return (float[]) dash.clone();
362 }
363
364 /**
365 * Returns the current dash phase.
366 * The dash phase is a distance specified in user coordinates that
367 * represents an offset into the dashing pattern. In other words, the dash
368 * phase defines the point in the dashing pattern that will correspond to
369 * the beginning of the stroke.
370 * @return the dash phase as a <code>float</code> value.
371 */
372 public float getDashPhase() {
373 return dash_phase;
374 }
375
376 /**
377 * Returns the hashcode for this stroke.
378 * @return a hash code for this stroke.
379 */
380 public int hashCode() {
381 int hash = Float.floatToIntBits(width);
382 hash = hash * 31 + join;
383 hash = hash * 31 + cap;
384 hash = hash * 31 + Float.floatToIntBits(miterlimit);
385 if (dash != null) {
386 hash = hash * 31 + Float.floatToIntBits(dash_phase);
387 for (int i = 0; i < dash.length; i++) {
388 hash = hash * 31 + Float.floatToIntBits(dash[i]);
389 }
390 }
391 return hash;
392 }
393
394 /**
395 * Returns true if this BasicStroke represents the same
396 * stroking operation as the given argument.
397 */
398 /**
399 * Tests if a specified object is equal to this <code>BasicStroke</code>
400 * by first testing if it is a <code>BasicStroke</code> and then comparing
401 * its width, join, cap, miter limit, dash, and dash phase attributes with
402 * those of this <code>BasicStroke</code>.
403 * @param obj the specified object to compare to this
404 * <code>BasicStroke</code>
405 * @return <code>true</code> if the width, join, cap, miter limit, dash, and
406 * dash phase are the same for both objects;
407 * <code>false</code> otherwise.
408 */
409 public boolean equals(Object obj) {
410 if (!(obj instanceof BasicStroke)) {
411 return false;
412 }
413
414 BasicStroke bs = (BasicStroke) obj;
415 if (width != bs.width) {
416 return false;
417 }
418
419 if (join != bs.join) {
420 return false;
421 }
422
423 if (cap != bs.cap) {
424 return false;
425 }
426
427 if (miterlimit != bs.miterlimit) {
428 return false;
429 }
430
431 if (dash != null) {
432 if (dash_phase != bs.dash_phase) {
433 return false;
434 }
435
436 if (!java.util.Arrays.equals(dash, bs.dash)) {
437 return false;
438 }
439 } else if (bs.dash != null) {
440 return false;
441 }
442
443 return true;
444 }
445 }
|