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