1 /*******************************************************************************
2 * Copyright (c) 2011 Association for Decentralized Information Management in
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.diagram.connection.rendering.arrows;
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Path2D;
18 import java.io.Serializable;
19 import java.util.StringTokenizer;
23 * @author Tuukka Lehtonen
25 public class ArrowLineEndStyle implements ILineEndStyle, Serializable {
27 private static final long serialVersionUID = -346653685430483245L;
29 public static enum ArrowType { None, Stroke, Fill }
31 public static final double DEFAULT_LENGTH = 8.0;
32 public static final double DEFAULT_WIDTH = 4.0;
33 public static final double DEFAULT_SPACE = 0.0;
35 protected ArrowType type;
36 protected double lineEndLength;
37 protected double length;
38 protected double width;
39 protected double space;
40 protected Color color;
42 protected transient Path2D path;
44 public ArrowLineEndStyle() {
45 this(DEFAULT_LENGTH, DEFAULT_WIDTH, DEFAULT_SPACE, null);
48 public ArrowLineEndStyle(double length, double width, double space) {
49 this(length, width, space, null);
52 public ArrowLineEndStyle(double length, double width, double space, Color color) {
53 this.type = ArrowType.Fill;
58 this.path = arrow(length, width, space);
61 public ArrowLineEndStyle(String desc) {
62 this.type = ArrowType.None;
63 this.lineEndLength = 0.0;
65 double l = DEFAULT_LENGTH;
66 double w = DEFAULT_WIDTH;
67 double s = DEFAULT_SPACE;
69 StringTokenizer tokenizer = new StringTokenizer(desc);
70 if (tokenizer.hasMoreTokens()) {
71 String type = tokenizer.nextToken();
72 this.type = parseType(type);
74 if (tokenizer.hasMoreTokens()) {
75 String ls = tokenizer.nextToken();
76 l = parseSize(ls, length);
78 if (tokenizer.hasMoreTokens()) {
79 String ws = tokenizer.nextToken();
80 w = parseSize(ws, width);
82 if (tokenizer.hasMoreTokens()) {
83 String ss = tokenizer.nextToken();
84 s = parseSize(ss, space);
88 if (this.type != ArrowType.None) {
89 this.path = arrow(l, w, s);
100 public void render(Graphics2D g, double x, double y, int dir) {
101 if (type == ArrowType.None || path == null)
104 AffineTransform old = g.getTransform();
106 g.rotate(dir*Math.PI*0.5);
123 public double getLineEndLength(int direction) {
124 return lineEndLength;
127 private static Path2D arrow(double length, double width, double space) {
128 Path2D.Double path = new Path2D.Double();
129 path.moveTo(-space, 0);
130 path.lineTo(-length-space, -width);
131 path.lineTo(-length-space, +width);
136 private static double parseSize(String size, double defaultValue) {
138 return Double.parseDouble(size);
139 } catch (NumberFormatException e) {
144 private static ArrowType parseType(String type) {
145 String lower = type.toLowerCase();
146 if ("none".equals(lower))
147 return ArrowType.None;
148 if ("stroke".equals(lower))
149 return ArrowType.Stroke;
150 if ("fill".equals(lower))
151 return ArrowType.Fill;
152 throw new IllegalArgumentException("unrecognized arrow type: " + type);
156 public String toString() {
157 return getClass().getSimpleName() + "@" + System.identityHashCode(this) + "[" + type + ", w=" + width + ", l=" + length + ", s=" + space + ", lel=" + lineEndLength + "]";
161 public int hashCode() {
162 final int prime = 31;
165 temp = Double.doubleToLongBits(length);
166 result = prime * result + (int) (temp ^ (temp >>> 32));
167 temp = Double.doubleToLongBits(lineEndLength);
168 result = prime * result + (int) (temp ^ (temp >>> 32));
169 temp = Double.doubleToLongBits(space);
170 result = prime * result + (int) (temp ^ (temp >>> 32));
171 result = prime * result + ((type == null) ? 0 : type.hashCode());
172 temp = Double.doubleToLongBits(width);
173 result = prime * result + (int) (temp ^ (temp >>> 32));
178 public boolean equals(Object obj) {
183 if (getClass() != obj.getClass())
185 ArrowLineEndStyle other = (ArrowLineEndStyle) obj;
186 if (Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length))
188 if (Double.doubleToLongBits(lineEndLength) != Double.doubleToLongBits(other.lineEndLength))
190 if (Double.doubleToLongBits(space) != Double.doubleToLongBits(other.space))
192 if (type != other.type)
194 if (Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))