]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java
b2121bf70128b358aada26990e75deae7a93b100
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / nodes / NetworkDrawingNode.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.Stroke;
7 import java.awt.geom.AffineTransform;
8 import java.awt.geom.Path2D;
9 import java.awt.geom.Point2D;
10 import java.awt.geom.Rectangle2D;
11 import java.util.ArrayList;
12 import java.util.Iterator;
13 import java.util.List;
14
15 import org.simantics.Simantics;
16 import org.simantics.db.Resource;
17 import org.simantics.db.WriteGraph;
18 import org.simantics.db.common.request.WriteRequest;
19 import org.simantics.db.exception.DatabaseException;
20 import org.simantics.diagram.elements.DiagramNodeUtil;
21 import org.simantics.diagram.ui.DiagramModelHints;
22 import org.simantics.district.network.ModelledCRS;
23 import org.simantics.district.network.ui.DNEdgeBuilder;
24 import org.simantics.district.network.ui.NetworkDrawingParticipant;
25 import org.simantics.g2d.canvas.Hints;
26 import org.simantics.g2d.canvas.ICanvasContext;
27 import org.simantics.g2d.canvas.IToolMode;
28 import org.simantics.g2d.diagram.IDiagram;
29 import org.simantics.scenegraph.g2d.G2DNode;
30 import org.simantics.scenegraph.g2d.events.EventTypes;
31 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
32 import org.simantics.scenegraph.g2d.events.MouseEvent;
33 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;
34 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;
35 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
36 import org.simantics.scenegraph.utils.GeometryUtils;
37 import org.simantics.scenegraph.utils.NodeUtil;
38
39 public class NetworkDrawingNode extends G2DNode {
40
41     private static final long serialVersionUID = -3475301184009620573L;
42     
43     private Point2D currentMousePos = null;
44     
45     private List<Point2D> nodes = new ArrayList<>();
46
47     private Resource diagramResource;
48
49     private boolean committed;
50
51     private NetworkDrawingParticipant participant;
52
53     private IDiagram diagram;
54
55     private static final Stroke DASHED_STROKE = new BasicStroke(2.0f,
56             BasicStroke.CAP_ROUND,
57             BasicStroke.JOIN_ROUND,
58             4.0f, new float[]{4.0f}, 0.0f);
59
60     private static final Color BLUE_ALPHA = new Color(0, 0, 255, 100);
61
62     private boolean scaleStroke = true;
63     
64     @Override
65     public void init() {
66         super.init();
67         addEventHandler(this);
68     }
69     
70     public void setNetworkDrawingParticipant(NetworkDrawingParticipant participant) {
71         this.participant = participant;
72     }
73     
74     public void setDiagram(IDiagram diagram) {
75         if (diagram != null) {
76             this.diagram = diagram;
77             this.diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
78         }
79     }
80
81     @Override
82     public void render(Graphics2D g2d) {
83         if (nodes.isEmpty())
84             return;
85         
86         Path2D path = new Path2D.Double();
87         Iterator<Point2D> nodeIter = nodes.iterator();
88         if (nodeIter.hasNext()) {
89             Point2D node = nodeIter.next();
90             path.moveTo(node.getX(), node.getY());
91         }
92         while (nodeIter.hasNext()) {
93             Point2D node = nodeIter.next();
94             path.lineTo(node.getX(), node.getY());
95         }
96         if (currentMousePos != null)
97             path.lineTo(currentMousePos.getX(), currentMousePos.getY());
98         
99         Color old = g2d.getColor();
100         Stroke oldStroke = g2d.getStroke();
101         
102         if (DASHED_STROKE != null) {
103             if (scaleStroke && DASHED_STROKE instanceof BasicStroke) {
104                 BasicStroke bs = GeometryUtils.scaleStroke(DASHED_STROKE, (float) (1.0 / GeometryUtils.getScale(g2d.getTransform())));
105                 g2d.setStroke(bs);
106             } else {
107                 g2d.setStroke(DASHED_STROKE);
108             }
109         }
110         
111         g2d.setColor(BLUE_ALPHA);
112
113         g2d.draw(path);
114         
115         g2d.setStroke(oldStroke);
116         g2d.setColor(old);
117     }
118
119     @Override
120     public Rectangle2D getBoundsInLocal() {
121         return null;
122     }
123     
124     @Override
125     public int getEventMask() {
126         return EventTypes.AnyMask;
127     }
128     
129     @Override
130     protected boolean mouseDoubleClicked(MouseDoubleClickedEvent e) {
131         // nodes to path2d
132         IToolMode mode = getToolMode();
133         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
134             Point2D start = null;
135             Point2D end = null;
136             Iterator<Point2D> nodeIter = nodes.iterator();
137             while (nodeIter.hasNext()) {
138                 if (end == null) {
139                     start = nodeIter.next();
140                     if (!nodeIter.hasNext()) {
141                         break;
142                     }
143                 } else {
144                     start = end;
145                 }
146                 
147                 end = nodeIter.next();
148                 
149                 createEdge(start, end);
150             }
151             
152             nodes.clear();
153             committed = true;
154             
155             repaint();
156             
157             return true;
158         }
159         return super.mouseDoubleClicked(e);
160     }
161
162     private void createEdge(Point2D start, Point2D end) {
163         
164         double currentPadding = DistrictNetworkVertexNode.width;
165         AffineTransform test = getTransform();
166         ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(this);
167         AffineTransform tr = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM);
168         AffineTransform testing = new AffineTransform(tr); 
169         testing.concatenate(test);
170         double calculateScaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(testing);
171         double padding = currentPadding * calculateScaleRecip;
172         /*
173          *  To convert y-coordinates to map coordinates in ruler, use:
174          *    double val = (y-offsetY)/scaleY;
175          *    val = Math.toDegrees(Math.atan(Math.sinh(Math.toRadians(val))));
176          *    String str = formatValue(val);
177          */
178         // TODO: fix scale
179         double scaleY = getTransform().getScaleY();
180         double scaleX = getTransform().getScaleX();
181         
182         double startLat = ModelledCRS.yToLatitude(-start.getY() / scaleY);
183         double startLon = ModelledCRS.xToLongitude(start.getX() / scaleX);
184         
185         double endLat = ModelledCRS.yToLatitude(-end.getY() / scaleY);
186         double endLon = ModelledCRS.xToLongitude(end.getX() / scaleX);
187         
188         double[] startCoords = new double[] { startLon, startLat };
189         double[] endCoords = new double[] { endLon, endLat };
190         
191         DNEdgeBuilder builder = new DNEdgeBuilder(diagramResource, diagram);
192         Simantics.getSession().asyncRequest(new WriteRequest() {
193             
194             @Override
195             public void perform(WriteGraph graph) throws DatabaseException {
196                 builder.create(graph, startCoords, 0, endCoords, 0, padding);
197             }
198         });
199         
200     }
201
202     @Override
203     protected boolean mouseClicked(MouseClickEvent e) {
204         // check ToolMode
205         IToolMode mode = getToolMode();
206         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
207             if (committed) {
208                 committed = false;
209                 return false;
210             }
211             if (e.button == MouseEvent.RIGHT_BUTTON && !nodes.isEmpty()) {
212                 nodes.remove(nodes.size() - 1);
213             } else if (e.button == MouseEvent.LEFT_BUTTON) {
214                 Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
215                 nodes.add(new Point2D.Double(localPos.getX(), localPos.getY()));
216             }
217             repaint();
218             return true;
219         }
220         return super.mouseClicked(e);
221     }
222     
223     private IToolMode getToolMode() {
224         return participant.getHint(Hints.KEY_TOOL);
225     }
226
227     @Override
228     protected boolean mouseMoved(MouseMovedEvent e) {
229         IToolMode mode = getToolMode();
230         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
231             boolean repaint = false;
232             Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
233             if (participant.pickHoveredElement(p)) {
234                 repaint = true;
235             }
236             if (!nodes.isEmpty()) {
237                 currentMousePos = p;
238                 
239                 repaint();
240                 return true;
241             }
242             currentMousePos = null;
243             if (repaint == true)
244                 repaint();
245         }
246         return super.mouseMoved(e);
247     }
248     
249     @Override
250     protected boolean keyPressed(KeyPressedEvent e) {
251         if (e.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) {
252             nodes.clear();
253             repaint();
254             return true;
255         }
256         return super.keyPressed(e);
257             
258     }
259 }