package org.simantics.sysdyn.ui.elements;\r
\r
-import java.awt.Shape;\r
import java.awt.geom.Path2D;\r
import java.awt.geom.Rectangle2D;\r
\r
@GraphType("http://www.simantics.org/Sysdyn#Flow")\r
public class FlowElement extends Element implements IElementListener {\r
\r
- public static double ARROW_LENGTH1 = 0.2;\r
- public static double ARROW_LENGTH2 = 3.0;\r
- public static double ARROW_WIDTH = 1.8;\r
- \r
+ public static double ARROW_LENGTH = 3.2;\r
+ public static double ARROW_WIDTH = 3;\r
+\r
static final double OFFSET = 1.5;\r
- \r
- /*\r
- * Total length of the arrow is ARROW_LENGTH1 + ARROW_LENGTH2\r
- */ \r
+ static final double ARROW_OFFSET = 3.2;\r
+\r
+ /*\r
+ * Total length of the arrow is ARROW_LENGTH1 + ARROW_LENGTH2\r
+ */ \r
@RelatedElement("http://www.simantics.org/Sysdyn#HasTail")\r
- Connectable tail;\r
+ Connectable tail;\r
@RelatedElement("http://www.simantics.org/Sysdyn#HasHead")\r
- Connectable head;\r
- double angle = 0.1;\r
-\r
- // Auxiliary \r
- double angle0;\r
- double angle1;\r
- double cx;\r
- double cy;\r
- double r;\r
- \r
- // Scene graph\r
- ShapeNode lineNode1;\r
- ShapeNode lineNode2;\r
- FilledShapeNode arrowNode;\r
- \r
- public FlowElement() { \r
- }\r
- \r
- public FlowElement(Connectable tail, Connectable head) {\r
- super();\r
- this.tail = tail;\r
- this.head = head;\r
- }\r
- \r
- @Override\r
- public void elementUpdated(IElement element) {\r
- update(); \r
- } \r
-\r
- @Override\r
- public void remove() {\r
- lineNode1.remove();\r
- lineNode2.remove();\r
- tail.removeListener(this);\r
- head.removeListener(this);\r
- }\r
-\r
- @Override\r
- public void init(G2DParentNode parent) {\r
- tail.addListener(this);\r
- head.addListener(this);\r
- \r
- lineNode1 = parent.addNode(ShapeNode.class);\r
- lineNode1.setScaleStroke(true);\r
- lineNode2 = parent.addNode(ShapeNode.class);\r
- lineNode2.setScaleStroke(true);\r
- \r
- //arrowNode = parent.addNode(FilledShapeNode.class);\r
- update();\r
- }\r
- \r
- protected Shape createArrow(double x, double y, double dx, double dy) {\r
+ Connectable head;\r
+ double angle = 0.1;\r
+\r
+ // Auxiliary \r
+ double angle0;\r
+ double angle1;\r
+ double cx;\r
+ double cy;\r
+ double r;\r
+\r
+ // Scene graph\r
+ ShapeNode lineNode1;\r
+ ShapeNode lineNode2;\r
+ FilledShapeNode arrowNode;\r
+\r
+ public FlowElement() { \r
+ }\r
+\r
+ public FlowElement(Connectable tail, Connectable head) {\r
+ super();\r
+ this.tail = tail;\r
+ this.head = head;\r
+ }\r
+\r
+ @Override\r
+ public void elementUpdated(IElement element) {\r
+ update(); \r
+ } \r
+\r
+ @Override\r
+ public void remove() {\r
+ lineNode1.remove();\r
+ lineNode2.remove();\r
+ tail.removeListener(this);\r
+ head.removeListener(this);\r
+ }\r
+\r
+ @Override\r
+ public void init(G2DParentNode parent) {\r
+ tail.addListener(this);\r
+ head.addListener(this);\r
+\r
+ lineNode1 = parent.addNode(ShapeNode.class);\r
+ lineNode1.setScaleStroke(true);\r
+ lineNode2 = parent.addNode(ShapeNode.class);\r
+ lineNode2.setScaleStroke(true);\r
+\r
+ arrowNode = parent.addNode(FilledShapeNode.class);\r
+ update();\r
+ }\r
+\r
+ protected void createArrow(Connectable head, Connectable tail) { \r
+ double x = tail.getOrigo().getX();\r
+ double y = tail.getOrigo().getY();\r
+\r
+ Rectangle2D rect = new Rectangle2D.Double();\r
+ head.getBounds(rect);\r
+ double cx = rect.getCenterX();\r
+ double minx = rect.getMinX();\r
+ double maxx = rect.getMaxX();\r
+ double miny = rect.getMinY();\r
+ double maxy = rect.getMaxY();\r
+\r
Path2D path = new Path2D.Double();\r
- path.moveTo(x+ARROW_LENGTH1*dx, y+ARROW_LENGTH1*dy);\r
- x -= ARROW_LENGTH2*dx;\r
- y -= ARROW_LENGTH2*dy;\r
- path.lineTo(x-ARROW_WIDTH*dy, y+ARROW_WIDTH*dx);\r
- path.lineTo(x+ARROW_WIDTH*dy, y-ARROW_WIDTH*dx);\r
+\r
+ // approach from top\r
+ if (y < miny) {\r
+ path.moveTo(cx, miny);\r
+ path.lineTo(cx + ARROW_WIDTH, miny - ARROW_LENGTH);\r
+ path.lineTo(cx - ARROW_WIDTH, miny - ARROW_LENGTH);\r
+ } \r
+\r
+ // approach from beneath\r
+ else if (y > maxy) {\r
+ path.moveTo(cx, maxy);\r
+ path.lineTo(cx + ARROW_WIDTH, maxy + ARROW_LENGTH);\r
+ path.lineTo(cx - ARROW_WIDTH, maxy + ARROW_LENGTH);\r
+ }\r
+\r
+ // approach from left\r
+ else if (x < minx) {\r
+ path.moveTo(minx, y);\r
+ path.lineTo(minx - ARROW_LENGTH, y - ARROW_WIDTH);\r
+ path.lineTo(minx - ARROW_LENGTH, y + ARROW_WIDTH);\r
+ }\r
+\r
+ // approach from right\r
+ else if (x > maxx) {\r
+ path.moveTo(maxx, y);\r
+ path.lineTo(maxx + ARROW_LENGTH, y - ARROW_WIDTH);\r
+ path.lineTo(maxx + ARROW_LENGTH, y + ARROW_WIDTH);\r
+ }\r
+\r
path.closePath();\r
- return path;\r
+ arrowNode.setShape(path);\r
}\r
- \r
- // TODO\r
- \r
- private void draw(boolean vertical, double ... coordinates) {\r
- lineNode1.setShape(Flows.createOffsetLine(vertical, OFFSET, coordinates));\r
- lineNode2.setShape(Flows.createOffsetLine(vertical, -OFFSET, coordinates));\r
- }\r
-\r
- private void draw(Connectable valve, Connectable node) {\r
- double x0 = valve.getOrigo().getX();\r
- double y0 = valve.getOrigo().getY(); \r
- double x1 = node.getOrigo().getX();\r
- double y1 = node.getOrigo().getY();\r
-\r
- Rectangle2D rect = new Rectangle2D.Double();\r
- node.getBounds(rect);\r
- if( ((ValveElement)valve).rotated ) {\r
- if(y1 > y0)\r
- y0 += OFFSET;\r
- else\r
- y0 -= OFFSET;\r
- if(rect.getMinX() <= x0 && rect.getMaxX() >= x0) {\r
- if(y1 > y0)\r
- draw(true, y0, x0, rect.getMinY());\r
- else\r
- draw(true, y0, x0, rect.getMaxY());\r
- }\r
- else {\r
- if(x1 > x0)\r
- draw(true, y0, x0, y1, rect.getMinX());\r
- else\r
- draw(true, y0, x0, y1, rect.getMaxX());\r
- }\r
- }\r
- else {\r
- if(x1 > x0)\r
- x0 += OFFSET;\r
- else\r
- x0 -= OFFSET;\r
- if(rect.getMinY() <= y0 && rect.getMaxY() >= y0) {\r
- if(x1 > x0)\r
- draw(false, x0, y0, rect.getMinX());\r
- else\r
- draw(false, x0, y0, rect.getMaxX());\r
- }\r
- else {\r
- if(y1 > y0)\r
- draw(false, x0, y0, x1, rect.getMinY());\r
- else\r
- draw(false, x0, y0, x1, rect.getMaxY());\r
- }\r
- }\r
- }\r
-\r
- protected void updateSceneGraph() {\r
- if(tail instanceof ValveElement)\r
- draw(tail, head);\r
- else if(head instanceof ValveElement)\r
- draw(head, tail);\r
- }\r
- \r
- // TODO\r
- \r
- public void update() {\r
- if(lineNode1 != null)\r
- updateSceneGraph();\r
- super.update();\r
- }\r
- \r
- @Override\r
- public void getBounds(Rectangle2D bounds) {\r
- bounds.setFrame(lineNode1.getBounds());\r
- }\r
-\r
- @Override\r
- public boolean hitTest(double x, double y, double tolerance) {\r
+\r
+ // TODO\r
+\r
+ private void draw(boolean vertical, double ... coordinates) {\r
+ lineNode1.setShape(Flows.createOffsetLine(vertical, OFFSET, coordinates));\r
+ lineNode2.setShape(Flows.createOffsetLine(vertical, -OFFSET, coordinates));\r
+ }\r
+\r
+ private void draw(boolean hasArrow, Connectable valve, Connectable node) {\r
+ double x0 = valve.getOrigo().getX();\r
+ double y0 = valve.getOrigo().getY(); \r
+ double x1 = node.getOrigo().getX();\r
+ double y1 = node.getOrigo().getY();\r
+\r
+ Rectangle2D rect = new Rectangle2D.Double();\r
+ node.getBounds(rect);\r
+ \r
+ double minY = hasArrow ? rect.getMinY() - ARROW_OFFSET : rect.getMinY();\r
+ double maxY = hasArrow ? rect.getMaxY() + ARROW_OFFSET : rect.getMaxY();\r
+ double minX = hasArrow ? rect.getMinX() - ARROW_OFFSET : rect.getMinX();\r
+ double maxX = hasArrow ? rect.getMaxX() + ARROW_OFFSET : rect.getMaxX();\r
+ \r
+ \r
+ if( ((ValveElement)valve).rotated ) {\r
+ if(y1 > y0)\r
+ y0 += OFFSET;\r
+ else\r
+ y0 -= OFFSET;\r
+ if(rect.getMinX() <= x0 && rect.getMaxX() >= x0) {\r
+ if(y1 > y0)\r
+ draw(true, y0, x0, minY);\r
+ else\r
+ draw(true, y0, x0, maxY);\r
+ }\r
+ else {\r
+ if(x1 > x0)\r
+ draw(true, y0, x0, y1, minX);\r
+ else\r
+ draw(true, y0, x0, y1, maxX);\r
+ }\r
+ }\r
+ else {\r
+ if(x1 > x0)\r
+ x0 += OFFSET;\r
+ else\r
+ x0 -= OFFSET;\r
+ if(rect.getMinY() <= y0 && rect.getMaxY() >= y0) {\r
+ if(x1 > x0)\r
+ draw(false, x0, y0, minX);\r
+ else\r
+ draw(false, x0, y0, maxX);\r
+ }\r
+ else {\r
+ if(y1 > y0)\r
+ draw(false, x0, y0, x1, minY);\r
+ else\r
+ draw(false, x0, y0, x1, maxY);\r
+ }\r
+ }\r
+\r
+\r
+ }\r
+\r
+ protected void updateSceneGraph() {\r
+ boolean hasArrow = tail instanceof ValveElement && !(head instanceof ValveElement);\r
+ if(tail instanceof ValveElement)\r
+ draw(hasArrow, tail, head);\r
+ else if(head instanceof ValveElement)\r
+ draw(hasArrow, head, tail);\r
+ if(hasArrow)\r
+ createArrow(head, tail);\r
+ }\r
+\r
+ // TODO\r
+\r
+ public void update() {\r
+ if(lineNode1 != null)\r
+ updateSceneGraph();\r
+ super.update();\r
+ }\r
+\r
+ @Override\r
+ public void getBounds(Rectangle2D bounds) {\r
+ bounds.setFrame(lineNode1.getBounds());\r
+ }\r
+\r
+ @Override\r
+ public boolean hitTest(double x, double y, double tolerance) {\r
// TODO\r
return false;\r
- }\r
-\r
- @Override\r
- public <T> T getInterface(Class<T> clazz) { \r
- return super.getInterface(clazz);\r
- }\r
-\r
- @Override\r
- public void elementRemoved(IElement element) {\r
- remove(); \r
- }\r
- \r
+ }\r
+\r
+ @Override\r
+ public <T> T getInterface(Class<T> clazz) { \r
+ return super.getInterface(clazz);\r
+ }\r
+\r
+ @Override\r
+ public void elementRemoved(IElement element) {\r
+ remove(); \r
+ }\r
+\r
}\r