+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.svg;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Graphics2D;\r
+\r
+//import org.apache.batik.util.CSSConstants;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class StrokeDesc {\r
+\r
+ public static final String DEFAULT_MEASUREMENT_UNIT = "";\r
+\r
+ /**\r
+ * This empty array stands for no dashing.\r
+ */\r
+ public static final double[] NO_DASHES_DASH_ARRAY = {};\r
+ \r
+// public static final String[] joinConv = { "miter", "round", "bevel" };\r
+// public static final String[] capConv = { "butt", "round", "square" };\r
+ \r
+ /**\r
+ * Joins path segments by extending their outside edges until they meet.\r
+ */\r
+ public final static Integer JOIN_MITER = BasicStroke.JOIN_MITER;\r
+\r
+ /**\r
+ * Joins path segments by rounding off the corner at a radius of half the\r
+ * line width.\r
+ */\r
+ public final static Integer JOIN_ROUND = BasicStroke.JOIN_ROUND;\r
+\r
+ /**\r
+ * Joins path segments by connecting the outer corners of their wide\r
+ * outlines with a straight segment.\r
+ */\r
+ public final static Integer JOIN_BEVEL = BasicStroke.JOIN_BEVEL;\r
+\r
+ /**\r
+ * Ends unclosed subpaths and dash segments with no added decoration.\r
+ */\r
+ public final static Integer CAP_BUTT = BasicStroke.CAP_BUTT;\r
+\r
+ /**\r
+ * Ends unclosed subpaths and dash segments with a round decoration that has\r
+ * a radius equal to half of the width of the pen.\r
+ */\r
+ public final static Integer CAP_ROUND = BasicStroke.CAP_ROUND;\r
+\r
+ /**\r
+ * Ends unclosed subpaths and dash segments with a square projection that\r
+ * extends beyond the end of the segment to a distance equal to half of the\r
+ * line width.\r
+ */\r
+ public final static Integer CAP_SQUARE = BasicStroke.CAP_SQUARE;\r
+\r
+ \r
+ private String paint;\r
+\r
+ private double opacity;\r
+\r
+ private double width;\r
+\r
+ private LineJoin join;\r
+\r
+ private LineCap cap;\r
+\r
+ private double miterLimit;\r
+\r
+ /**\r
+ * An empty array (length == 0) stands for no dashing.\r
+ */\r
+ private double[] dash;\r
+\r
+ private double dashOffset;\r
+ \r
+ /**\r
+ * One of valid measurement units in SVG, such as "in", "mm", "cm", etc.\r
+ */\r
+ private String unitSuffix;\r
+\r
+ public StrokeDesc() {\r
+ this(StyleConstants.INHERIT, 1.0, 1.0, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);\r
+ }\r
+ \r
+ public StrokeDesc(String paint) {\r
+ this(paint, 1.0, 1.0, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);\r
+ }\r
+ \r
+ public StrokeDesc(String paint, double opacity, double width) {\r
+ this(paint, opacity, width, LineJoin.bevel, LineCap.butt, 10.0, null, 0.0);\r
+ }\r
+\r
+ public StrokeDesc(String paint, double opacity, double width, LineJoin join, LineCap cap) {\r
+ this(paint, opacity, width, join, cap, 10.0, null, 0.0);\r
+ }\r
+ \r
+ public StrokeDesc(String paint, double opacity, double width, LineJoin join, LineCap cap, double miterLimit, double[] dashArray, double dashOffset) {\r
+ setPaint(paint);\r
+ setOpacity(opacity);\r
+ setLineWidth(width);\r
+ setLineJoin(join);\r
+ setEndCap(cap);\r
+ setMiterLimit(miterLimit);\r
+ \r
+ if (dashArray == null || dashArray.length == 0)\r
+ dashArray = NO_DASHES_DASH_ARRAY;\r
+ this.dash = dashArray;\r
+ this.dashOffset = dashOffset;\r
+ \r
+ this.unitSuffix = DEFAULT_MEASUREMENT_UNIT;\r
+ }\r
+ \r
+ public void setUnitSuffix(String unitSuffix) {\r
+ if (!SVGUnits.isValidUnit(unitSuffix))\r
+ throw new IllegalArgumentException("invalid unit suffix: " + unitSuffix);\r
+ this.unitSuffix = unitSuffix;\r
+ }\r
+ \r
+ public String getUnitSuffix() {\r
+ return unitSuffix;\r
+ }\r
+ \r
+ public String getPaint() {\r
+ return paint;\r
+ }\r
+ \r
+ public void setPaint(String paint) {\r
+ this.paint = paint;\r
+ }\r
+ \r
+ public double getOpacity() {\r
+ return opacity;\r
+ }\r
+ \r
+ public void setOpacity(double opacity) {\r
+ this.opacity = opacity;\r
+ }\r
+ \r
+ /**\r
+ * Returns the line width. Line width is represented in user space, which is\r
+ * the default-coordinate system used by Java 2D. See the\r
+ * <code>Graphics2D</code> class comments for more information on the user\r
+ * space coordinate system.\r
+ * \r
+ * @return the line width of this <code>BasicStroke</code>.\r
+ * @see Graphics2D\r
+ */\r
+ public double getLineWidth() {\r
+ return width;\r
+ }\r
+ \r
+ public String getLineWidthWithUnit() {\r
+ return String.valueOf(width) + unitSuffix;\r
+ }\r
+\r
+ public void setLineWidth(double width) {\r
+ this.width = width;\r
+ }\r
+ \r
+ /**\r
+ * Returns the end cap style.\r
+ * \r
+ * @return the end cap style of this <code>BasicStroke</code> as one of\r
+ * the static <code>int</code> values that define possible end cap\r
+ * styles.\r
+ */\r
+ public LineCap getEndCap() {\r
+ return cap;\r
+ }\r
+\r
+ public void setEndCap(LineCap cap) {\r
+ this.cap = cap;\r
+ }\r
+ \r
+ /**\r
+ * Returns the line join style.\r
+ * \r
+ * @return the line join style of the <code>BasicStroke</code> as one of\r
+ * the static <code>int</code> values that define possible line\r
+ * join styles.\r
+ */\r
+ public LineJoin getLineJoin() {\r
+ return join;\r
+ }\r
+\r
+ public void setLineJoin(LineJoin join) {\r
+ this.join = join;\r
+ }\r
+ \r
+ /**\r
+ * Returns the limit of miter joins.\r
+ * \r
+ * @return the limit of miter joins of the <code>BasicStroke</code>.\r
+ */\r
+ public double getMiterLimit() {\r
+ return miterLimit;\r
+ }\r
+\r
+ public void setMiterLimit(double miterLimit) {\r
+ this.miterLimit = miterLimit;\r
+ }\r
+ \r
+ /**\r
+ * Returns the array representing the lengths of the dash segments.\r
+ * Alternate entries in the array represent the user space lengths of the\r
+ * opaque and transparent segments of the dashes. As the pen moves along the\r
+ * outline of the <code>Shape</code> to be stroked, the user space\r
+ * distance that the pen travels is accumulated. The distance value is used\r
+ * to index into the dash array. The pen is opaque when its current\r
+ * cumulative distance maps to an even element of the dash array and\r
+ * transparent otherwise.\r
+ * \r
+ * @return the dash array.\r
+ */\r
+ public double[] getDashArray() {\r
+ if (dash == NO_DASHES_DASH_ARRAY)\r
+ return dash;\r
+ return (double[]) dash.clone();\r
+ }\r
+\r
+ public void setDashArray(double[] dash) {\r
+ if (dash == null || dash.length == 0)\r
+ dash = NO_DASHES_DASH_ARRAY;\r
+ this.dash = dash;\r
+ }\r
+ \r
+ /**\r
+ * Returns the current dash phase. The dash phase is a distance specified in\r
+ * user coordinates that represents an offset into the dashing pattern. In\r
+ * other words, the dash phase defines the point in the dashing pattern that\r
+ * will correspond to the beginning of the stroke.\r
+ * \r
+ * @return the dash phase as a <code>double</code> value.\r
+ */\r
+ public double getDashOffset() {\r
+ return dashOffset;\r
+ }\r
+ \r
+ public void setDashOffset(double dashOffset) {\r
+ this.dashOffset = dashOffset;\r
+ }\r
+\r
+ /**\r
+ * Returns the hashcode for this stroke.\r
+ * \r
+ * @return a hash code for this stroke.\r
+ */\r
+ public int hashCode() {\r
+ int hash = (int) Double.doubleToLongBits(width);\r
+ hash = hash * 31 + join.ordinal();\r
+ hash = hash * 31 + cap.ordinal();\r
+ hash = hash * 31 + (int) Double.doubleToLongBits(miterLimit);\r
+ if (dash != null) {\r
+ hash = hash * 31 + (int) Double.doubleToLongBits(dashOffset);\r
+ for (int i = 0; i < dash.length; i++) {\r
+ hash = hash * 31 + (int) Double.doubleToLongBits(dash[i]);\r
+ }\r
+ }\r
+ return hash;\r
+ }\r
+\r
+ /**\r
+ * Returns true if this BasicStroke represents the same stroking operation\r
+ * as the given argument.\r
+ * \r
+ * <p>\r
+ * Tests if a specified object is equal to this <code>Stroke</code> by\r
+ * first testing if it is a <code>BasicStroke</code> and then comparing\r
+ * its width, join, cap, miter limit, dash, and dash phase attributes with\r
+ * those of this <code>Stroke</code>.\r
+ * \r
+ * @param obj the specified object to compare to this <code>Stroke</code>\r
+ * @return <code>true</code> if the width, join, cap, miter limit, dash,\r
+ * and dash phase are the same for both objects; <code>false</code>\r
+ * otherwise.\r
+ */\r
+ public boolean equals(Object obj) {\r
+ if (!(obj instanceof StrokeDesc)) {\r
+ return false;\r
+ }\r
+\r
+ StrokeDesc bs = (StrokeDesc) obj;\r
+ if (width != bs.width) {\r
+ return false;\r
+ }\r
+\r
+ if (join != bs.join) {\r
+ return false;\r
+ }\r
+\r
+ if (cap != bs.cap) {\r
+ return false;\r
+ }\r
+\r
+ if (miterLimit != bs.miterLimit) {\r
+ return false;\r
+ }\r
+\r
+ if (dash != null) {\r
+ if (dashOffset != bs.dashOffset) {\r
+ return false;\r
+ }\r
+\r
+ if (!java.util.Arrays.equals(dash, bs.dash)) {\r
+ return false;\r
+ }\r
+ } else if (bs.dash != null) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+// public String toStyleString() {\r
+// StringBuilder s = new StringBuilder();\r
+// \r
+// s.append(CSSConstants.CSS_STROKE_PROPERTY);\r
+// s.append(':');\r
+// s.append(paint);\r
+// if (!paint.equals(CSSConstants.CSS_NONE_VALUE)) {\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_OPACITY_PROPERTY);\r
+// s.append(':');\r
+// s.append(opacity);\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_WIDTH_PROPERTY);\r
+// s.append(':');\r
+// s.append(width);\r
+// s.append(unitSuffix);\r
+// if (dash.length > 0) {\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_DASHARRAY_PROPERTY);\r
+// s.append(':');\r
+// appendDashArrayString(s);\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_DASHOFFSET_PROPERTY);\r
+// s.append(':');\r
+// s.append(dashOffset);\r
+// }\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_LINECAP_PROPERTY);\r
+// s.append(':');\r
+// s.append(cap.toString());\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_LINEJOIN_PROPERTY);\r
+// s.append(':');\r
+// s.append(join.toString());\r
+// if (LineJoin.miter.equals(join)) {\r
+// s.append(';');\r
+// s.append(CSSConstants.CSS_STROKE_MITERLIMIT_PROPERTY);\r
+// s.append(':');\r
+// s.append(miterLimit);\r
+// }\r
+// }\r
+// s.append(';');\r
+// \r
+// return s.toString();\r
+// }\r
+\r
+ public void appendDashArrayString(StringBuilder s) {\r
+ if (dash.length > 0) {\r
+ s.append(dash[0]);\r
+ for (int i = 1; i < dash.length; ++i) {\r
+ s.append(',');\r
+ s.append(dash[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ public String dashArrayToString() {\r
+ String s = "";\r
+ if (dash.length > 0) {\r
+ s += dash[0];\r
+ for (int i = 1; i < dash.length; ++i) {\r
+ s += ',' + dash[i];\r
+ }\r
+ }\r
+ return s;\r
+ }\r
+\r
+}\r