]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram.connection/src/org/simantics/diagram/connection/rendering/BasicConnectionStyle.java
(refs #7177) Rounded connections
[simantics/platform.git] / bundles / org.simantics.diagram.connection / src / org / simantics / diagram / connection / rendering / BasicConnectionStyle.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 java.awt.Color;
15 import java.awt.Graphics2D;
16 import java.awt.RenderingHints;
17 import java.awt.Stroke;
18 import java.awt.geom.AffineTransform;
19 import java.awt.geom.Ellipse2D;
20 import java.awt.geom.Line2D;
21 import java.awt.geom.Path2D;
22 import java.awt.geom.PathIterator;
23 import java.io.Serializable;
24
25 /**
26  * @author Tuukka Lehtonen
27  */
28 public class BasicConnectionStyle implements ConnectionStyle, Serializable {
29
30     private static final long serialVersionUID = -5799681720482456895L;
31
32     // line thickness in millimeters.
33     final Color                     lineColor;
34     final Color                     branchPointColor;
35     final double                    branchPointRadius;
36     final Stroke                    lineStroke;
37     final Stroke                    routeLineStroke;
38     final double                    degenerateLineLength;
39     final double                    rounding;
40
41     transient Line2D          line             = new Line2D.Double();
42     transient Ellipse2D       ellipse          = new Ellipse2D.Double();
43
44     public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength,
45             double rounding) {
46         this.lineColor = lineColor;
47         this.branchPointColor = branchPointColor;
48         this.branchPointRadius = branchPointRadius;
49         this.lineStroke = lineStroke;
50         this.routeLineStroke = routeLineStroke;
51         this.degenerateLineLength = degenerateLineLength;
52         this.rounding = rounding;
53     }
54     
55     public BasicConnectionStyle(Color lineColor, Color branchPointColor, double branchPointRadius, Stroke lineStroke, Stroke routeLineStroke, double degenerateLineLength) {
56         this(lineColor, branchPointColor, branchPointRadius, lineStroke, routeLineStroke, degenerateLineLength, 0.0);
57     }
58
59     public Color getLineColor() {
60         return lineColor;
61     }
62     
63     public Color getBranchPointColor() {
64         return branchPointColor;
65     }
66     
67     public double getBranchPointRadius() {
68         return branchPointRadius;
69     }
70     
71     public Stroke getLineStroke() {
72         return lineStroke;
73     }
74     
75     public Stroke getRouteLineStroke() {
76         return routeLineStroke;
77     }
78
79     @Override
80     public void drawLine(Graphics2D g, double x1, double y1, double x2,
81             double y2, boolean isTransient) {
82         if (lineColor != null)
83             g.setColor(lineColor);
84         if(isTransient) {
85             g.setStroke(lineStroke);
86             line.setLine(x1, y1, x2, y2);
87             g.draw(line);
88         } else {
89             g.setStroke(routeLineStroke);
90             line.setLine(x1, y1, x2, y2);
91             g.draw(line);
92         }
93     }
94
95     @Override
96     public void drawPath(Graphics2D g, Path2D path, boolean isTransient) {
97         if (lineColor != null)
98             g.setColor(lineColor);
99         if (lineStroke != null)
100             g.setStroke(lineStroke);
101         if(rounding > 0.0) {
102             Object oldRenderingHint = g.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
103             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
104             g.draw(round(path));
105             g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldRenderingHint);
106         }
107         else
108             g.draw(path);
109     }
110     
111     private Path2D round(Path2D path) {
112         Path2D newPath = new Path2D.Double();
113         PathIterator it = path.getPathIterator(new AffineTransform());
114         double[] coords = new double[6];
115         double newX=0.0, newY=0.0;
116         double curX=0.0, curY=0.0;
117         double oldX=0.0, oldY=0.0;
118         int state = 0;
119         while(!it.isDone()) {
120             int type = it.currentSegment(coords);
121             if(type == PathIterator.SEG_LINETO) {
122                 newX = coords[0];
123                 newY = coords[1];
124                 if(state == 1) {
125                     double dx1 = curX-oldX;
126                     double dy1 = curY-oldY;
127                     double dx2 = curX-newX;
128                     double dy2 = curY-newY;
129                     double maxRadius = 0.5 * Math.min(Math.sqrt(dx1*dx1 + dy1*dy1), Math.sqrt(dx2*dx2 + dy2*dy2));
130                     double radius = Math.min(rounding, maxRadius);
131                     newPath.lineTo(curX + radius*Math.signum(oldX-curX), curY + radius*Math.signum(oldY-curY));
132                     newPath.curveTo(curX, curY,
133                                     curX, curY,
134                                     curX + radius*Math.signum(newX-curX), curY + radius*Math.signum(newY-curY));
135
136                     //newPath.lineTo(curX + round*Math.signum(oldX-curX), curY + round*Math.signum(oldY-curY));
137                     //newPath.lineTo(curX + round*Math.signum(newX-curX), curY + round*Math.signum(newY-curY));
138                     //newPath.lineTo(curX, curY);
139                 }
140                 else
141                     ++state;
142                 oldX = curX;
143                 oldY = curY;
144                 curX = newX;
145                 curY = newY;   
146             }
147             else {
148                 if(state > 0) {
149                     newPath.lineTo(curX, curY);
150                     state = 0;
151                 }
152                 switch(type) {
153                 case PathIterator.SEG_MOVETO:
154                     curX = coords[0];
155                     curY = coords[1];
156                     newPath.moveTo(curX, curY);
157                     break;
158                 case PathIterator.SEG_QUADTO:
159                     curX = coords[2];
160                     curY = coords[3];
161                     newPath.quadTo(coords[0], coords[1], coords[2], coords[3]);
162                     break;
163                 case PathIterator.SEG_CUBICTO:
164                     curX = coords[4];
165                     curY = coords[5];
166                     newPath.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
167                     break;
168                 case PathIterator.SEG_CLOSE:
169                     newPath.closePath();
170                     break;
171                 }
172             }
173             it.next();
174         }
175         if(state > 0)
176             newPath.lineTo(curX, curY);
177         return newPath;
178     }
179
180     @Override
181     public void drawBranchPoint(Graphics2D g, double x, double y) {
182         g.setColor(branchPointColor);
183         double r = branchPointRadius;
184         double d = 2*r;
185         ellipse.setFrame(x-r, y-r, d, d);
186         g.fill(ellipse);
187     }
188
189     @Override
190     public void drawDegeneratedLine(Graphics2D g, double x, double y,
191             boolean isHorizontal, boolean isTransient) {
192         double d = getDegeneratedLineLength()*0.5;
193         if(isHorizontal) {
194             line.setLine(x-d, y, x+d, y);
195             g.draw(line);
196         } else {
197             line.setLine(x, y-d, x, y+d);
198             g.draw(line);
199         }
200     }
201
202     @Override
203     public double getDegeneratedLineLength() {
204         return degenerateLineLength;
205     }
206
207     @Override
208     public int hashCode() {
209         final int prime = 31;
210         int result = 1;
211         result = prime * result + ((branchPointColor == null) ? 0 : branchPointColor.hashCode());
212         long temp;
213         temp = Double.doubleToLongBits(branchPointRadius);
214         result = prime * result + (int) (temp ^ (temp >>> 32));
215         temp = Double.doubleToLongBits(degenerateLineLength);
216         result = prime * result + (int) (temp ^ (temp >>> 32));
217         result = prime * result + ((lineColor == null) ? 0 : lineColor.hashCode());
218         result = prime * result + ((lineStroke == null) ? 0 : lineStroke.hashCode());
219         result = prime * result + ((routeLineStroke == null) ? 0 : routeLineStroke.hashCode());
220         return result;
221     }
222
223     @Override
224     public boolean equals(Object obj) {
225         if (this == obj)
226             return true;
227         if (obj == null)
228             return false;
229         if (getClass() != obj.getClass())
230             return false;
231         BasicConnectionStyle other = (BasicConnectionStyle) obj;
232         if (branchPointColor == null) {
233             if (other.branchPointColor != null)
234                 return false;
235         } else if (!branchPointColor.equals(other.branchPointColor))
236             return false;
237         if (Double.doubleToLongBits(branchPointRadius) != Double.doubleToLongBits(other.branchPointRadius))
238             return false;
239         if (Double.doubleToLongBits(degenerateLineLength) != Double.doubleToLongBits(other.degenerateLineLength))
240             return false;
241         if (lineColor == null) {
242             if (other.lineColor != null)
243                 return false;
244         } else if (!lineColor.equals(other.lineColor))
245             return false;
246         if (lineStroke == null) {
247             if (other.lineStroke != null)
248                 return false;
249         } else if (!lineStroke.equals(other.lineStroke))
250             return false;
251         if (routeLineStroke == null) {
252             if (other.routeLineStroke != null)
253                 return false;
254         } else if (!routeLineStroke.equals(other.routeLineStroke))
255             return false;
256         return true;
257     }
258
259     public double getRounding() {
260         return rounding;
261     }
262
263 }