]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/arrows/ArrowLineEndStyle.java
Fixed route graph splitting and diagram mapping race condition problem
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / rendering / arrows / ArrowLineEndStyle.java
1 /*******************************************************************************
2  * Copyright (c) 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.connection.rendering.arrows;
13
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;
20
21
22 /**
23  * @author Tuukka Lehtonen
24  */
25 public class ArrowLineEndStyle implements ILineEndStyle, Serializable {
26
27     private static final long serialVersionUID = -346653685430483245L;
28
29     public static enum ArrowType { None, Stroke, Fill }
30
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;
34
35     protected ArrowType        type;
36     protected double           lineEndLength;
37     protected double           length;
38     protected double           width;
39     protected double           space;
40     protected Color            color;
41
42     protected transient Path2D path;
43
44     public ArrowLineEndStyle() {
45         this(DEFAULT_LENGTH, DEFAULT_WIDTH, DEFAULT_SPACE, null);
46     }
47
48     public ArrowLineEndStyle(double length, double width, double space) {
49         this(length, width, space, null);
50     }
51
52     public ArrowLineEndStyle(double length, double width, double space, Color color) {
53         this.type = ArrowType.Fill;
54         this.length = length;
55         this.width = width;
56         this.space = space;
57         this.color = color;
58         this.path = arrow(length, width, space);
59     }
60
61     public ArrowLineEndStyle(String desc) {
62         this.type = ArrowType.None;
63         this.lineEndLength = 0.0;
64
65         double l = DEFAULT_LENGTH;
66         double w = DEFAULT_WIDTH;
67         double s = DEFAULT_SPACE;
68
69         StringTokenizer tokenizer = new StringTokenizer(desc);
70         if (tokenizer.hasMoreTokens()) {
71             String type = tokenizer.nextToken();
72             this.type = parseType(type);
73
74             if (tokenizer.hasMoreTokens()) {
75                 String ls = tokenizer.nextToken();
76                 l = parseSize(ls, length);
77
78                 if (tokenizer.hasMoreTokens()) {
79                     String ws = tokenizer.nextToken();
80                     w = parseSize(ws, width);
81
82                     if (tokenizer.hasMoreTokens()) {
83                         String ss = tokenizer.nextToken();
84                         s = parseSize(ss, space);
85                     }
86                 }
87             }
88             if (this.type != ArrowType.None) {
89                 this.path = arrow(l, w, s);
90                 lineEndLength = l+s;
91             }
92         }
93
94         this.width = w;
95         this.length = l;
96         this.space = s;
97     }
98
99     @Override
100     public void render(Graphics2D g, double x, double y, int dir) {
101         if (type == ArrowType.None || path == null)
102             return;
103
104         AffineTransform old = g.getTransform();
105         g.translate(x, y);
106         g.rotate(dir*Math.PI*0.5);
107         if(color != null)
108                 g.setColor(color);
109
110         switch (type) {
111             case Fill:
112                 g.fill(path);
113                 break;
114             case Stroke:
115                 g.draw(path);
116                 break;
117         }
118
119         g.setTransform(old);
120     }
121
122     @Override
123     public double getLineEndLength(int direction) {
124         return lineEndLength;
125     }
126
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);
132         path.closePath();
133         return path;
134     }
135
136     private static double parseSize(String size, double defaultValue) {
137         try {
138             return Double.parseDouble(size);
139         } catch (NumberFormatException e) {
140             return defaultValue;
141         }
142     }
143
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);
153     }
154
155     @Override
156     public String toString() {
157         return getClass().getSimpleName() + "@" + System.identityHashCode(this) + "[" + type + ", w=" + width + ", l=" + length + ", s=" + space + ", lel=" + lineEndLength + "]";
158     }
159
160     @Override
161     public int hashCode() {
162         final int prime = 31;
163         int result = 1;
164         long temp;
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));
174         return result;
175     }
176
177     @Override
178     public boolean equals(Object obj) {
179         if (this == obj)
180             return true;
181         if (obj == null)
182             return false;
183         if (getClass() != obj.getClass())
184             return false;
185         ArrowLineEndStyle other = (ArrowLineEndStyle) obj;
186         if (Double.doubleToLongBits(length) != Double.doubleToLongBits(other.length))
187             return false;
188         if (Double.doubleToLongBits(lineEndLength) != Double.doubleToLongBits(other.lineEndLength))
189             return false;
190         if (Double.doubleToLongBits(space) != Double.doubleToLongBits(other.space))
191             return false;
192         if (type != other.type)
193             return false;
194         if (Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))
195             return false;
196         return true;
197     }
198
199 }