-/*******************************************************************************\r
- * Copyright (c) 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.diagram.connection.rendering;\r
-\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-import java.awt.BasicStroke;\r
-import java.awt.Color;\r
-import java.awt.Graphics2D;\r
-import java.awt.geom.Path2D;\r
-import java.io.Serializable;\r
-import java.util.List;\r
-\r
-import org.simantics.diagram.connection.RouteGraph;\r
-import org.simantics.diagram.connection.RouteLine;\r
-import org.simantics.diagram.connection.RoutePoint;\r
-import org.simantics.diagram.connection.RouteTerminal;\r
-import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;\r
-\r
-\r
-public class StyledRouteGraphRenderer implements IRouteGraphRenderer, Serializable {\r
-\r
- private static final BasicStroke GUIDE_LINE_STROKE = new BasicStroke(0.1f);\r
- private static final Color GUIDE_LINE_COLOR = new Color(255,255,255);\r
- \r
- private static final long serialVersionUID = 1564960933064029020L;\r
-\r
- protected final ConnectionStyle style;\r
-\r
- // Caches to avoid creating new objects all the time during rendering\r
- protected transient Path2D path;\r
- protected transient THashSet<RoutePoint> branchPoints;\r
-\r
- public StyledRouteGraphRenderer(ConnectionStyle style) {\r
- if (style == null)\r
- throw new NullPointerException("null style");\r
- this.style = style;\r
- }\r
-\r
- public ConnectionStyle getStyle() {\r
- return style;\r
- }\r
-\r
- @Override\r
- public void render(Graphics2D g, RouteGraph rg) {\r
- if (path == null)\r
- path = new Path2D.Double();\r
- path.reset();\r
- rg.getPath2D(path);\r
- style.drawPath(g, path, false);\r
-\r
- if (branchPoints == null)\r
- branchPoints = new THashSet<RoutePoint>();\r
- branchPoints.clear();\r
- for(RouteLine line : rg.getLines()) {\r
- renderLine(g, line, false);\r
- collectBranchPoints(line, branchPoints);\r
- }\r
- for(RouteLine line : rg.getTransientLines()) {\r
- renderLine(g, line, true);\r
- collectBranchPoints(line, branchPoints);\r
- }\r
-\r
- /*for(RouteTerminal terminal : rg.getTerminals())\r
- terminal.render(g);*/\r
- for(RoutePoint point : branchPoints) {\r
- style.drawBranchPoint(g, point.getX(), point.getY());\r
- }\r
- }\r
- \r
- private static void collectBranchPoints(RouteLine line, THashSet<RoutePoint> branchPoints) {\r
- List<RoutePoint> points = line.getPoints();\r
- for(int i=1;i<points.size()-1;++i) {\r
- RoutePoint point = points.get(i);\r
- branchPoints.add(point);\r
- }\r
- }\r
- \r
- private void renderLine(Graphics2D g, RouteLine line, boolean isTransient) {\r
- if(line.getPoints().size() == 0) {\r
- System.err.println("Route line does not contain any points (data = " + line.getData() + ").");\r
- return;\r
- }\r
- RoutePoint p1 = line.getBegin();\r
- RoutePoint p2 = line.getEnd();\r
- double x1 = p1.getX();\r
- double y1 = p1.getY();\r
- double x2 = p2.getX();\r
- double y2 = p2.getY();\r
- boolean isHorizontal = line.isHorizontal();\r
-// double length = isHorizontal ? x2-x1 : y2-y1; // original length before removing the endpoints\r
- if(isHorizontal) {\r
- if(p1 instanceof RouteTerminal) {\r
- RouteTerminal terminal = (RouteTerminal)p1;\r
- ILineEndStyle style = terminal.getRenderStyle();\r
- style.render(g, x1, y1, 2);\r
- x1 += style.getLineEndLength(0);\r
- }\r
- if(p2 instanceof RouteTerminal) {\r
- RouteTerminal terminal = (RouteTerminal)p2;\r
- ILineEndStyle style = terminal.getRenderStyle();\r
- style.render(g, x2, y2, 0);\r
- x2 -= style.getLineEndLength(2);\r
- }\r
- }\r
- else {\r
- if(p1 instanceof RouteTerminal) {\r
- RouteTerminal terminal = (RouteTerminal)p1;\r
- ILineEndStyle style = terminal.getRenderStyle();\r
- style.render(g, x1, y1, 3);\r
- y1 += style.getLineEndLength(1);\r
- }\r
- if(p2 instanceof RouteTerminal) {\r
- RouteTerminal terminal = (RouteTerminal)p2;\r
- ILineEndStyle style = terminal.getRenderStyle();\r
- style.render(g, x2, y2, 1);\r
- y2 -= style.getLineEndLength(3);\r
- }\r
- }\r
-// if(length <= style.getDegeneratedLineLength())\r
-// style.drawDegeneratedLine(g, 0.5*(x1+x2), 0.5*(y1+y2), isHorizontal, isTransient);\r
-// else\r
-// style.drawLine(g, x1, y1, x2, y2, isTransient);\r
- }\r
- \r
- @Override\r
- public void renderGuides(Graphics2D g, RouteGraph rg) {\r
- Path2D path = new Path2D.Double();\r
- for(RouteLine line : rg.getLines()) {\r
- RoutePoint p1 = line.getBegin();\r
- RoutePoint p2 = line.getEnd();\r
- double dx = p2.getX() - p1.getX();\r
- double dy = p2.getY() - p1.getY();\r
- double adx = Math.abs(dx);\r
- double ady = Math.abs(dy);\r
- if(adx > ady) {\r
- if(adx > 4)\r
- dx = 0.5*dx - Math.signum(dx);\r
- else\r
- dx *= 0.25;\r
- path.moveTo(p1.getX()+dx, p1.getY());\r
- path.lineTo(p2.getX()-dx, p2.getY());\r
- }\r
- else {\r
- if(ady > 4)\r
- dy = 0.5*dy - Math.signum(dy);\r
- else\r
- dy *= 0.25;\r
- path.moveTo(p1.getX(), p1.getY()+dy);\r
- path.lineTo(p2.getX(), p2.getY()-dy);\r
- }\r
- }\r
- g.setStroke(GUIDE_LINE_STROKE);\r
- g.setColor(GUIDE_LINE_COLOR);\r
- g.draw(path);\r
- }\r
-\r
- @Override\r
- public int hashCode() {\r
- return style.hashCode();\r
- }\r
-\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- StyledRouteGraphRenderer other = (StyledRouteGraphRenderer) obj;\r
- return style.equals(other.style);\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.connection.rendering;
+
+import gnu.trove.set.hash.THashSet;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.Path2D;
+import java.io.Serializable;
+import java.util.List;
+
+import org.simantics.diagram.connection.RouteGraph;
+import org.simantics.diagram.connection.RouteLine;
+import org.simantics.diagram.connection.RoutePoint;
+import org.simantics.diagram.connection.RouteTerminal;
+import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
+
+
+public class StyledRouteGraphRenderer implements IRouteGraphRenderer, Serializable {
+
+ private static final BasicStroke GUIDE_LINE_STROKE = new BasicStroke(0.1f);
+ private static final Color GUIDE_LINE_COLOR = new Color(255,255,255);
+
+ private static final long serialVersionUID = 1564960933064029020L;
+
+ protected final ConnectionStyle style;
+
+ private static class Cache {
+ Path2D path = new Path2D.Double();
+ THashSet<RoutePoint> branchPoints = new THashSet<>();
+ }
+
+ // Caches to avoid creating new objects all the time during rendering
+ protected static ThreadLocal<Cache> caches = ThreadLocal.withInitial(() -> new Cache());
+
+ public StyledRouteGraphRenderer(ConnectionStyle style) {
+ if (style == null)
+ throw new NullPointerException("null style");
+ this.style = style;
+ }
+
+ public ConnectionStyle getStyle() {
+ return style;
+ }
+
+ @Override
+ public void render(Graphics2D g, RouteGraph rg) {
+ Cache cache = caches.get();
+ Path2D path = cache.path;
+ THashSet<RoutePoint> branchPoints = cache.branchPoints;
+
+ path.reset();
+ rg.getPath2D(path);
+ style.drawPath(g, path, false);
+
+ branchPoints.clear();
+ for(RouteLine line : rg.getLines()) {
+ renderLine(g, line, false);
+ collectBranchPoints(line, branchPoints);
+ }
+ for(RouteLine line : rg.getTransientLines()) {
+ renderLine(g, line, true);
+ collectBranchPoints(line, branchPoints);
+ }
+
+ /*for(RouteTerminal terminal : rg.getTerminals())
+ terminal.render(g);*/
+ for(RoutePoint point : branchPoints) {
+ style.drawBranchPoint(g, point.getX(), point.getY());
+ }
+ }
+
+ private static void collectBranchPoints(RouteLine line, THashSet<RoutePoint> branchPoints) {
+ List<RoutePoint> points = line.getPoints();
+ for(int i=1;i<points.size()-1;++i) {
+ RoutePoint point = points.get(i);
+ branchPoints.add(point);
+ }
+ }
+
+ private void renderLine(Graphics2D g, RouteLine line, boolean isTransient) {
+ if(line.getPoints().size() == 0) {
+ System.err.println("Route line does not contain any points (data = " + line.getData() + ").");
+ return;
+ }
+ RoutePoint p1 = line.getBegin();
+ RoutePoint p2 = line.getEnd();
+ double x1 = p1.getX();
+ double y1 = p1.getY();
+ double x2 = p2.getX();
+ double y2 = p2.getY();
+ boolean isHorizontal = line.isHorizontal();
+// double length = isHorizontal ? x2-x1 : y2-y1; // original length before removing the endpoints
+ if(isHorizontal) {
+ if(p1 instanceof RouteTerminal) {
+ RouteTerminal terminal = (RouteTerminal)p1;
+ ILineEndStyle style = terminal.getRenderStyle();
+ style.render(g, x1, y1, 2);
+ x1 += style.getLineEndLength(0);
+ }
+ if(p2 instanceof RouteTerminal) {
+ RouteTerminal terminal = (RouteTerminal)p2;
+ ILineEndStyle style = terminal.getRenderStyle();
+ style.render(g, x2, y2, 0);
+ x2 -= style.getLineEndLength(2);
+ }
+ }
+ else {
+ if(p1 instanceof RouteTerminal) {
+ RouteTerminal terminal = (RouteTerminal)p1;
+ ILineEndStyle style = terminal.getRenderStyle();
+ style.render(g, x1, y1, 3);
+ y1 += style.getLineEndLength(1);
+ }
+ if(p2 instanceof RouteTerminal) {
+ RouteTerminal terminal = (RouteTerminal)p2;
+ ILineEndStyle style = terminal.getRenderStyle();
+ style.render(g, x2, y2, 1);
+ y2 -= style.getLineEndLength(3);
+ }
+ }
+// if(length <= style.getDegeneratedLineLength())
+// style.drawDegeneratedLine(g, 0.5*(x1+x2), 0.5*(y1+y2), isHorizontal, isTransient);
+// else
+// style.drawLine(g, x1, y1, x2, y2, isTransient);
+ }
+
+ @Override
+ public void renderGuides(Graphics2D g, RouteGraph rg) {
+ Path2D path = new Path2D.Double();
+ for(RouteLine line : rg.getLines()) {
+ RoutePoint p1 = line.getBegin();
+ RoutePoint p2 = line.getEnd();
+ double dx = p2.getX() - p1.getX();
+ double dy = p2.getY() - p1.getY();
+ double adx = Math.abs(dx);
+ double ady = Math.abs(dy);
+ if(adx > ady) {
+ if(adx > 4)
+ dx = 0.5*dx - Math.signum(dx);
+ else
+ dx *= 0.25;
+ path.moveTo(p1.getX()+dx, p1.getY());
+ path.lineTo(p2.getX()-dx, p2.getY());
+ }
+ else {
+ if(ady > 4)
+ dy = 0.5*dy - Math.signum(dy);
+ else
+ dy *= 0.25;
+ path.moveTo(p1.getX(), p1.getY()+dy);
+ path.lineTo(p2.getX(), p2.getY()-dy);
+ }
+ }
+ g.setStroke(GUIDE_LINE_STROKE);
+ g.setColor(GUIDE_LINE_COLOR);
+ g.draw(path);
+ }
+
+ @Override
+ public int hashCode() {
+ return style.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StyledRouteGraphRenderer other = (StyledRouteGraphRenderer) obj;
+ return style.equals(other.style);
+ }
+
+}