--- /dev/null
+/*******************************************************************************\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