]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java
b1bb1468dd63653ee1c423a9653fbc307088bc8e
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / nodes / DistrictNetworkVertexNode.java
1 package org.simantics.district.network.ui.nodes;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Graphics2D;
6 import java.awt.RenderingHints;
7 import java.awt.geom.AffineTransform;
8 import java.awt.geom.Point2D;
9 import java.awt.geom.Rectangle2D;
10 import java.util.Optional;
11
12 import org.simantics.district.network.ui.adapters.DistrictNetworkVertex;
13 import org.simantics.maps.MapScalingTransform;
14 import org.simantics.scenegraph.INode;
15 import org.simantics.scenegraph.ISelectionPainterNode;
16 import org.simantics.scenegraph.g2d.G2DNode;
17 import org.simantics.scenegraph.g2d.G2DParentNode;
18 import org.simantics.scenegraph.g2d.G2DRenderingHints;
19 import org.simantics.scenegraph.g2d.IG2DNode;
20 import org.simantics.scenegraph.g2d.nodes.SVGNode;
21 import org.simantics.scenegraph.utils.GeometryUtils;
22 import org.simantics.scenegraph.utils.NodeUtil;
23
24 public class DistrictNetworkVertexNode extends G2DParentNode implements ISelectionPainterNode, HoverSensitiveNode {
25
26     //private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkVertexNode.class);
27
28     private static final long serialVersionUID = -2641639101400236719L;
29
30     private static final double left = -15;
31     private static final double top = left;
32     public static final double width = 30;
33     private static final double height = width;
34
35     private static final BasicStroke STROKE           = new BasicStroke((float)width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
36     private static final Color       SELECTION_COLOR  = new Color(255, 0, 255, 96);
37
38     private static final Rectangle2D NORMAL = new Rectangle2D.Double(left, top, width, height);
39     private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 2, top * 2, width * 2, height * 2);
40
41     private DistrictNetworkVertex vertex;
42
43     private static boolean scaleStroke = true;
44     private boolean hover;
45
46     private Color color;
47     private transient Color dynamicColor;
48
49     private Rectangle2D bounds;
50     private transient Point2D point;
51     private transient Rectangle2D rect;
52     private transient AffineTransform symbolTransform;
53
54     private double nodeSize = 1.0;
55
56     private boolean hidden = false;
57
58     @Override
59     public void init() {
60         setZIndex(2);
61     }
62
63     @Override
64     public void render(Graphics2D g2d) {
65         AffineTransform ot = null;
66         AffineTransform t = getTransform();
67         double viewScaleRecip = scaleStroke ? (Double) g2d.getRenderingHint(DistrictRenderingHints.KEY_VIEW_SCALE_RECIPROCAL_UNDER_SPATIAL_ROOT) : 1.0;
68         if (t != null && !t.isIdentity()) {
69             //ot = g2d.getTransform();
70             ot = (AffineTransform) g2d.getRenderingHint(G2DRenderingHints.KEY_TRANSFORM_UNDER_SPATIAL_ROOT);
71             if (ot == null)
72                 ot = g2d.getTransform();
73             g2d.transform(t);
74
75             if (scaleStroke) {
76                 AffineTransform work = DistrictNetworkNodeUtils.sharedTransform.get();
77                 work.setTransform(ot);
78                 work.concatenate(t);
79                 viewScaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(work);
80             }
81         }
82
83         // Translate lat and lon to X and Y
84         Point2D p = point = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), point);
85
86         if (!hidden && nodeSize > 0.0) {
87             Object oaaHint = null;
88             Object aaHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
89             if (aaHint != RenderingHints.VALUE_ANTIALIAS_OFF) {
90                 oaaHint = aaHint;
91                 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
92             }
93     
94             Color oldColor = g2d.getColor();
95             Color newColor = dynamicColor != null ? dynamicColor : color;
96             boolean changeColor = !oldColor.equals(newColor);
97     
98             double scaleRecip = viewScaleRecip * nodeSize;
99     
100             Rectangle2D toDraw = rect = DistrictNetworkNodeUtils.calculateDrawnGeometry(p, hover ? HOVERED : NORMAL, rect, scaleRecip);
101     
102             if (NodeUtil.isSelected(this, 1)) {
103                 changeColor = true;
104                 g2d.setColor(SELECTION_COLOR);
105                 BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float)viewScaleRecip);
106                 g2d.setStroke(ss);
107                 g2d.draw(toDraw);
108             }
109     
110             // render
111             if (changeColor)
112                 g2d.setColor(newColor);
113             g2d.fill(toDraw);
114             
115             // Reset settings
116             if (changeColor)
117                 g2d.setColor(oldColor);
118             if (oaaHint != null)
119                 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint);
120         }
121
122         // Render SVG symbol
123         for (INode nn : getNodes()) {
124             G2DNode g2dNode = (G2DNode)nn;
125             if (nn instanceof SVGNode) {
126                 Rectangle2D toDraw = rect = DistrictNetworkNodeUtils.calculateDrawnGeometry(p, hover ? HOVERED : NORMAL, rect, viewScaleRecip);
127                 symbolTransform = DistrictNetworkNodeUtils.getTransformToRectangle(toDraw, symbolTransform);
128                 g2dNode.setTransform(symbolTransform);
129             }
130             
131             g2dNode.render(g2d);
132         }
133         
134         if (ot != null)
135             g2d.setTransform(ot);
136     }
137
138     @Override
139     public Rectangle2D getBounds() {
140         return super.getBounds();
141     }
142
143     @Override
144     public Rectangle2D getBoundsInLocal() {
145         updateBounds();
146         return bounds;
147     }
148
149     private void updateBounds() {
150         Rectangle2D oldBounds = bounds;
151         if (oldBounds == null)
152             oldBounds = new Rectangle2D.Double();
153         bounds = calculateBounds(oldBounds);
154     }
155
156     @Override
157     public void setTransform(AffineTransform transform) {
158         super.setTransform(transform);
159         // Update bounds
160         updateBounds();
161     }
162
163     private Rectangle2D calculateBounds(Rectangle2D rect) {
164         Point2D calcPoint = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), point);
165         AffineTransform at = NodeUtil.getLocalToGlobalTransform(this);
166         at.concatenate(MapScalingTransform.INSTANCE);
167         double x = calcPoint.getX();
168         double y = calcPoint.getY();
169         double scaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(at);
170         double widthh = width * scaleRecip * nodeSize;
171         double heighth = height * scaleRecip * nodeSize;
172         if (rect == null)
173             rect = new Rectangle2D.Double();
174         rect.setRect(x - widthh/2, y - heighth/2, widthh, heighth);
175         return rect;
176     }
177
178     public void setVertex(DistrictNetworkVertex vertex) {
179         this.vertex = vertex;
180         updateBounds();
181     }
182
183     public DistrictNetworkVertex getVertex() {
184         return vertex;
185     }
186
187     @Override
188     public boolean hover(boolean hover, boolean isConnectionTool) {
189         // Only react to hover when the connection tool is active
190         boolean doHover = hover && isConnectionTool;
191         boolean changed = this.hover != doHover;
192         this.hover = doHover;
193         
194         for (IG2DNode child : getNodes()) {
195             if (child instanceof HoverSensitiveNode)
196                 changed = ((HoverSensitiveNode)child).hover(hover, isConnectionTool) || changed;
197         }
198         
199         return changed;
200     }
201     
202     @Override
203     public void setMousePosition(Point2D p) {
204         for (IG2DNode child : getNodes()) {
205             if (child instanceof HoverSensitiveNode)
206                 ((HoverSensitiveNode) child).setMousePosition(p);
207         }
208     }
209
210     public void setColor(Color color) {
211         this.color = color;
212     }
213
214     public Color getColor() {
215         return color;
216     }
217
218     @PropertySetter(value = "SVG")
219     public void setSVG(String value) {
220         for (INode nn : this.getNodes())
221             if (nn instanceof SVGNode)
222                 ((SVGNode)nn).setData(value);
223     }
224     
225     
226     @PropertySetter(value = "size")
227     public void setSize(Double size) {
228         boolean changed = false;
229         if (size != null) {
230             changed = size != this.nodeSize;
231             this.nodeSize = size;
232         } else {
233             changed = this.nodeSize != 1.0;
234             this.nodeSize = 1.0;
235         }
236         if (changed)
237             updateBounds();
238     }
239
240     @PropertySetter(value = "dynamicColor")
241     public void setDynamicColor(Color color) {
242         this.dynamicColor = color;
243     }
244
245     @PropertySetter(value = "hidden")
246     public void setHidden(Boolean value) {
247         this.hidden = value;
248     }
249
250     public void setStaticInformation(Optional<String> staticInformation) {
251         DistrictNetworkStaticInfoNode child = getOrCreateNode(DistrictNetworkStaticInfoNode.NODE_KEY, DistrictNetworkStaticInfoNode.class);
252         Point2D calculatePoint2D = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), null);
253         child.setLocation(calculatePoint2D, new Point2D.Double(1.0, 0.0));
254         if (staticInformation.isPresent()) {
255             child.setInfo(staticInformation.get());
256         } else {
257             child.setInfo(null);
258         }
259     }
260     
261     public void setInSimulation(Optional<Boolean> isInSimulation) {
262         if (!isInSimulation.isPresent()) {
263             removeNode(NotInSimulationNode.NODE_NAME);
264         } else {
265             NotInSimulationNode child = getOrCreateNode(NotInSimulationNode.NODE_NAME, NotInSimulationNode.class);
266             child.setZIndex(1000);
267             child.setIsInSimulation(isInSimulation.get());
268         }
269     }
270 }