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