1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.svg;
14 import java.awt.BasicStroke;
15 import java.awt.Graphics2D;
17 //import org.apache.batik.util.CSSConstants;
20 * @author Tuukka Lehtonen
22 public class StrokeDesc {
24 public static final String DEFAULT_MEASUREMENT_UNIT = "";
27 * This empty array stands for no dashing.
29 public static final double[] NO_DASHES_DASH_ARRAY = {};
31 // public static final String[] joinConv = { "miter", "round", "bevel" };
32 // public static final String[] capConv = { "butt", "round", "square" };
35 * Joins path segments by extending their outside edges until they meet.
37 public final static Integer JOIN_MITER = BasicStroke.JOIN_MITER;
40 * Joins path segments by rounding off the corner at a radius of half the
43 public final static Integer JOIN_ROUND = BasicStroke.JOIN_ROUND;
46 * Joins path segments by connecting the outer corners of their wide
47 * outlines with a straight segment.
49 public final static Integer JOIN_BEVEL = BasicStroke.JOIN_BEVEL;
52 * Ends unclosed subpaths and dash segments with no added decoration.
54 public final static Integer CAP_BUTT = BasicStroke.CAP_BUTT;
57 * Ends unclosed subpaths and dash segments with a round decoration that has
58 * a radius equal to half of the width of the pen.
60 public final static Integer CAP_ROUND = BasicStroke.CAP_ROUND;
63 * Ends unclosed subpaths and dash segments with a square projection that
64 * extends beyond the end of the segment to a distance equal to half of the
67 public final static Integer CAP_SQUARE = BasicStroke.CAP_SQUARE;
72 private double opacity;
76 private LineJoin join;
80 private double miterLimit;
83 * An empty array (length == 0) stands for no dashing.
85 private double[] dash;
87 private double dashOffset;
90 * One of valid measurement units in SVG, such as "in", "mm", "cm", etc.
92 private String unitSuffix;
95 this(StyleConstants.INHERIT, 1.0, 1.0, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);
98 public StrokeDesc(String paint) {
99 this(paint, 1.0, 1.0, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);
102 public StrokeDesc(String paint, double opacity, double width) {
103 this(paint, opacity, width, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);
106 public StrokeDesc(String paint, double opacity, double width, LineJoin join, LineCap cap) {
107 this(paint, opacity, width, join, cap, 10.0, null, 0.0);
110 public StrokeDesc(String paint, double opacity, double width, LineJoin join, LineCap cap, double miterLimit, double[] dashArray, double dashOffset) {
116 setMiterLimit(miterLimit);
118 if (dashArray == null || dashArray.length == 0)
119 dashArray = NO_DASHES_DASH_ARRAY;
120 this.dash = dashArray;
121 this.dashOffset = dashOffset;
123 this.unitSuffix = DEFAULT_MEASUREMENT_UNIT;
126 public void setUnitSuffix(String unitSuffix) {
127 if (!SVGUnits.isValidUnit(unitSuffix))
128 throw new IllegalArgumentException("invalid unit suffix: " + unitSuffix);
129 this.unitSuffix = unitSuffix;
132 public String getUnitSuffix() {
136 public String getPaint() {
140 public void setPaint(String paint) {
144 public double getOpacity() {
148 public void setOpacity(double opacity) {
149 this.opacity = opacity;
153 * Returns the line width. Line width is represented in user space, which is
154 * the default-coordinate system used by Java 2D. See the
155 * <code>Graphics2D</code> class comments for more information on the user
156 * space coordinate system.
158 * @return the line width of this <code>BasicStroke</code>.
161 public double getLineWidth() {
165 public String getLineWidthWithUnit() {
166 return String.valueOf(width) + unitSuffix;
169 public void setLineWidth(double width) {
174 * Returns the end cap style.
176 * @return the end cap style of this <code>BasicStroke</code> as one of
177 * the static <code>int</code> values that define possible end cap
180 public LineCap getEndCap() {
184 public void setEndCap(LineCap cap) {
189 * Returns the line join style.
191 * @return the line join style of the <code>BasicStroke</code> as one of
192 * the static <code>int</code> values that define possible line
195 public LineJoin getLineJoin() {
199 public void setLineJoin(LineJoin join) {
204 * Returns the limit of miter joins.
206 * @return the limit of miter joins of the <code>BasicStroke</code>.
208 public double getMiterLimit() {
212 public void setMiterLimit(double miterLimit) {
213 this.miterLimit = miterLimit;
217 * Returns the array representing the lengths of the dash segments.
218 * Alternate entries in the array represent the user space lengths of the
219 * opaque and transparent segments of the dashes. As the pen moves along the
220 * outline of the <code>Shape</code> to be stroked, the user space
221 * distance that the pen travels is accumulated. The distance value is used
222 * to index into the dash array. The pen is opaque when its current
223 * cumulative distance maps to an even element of the dash array and
224 * transparent otherwise.
226 * @return the dash array.
228 public double[] getDashArray() {
229 if (dash == NO_DASHES_DASH_ARRAY)
231 return (double[]) dash.clone();
234 public void setDashArray(double[] dash) {
235 if (dash == null || dash.length == 0)
236 dash = NO_DASHES_DASH_ARRAY;
241 * Returns the current dash phase. The dash phase is a distance specified in
242 * user coordinates that represents an offset into the dashing pattern. In
243 * other words, the dash phase defines the point in the dashing pattern that
244 * will correspond to the beginning of the stroke.
246 * @return the dash phase as a <code>double</code> value.
248 public double getDashOffset() {
252 public void setDashOffset(double dashOffset) {
253 this.dashOffset = dashOffset;
257 * Returns the hashcode for this stroke.
259 * @return a hash code for this stroke.
261 public int hashCode() {
262 int hash = (int) Double.doubleToLongBits(width);
263 hash = hash * 31 + join.ordinal();
264 hash = hash * 31 + cap.ordinal();
265 hash = hash * 31 + (int) Double.doubleToLongBits(miterLimit);
267 hash = hash * 31 + (int) Double.doubleToLongBits(dashOffset);
268 for (int i = 0; i < dash.length; i++) {
269 hash = hash * 31 + (int) Double.doubleToLongBits(dash[i]);
276 * Returns true if this BasicStroke represents the same stroking operation
277 * as the given argument.
280 * Tests if a specified object is equal to this <code>Stroke</code> by
281 * first testing if it is a <code>BasicStroke</code> and then comparing
282 * its width, join, cap, miter limit, dash, and dash phase attributes with
283 * those of this <code>Stroke</code>.
285 * @param obj the specified object to compare to this <code>Stroke</code>
286 * @return <code>true</code> if the width, join, cap, miter limit, dash,
287 * and dash phase are the same for both objects; <code>false</code>
290 public boolean equals(Object obj) {
291 if (!(obj instanceof StrokeDesc)) {
295 StrokeDesc bs = (StrokeDesc) obj;
296 if (width != bs.width) {
300 if (join != bs.join) {
308 if (miterLimit != bs.miterLimit) {
313 if (dashOffset != bs.dashOffset) {
317 if (!java.util.Arrays.equals(dash, bs.dash)) {
320 } else if (bs.dash != null) {
327 // public String toStyleString() {
328 // StringBuilder s = new StringBuilder();
330 // s.append(CSSConstants.CSS_STROKE_PROPERTY);
333 // if (!paint.equals(CSSConstants.CSS_NONE_VALUE)) {
335 // s.append(CSSConstants.CSS_STROKE_OPACITY_PROPERTY);
337 // s.append(opacity);
339 // s.append(CSSConstants.CSS_STROKE_WIDTH_PROPERTY);
342 // s.append(unitSuffix);
343 // if (dash.length > 0) {
345 // s.append(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY);
347 // appendDashArrayString(s);
349 // s.append(CSSConstants.CSS_STROKE_DASHOFFSET_PROPERTY);
351 // s.append(dashOffset);
354 // s.append(CSSConstants.CSS_STROKE_LINECAP_PROPERTY);
356 // s.append(cap.toString());
358 // s.append(CSSConstants.CSS_STROKE_LINEJOIN_PROPERTY);
360 // s.append(join.toString());
361 // if (LineJoin.miter.equals(join)) {
363 // s.append(CSSConstants.CSS_STROKE_MITERLIMIT_PROPERTY);
365 // s.append(miterLimit);
370 // return s.toString();
373 public void appendDashArrayString(StringBuilder s) {
374 if (dash.length > 0) {
376 for (int i = 1; i < dash.length; ++i) {
383 public String dashArrayToString() {
385 if (dash.length > 0) {
387 for (int i = 1; i < dash.length; ++i) {