]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/StyledRouteGraphRenderer.java
Configurable connection crossing styles
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / rendering / StyledRouteGraphRenderer.java
1 /*******************************************************************************
2  * Copyright (c) 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.connection.rendering;
13
14 import gnu.trove.set.hash.THashSet;
15
16 import java.awt.BasicStroke;
17 import java.awt.Color;
18 import java.awt.Graphics2D;
19 import java.awt.geom.Path2D;
20 import java.io.Serializable;
21 import java.util.List;
22
23 import org.simantics.diagram.connection.RouteGraph;
24 import org.simantics.diagram.connection.RouteLine;
25 import org.simantics.diagram.connection.RoutePoint;
26 import org.simantics.diagram.connection.RouteTerminal;
27 import org.simantics.diagram.connection.rendering.arrows.ILineEndStyle;
28
29
30 public class StyledRouteGraphRenderer implements IRouteGraphRenderer, Serializable {
31
32     private static final BasicStroke GUIDE_LINE_STROKE = new BasicStroke(0.1f);
33     private static final Color GUIDE_LINE_COLOR = new Color(255,255,255);
34     
35         private static final long serialVersionUID = 1564960933064029020L;
36
37         protected final ConnectionStyle style;
38
39         private static class Cache {
40                 Path2D path = new Path2D.Double();
41                 THashSet<RoutePoint> branchPoints = new THashSet<>();
42         }
43
44         // Caches to avoid creating new objects all the time during rendering
45         protected static ThreadLocal<Cache> caches = ThreadLocal.withInitial(() -> new Cache());
46
47         public StyledRouteGraphRenderer(ConnectionStyle style) {
48                 if (style == null)
49                         throw new NullPointerException("null style");
50                 this.style = style;
51         }
52
53         public ConnectionStyle getStyle() {
54                 return style;
55         }
56
57         @Override
58         public void render(Graphics2D g, RouteGraph rg) {
59                 Cache cache = caches.get();
60                 Path2D path = cache.path;
61                 THashSet<RoutePoint> branchPoints = cache.branchPoints;
62
63                 path.reset();
64                 rg.getPath2D(path);
65                 PathModifier pm = (PathModifier) g.getRenderingHint(ConnectionRenderingHints.KEY_PATH_MODIFIER);
66                 if (pm != null) {
67                         path = pm.modify(path);
68                 }
69                 style.drawPath(g, path, false);
70
71                 branchPoints.clear();
72                 for(RouteLine line : rg.getLines()) {
73                     renderLine(g, line, false);
74                     collectBranchPoints(line, branchPoints);
75                 }
76                 for(RouteLine line : rg.getTransientLines()) {
77                         renderLine(g, line, true);
78                         collectBranchPoints(line, branchPoints);
79                 }
80
81                 /*for(RouteTerminal terminal : rg.getTerminals())
82                         terminal.render(g);*/
83                 for(RoutePoint point : branchPoints) {
84                         style.drawBranchPoint(g, point.getX(), point.getY());
85                 }
86         }
87         
88         private static void collectBranchPoints(RouteLine line, THashSet<RoutePoint> branchPoints) {
89                 List<RoutePoint> points = line.getPoints();
90                 for(int i=1;i<points.size()-1;++i) {
91                         RoutePoint point = points.get(i);
92                         branchPoints.add(point);
93                 }
94         }
95         
96         private void renderLine(Graphics2D g, RouteLine line, boolean isTransient) {
97             if(line.getPoints().size() == 0) {
98                 System.err.println("Route line does not contain any points (data = " + line.getData() + ").");
99                 return;
100             }
101                 RoutePoint p1 = line.getBegin();
102                 RoutePoint p2 = line.getEnd();
103                 double x1 = p1.getX();
104                 double y1 = p1.getY();
105                 double x2 = p2.getX();
106                 double y2 = p2.getY();
107                 boolean isHorizontal = line.isHorizontal();
108 //              double length = isHorizontal ? x2-x1 : y2-y1; // original length before removing the endpoints
109                 if(isHorizontal) {
110                         if(p1 instanceof RouteTerminal) {
111                                 RouteTerminal terminal = (RouteTerminal)p1;
112                                 ILineEndStyle style = terminal.getRenderStyle();
113                                 style.render(g, x1, y1, 2);
114                                 x1 += style.getLineEndLength(0);
115                         }
116                         if(p2 instanceof RouteTerminal) {
117                                 RouteTerminal terminal = (RouteTerminal)p2;
118                                 ILineEndStyle style = terminal.getRenderStyle();
119                                 style.render(g, x2, y2, 0);
120                                 x2 -= style.getLineEndLength(2);
121                         }
122                 }
123                 else {
124                         if(p1 instanceof RouteTerminal) {
125                                 RouteTerminal terminal = (RouteTerminal)p1;
126                                 ILineEndStyle style = terminal.getRenderStyle();
127                                 style.render(g, x1, y1, 3);
128                                 y1 += style.getLineEndLength(1);
129                         }
130                         if(p2 instanceof RouteTerminal) {
131                                 RouteTerminal terminal = (RouteTerminal)p2;
132                                 ILineEndStyle style = terminal.getRenderStyle();
133                                 style.render(g, x2, y2, 1);
134                                 y2 -= style.getLineEndLength(3);
135                         }
136                 }
137 //              if(length <= style.getDegeneratedLineLength())
138 //                      style.drawDegeneratedLine(g, 0.5*(x1+x2), 0.5*(y1+y2), isHorizontal, isTransient);
139 //              else
140 //                      style.drawLine(g, x1, y1, x2, y2, isTransient);
141         }
142         
143         @Override
144         public void renderGuides(Graphics2D g, RouteGraph rg) {
145             Path2D path = new Path2D.Double();
146         for(RouteLine line : rg.getLines()) {
147             RoutePoint p1 = line.getBegin();
148             RoutePoint p2 = line.getEnd();
149             double dx = p2.getX() - p1.getX();
150             double dy = p2.getY() - p1.getY();
151             double adx = Math.abs(dx);
152             double ady = Math.abs(dy);
153             if(adx > ady) {
154                 if(adx > 4)
155                     dx = 0.5*dx - Math.signum(dx);
156                 else
157                     dx *= 0.25;
158                 path.moveTo(p1.getX()+dx, p1.getY());
159                 path.lineTo(p2.getX()-dx, p2.getY());
160             }
161             else {
162                 if(ady > 4)
163                     dy = 0.5*dy - Math.signum(dy);
164                 else
165                     dy *= 0.25;
166                 path.moveTo(p1.getX(), p1.getY()+dy);
167                 path.lineTo(p2.getX(), p2.getY()-dy);
168             }
169         }
170         g.setStroke(GUIDE_LINE_STROKE);
171         g.setColor(GUIDE_LINE_COLOR);
172         g.draw(path);
173         }
174
175         @Override
176         public int hashCode() {
177                 return style.hashCode();
178         }
179
180         @Override
181         public boolean equals(Object obj) {
182                 if (this == obj)
183                         return true;
184                 if (obj == null)
185                         return false;
186                 if (getClass() != obj.getClass())
187                         return false;
188                 StyledRouteGraphRenderer other = (StyledRouteGraphRenderer) obj;
189                 return style.equals(other.style);
190         }
191
192 }