1 package org.simantics.district.network.ui.nodes;
3 import java.awt.BasicStroke;
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;
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;
39 public class NetworkDrawingNode extends G2DNode {
41 private static final long serialVersionUID = -3475301184009620573L;
43 private Point2D currentMousePos = null;
45 private List<Point2D> nodes = new ArrayList<>();
47 private Resource diagramResource;
49 private boolean committed;
51 private NetworkDrawingParticipant participant;
53 private IDiagram diagram;
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);
60 private static final Color BLUE_ALPHA = new Color(0, 0, 255, 100);
62 private boolean scaleStroke = true;
67 addEventHandler(this);
70 public void setNetworkDrawingParticipant(NetworkDrawingParticipant participant) {
71 this.participant = participant;
74 public void setDiagram(IDiagram diagram) {
75 if (diagram != null) {
76 this.diagram = diagram;
77 this.diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
82 public void render(Graphics2D g2d) {
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());
92 while (nodeIter.hasNext()) {
93 Point2D node = nodeIter.next();
94 path.lineTo(node.getX(), node.getY());
96 if (currentMousePos != null)
97 path.lineTo(currentMousePos.getX(), currentMousePos.getY());
99 Color old = g2d.getColor();
100 Stroke oldStroke = g2d.getStroke();
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())));
107 g2d.setStroke(DASHED_STROKE);
111 g2d.setColor(BLUE_ALPHA);
115 g2d.setStroke(oldStroke);
120 public Rectangle2D getBoundsInLocal() {
125 public int getEventMask() {
126 return EventTypes.AnyMask;
130 protected boolean mouseDoubleClicked(MouseDoubleClickedEvent e) {
132 IToolMode mode = getToolMode();
133 if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
134 Point2D start = null;
136 Iterator<Point2D> nodeIter = nodes.iterator();
137 while (nodeIter.hasNext()) {
139 start = nodeIter.next();
140 if (!nodeIter.hasNext()) {
147 end = nodeIter.next();
149 createEdge(start, end);
159 return super.mouseDoubleClicked(e);
162 private void createEdge(Point2D start, Point2D end) {
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;
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);
179 double scaleY = getTransform().getScaleY();
180 double scaleX = getTransform().getScaleX();
182 double startLat = ModelledCRS.yToLatitude(-start.getY() / scaleY);
183 double startLon = ModelledCRS.xToLongitude(start.getX() / scaleX);
185 double endLat = ModelledCRS.yToLatitude(-end.getY() / scaleY);
186 double endLon = ModelledCRS.xToLongitude(end.getX() / scaleX);
188 double[] startCoords = new double[] { startLon, startLat };
189 double[] endCoords = new double[] { endLon, endLat };
191 DNEdgeBuilder builder = new DNEdgeBuilder(diagramResource, diagram);
192 Simantics.getSession().asyncRequest(new WriteRequest() {
195 public void perform(WriteGraph graph) throws DatabaseException {
196 builder.create(graph, startCoords, 0, endCoords, 0, padding);
203 protected boolean mouseClicked(MouseClickEvent e) {
205 IToolMode mode = getToolMode();
206 if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
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()));
220 return super.mouseClicked(e);
223 private IToolMode getToolMode() {
224 return participant.getHint(Hints.KEY_TOOL);
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)) {
236 if (!nodes.isEmpty()) {
242 currentMousePos = null;
246 return super.mouseMoved(e);
250 protected boolean keyPressed(KeyPressedEvent e) {
251 if (e.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) {
256 return super.keyPressed(e);