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.scenegraph.g2d.nodes;
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Composite;
17 import java.awt.Graphics2D;
18 import java.awt.Shape;
19 import java.awt.Stroke;
20 import java.awt.geom.AffineTransform;
21 import java.awt.geom.GeneralPath;
22 import java.awt.geom.Point2D;
23 import java.awt.geom.Rectangle2D;
25 import org.simantics.scenegraph.g2d.G2DNode;
26 import org.simantics.scenegraph.utils.InitValueSupport;
28 public class EdgeNode extends G2DNode implements InitValueSupport {
30 private static final long serialVersionUID = 1294351381209071074L;
32 public static enum ArrowType { None, Stroke, Fill, Both }
34 protected Color color = null;
35 protected Stroke stroke = null;
36 protected Shape shape = null;
37 protected Point2D firstdir = null;
38 protected Point2D lastdir = null;
39 protected Point2D first = null;
40 protected Point2D last = null;
41 protected double firstsize = 0;
42 protected double lastsize = 0;
43 protected ArrowType first_at = null;
44 protected ArrowType last_at = null;
45 protected Shape firstShape = null;
46 protected Shape lastShape = null;
48 private transient Rectangle2D bounds;
50 @SyncField({"color", "stroke", "shape", "firstdir", "lastdir", "first", "last", "firstsize", "lastsize", "first_at", "last_at"})
51 public void init(Shape shape, Stroke stroke, Color color, Point2D firstdir, Point2D lastdir, Point2D first, Point2D last, double firstsize, double lastsize, ArrowType first_at, ArrowType last_at, Shape firstShape, Shape lastShape) {
55 this.firstdir = firstdir;
56 this.lastdir = lastdir;
59 this.firstsize = firstsize;
60 this.lastsize = lastsize;
61 this.first_at = first_at;
62 this.last_at = last_at;
63 this.firstShape = firstShape;
64 this.lastShape = lastShape;
67 this.bounds = shape.getBounds2D();
72 public void render(Graphics2D g) {
73 if(color != null) g.setColor(color);
74 if(stroke == null || shape == null) return;
76 if(alphaComposite != null) {
77 g.setComposite(alphaComposite);
80 Stroke effectiveStroke = stroke;
81 if(dynamicStroke != null) {
82 effectiveStroke = dynamicStroke;
85 Color effectiveColor = color;
86 if(dynamicColor != null) {
87 effectiveColor = dynamicColor;
90 g.setStroke(effectiveStroke);
93 //g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
98 // float f = ((BasicStroke)effectiveStroke).getLineWidth() * 3f;
99 // Color background = Color.WHITE; // FIXME
100 // g.setColor(background);
101 // g.setStroke(new BasicStroke(f));
105 g.setColor(effectiveColor);
106 g.setStroke(effectiveStroke);
109 // Draw line ends if necessary.
110 boolean drawArrows = first_at != ArrowType.None || last_at != ArrowType.None;
114 AffineTransform at = g.getTransform();
116 g.setStroke(ARROW_STROKE);
118 if (first_at != ArrowType.None) {
119 double theta = Math.atan2(firstdir.getY(), firstdir.getX()) - Math.PI/2;
120 g.translate(first.getX(), first.getY());
122 g.scale(firstsize, firstsize);
124 if (first_at == ArrowType.Fill)
125 g.fill(FILLED_ARROW);
126 else if (first_at == ArrowType.Stroke)
127 g.draw(NORMAL_ARROW);
132 if (last_at != ArrowType.None) {
133 double theta = Math.atan2(lastdir.getY(), lastdir.getX()) - Math.PI/2;
134 g.translate(last.getX(), last.getY());
136 g.scale(lastsize, lastsize);
138 if (last_at == ArrowType.Fill)
139 g.fill(FILLED_ARROW);
140 else if (last_at == ArrowType.Stroke)
141 g.draw(NORMAL_ARROW);
148 public transient final static GeneralPath NORMAL_ARROW;
149 public transient final static GeneralPath FILLED_ARROW;
150 public transient static final Stroke ARROW_STROKE = new BasicStroke(1.0f);
153 FILLED_ARROW = new GeneralPath();
154 FILLED_ARROW.moveTo(-0.5f, 1f);
155 FILLED_ARROW.lineTo( 0f, 0f);
156 FILLED_ARROW.lineTo( 0.5f, 1f);
157 FILLED_ARROW.closePath();
159 NORMAL_ARROW = new GeneralPath();
160 NORMAL_ARROW.moveTo(-0.5f, 1f);
161 NORMAL_ARROW.lineTo( 0f, 0f);
162 NORMAL_ARROW.lineTo( 0.5f, 1f);
166 public Rectangle2D getBoundsInLocal() {
170 protected Composite alphaComposite = null;
171 protected Stroke dynamicStroke = null;
172 protected Color dynamicColor = null;
174 @PropertySetter("alpha")
175 @SyncField("alphaComposite")
176 public void setAlphaComposite(Composite alphaComposite) {
177 this.alphaComposite = alphaComposite;
180 @PropertySetter("width")
181 @SyncField("dynamicStroke")
182 public void setDynamicStroke(Stroke stroke) {
183 this.dynamicStroke = stroke;
186 @PropertySetter("color")
187 @SyncField("dynamicColor")
188 public void setDynamicColor(Color color) {
189 this.dynamicColor = color;
192 // public void setValue(String key, Object value) {
194 // if ("alpha".equals(key)) {
195 // Float val = Float.parseFloat((String)value);
196 // alphaComposite = AlphaComposite.getInstance(AlphaComposite. SRC_OVER, val);
197 // } else if ("width".equals(key)) {
198 // dynamicStroke = new BasicStroke(Float.parseFloat((String)value));
199 // } else if ("color".equals(key)) {
201 // dynamicColor = new Color(Integer.parseInt(value.toString(), 16));
202 // } catch (Throwable t) {
203 // t.printStackTrace();
209 public void initValues() {
210 dynamicStroke = null;
212 alphaComposite = null;