1
2
3
4
5
6
7
8
9
10 package edu.uci.ics.jung.visualization.renderers;
11
12 import java.awt.Shape;
13 import java.awt.geom.AffineTransform;
14 import java.awt.geom.GeneralPath;
15 import java.awt.geom.Line2D;
16 import java.awt.geom.PathIterator;
17 import java.awt.geom.Point2D;
18
19 import edu.uci.ics.jung.visualization.RenderContext;
20
21 public class BasicEdgeArrowRenderingSupport<V,E> implements EdgeArrowRenderingSupport<V, E> {
22
23
24
25
26 public AffineTransform getArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape) {
27 GeneralPath path = new GeneralPath(edgeShape);
28 float[] seg = new float[6];
29 Point2D p1=null;
30 Point2D p2=null;
31 AffineTransform at = new AffineTransform();
32
33
34 for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
35 int ret = i.currentSegment(seg);
36 if(ret == PathIterator.SEG_MOVETO) {
37 p2 = new Point2D.Float(seg[0],seg[1]);
38 } else if(ret == PathIterator.SEG_LINETO) {
39 p1 = p2;
40 p2 = new Point2D.Float(seg[0],seg[1]);
41 if(vertexShape.contains(p2)) {
42 at = getArrowTransform(rc, new Line2D.Float(p1,p2),vertexShape);
43 break;
44 }
45 }
46 }
47 return at;
48 }
49
50
51
52
53 public AffineTransform getReverseArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape) {
54 return getReverseArrowTransform(rc, edgeShape, vertexShape, true);
55 }
56
57
58
59
60 public AffineTransform getReverseArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape,
61 boolean passedGo) {
62 GeneralPath path = new GeneralPath(edgeShape);
63 float[] seg = new float[6];
64 Point2D p1=null;
65 Point2D p2=null;
66
67 AffineTransform at = new AffineTransform();
68 for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
69 int ret = i.currentSegment(seg);
70 if(ret == PathIterator.SEG_MOVETO) {
71 p2 = new Point2D.Float(seg[0],seg[1]);
72 } else if(ret == PathIterator.SEG_LINETO) {
73 p1 = p2;
74 p2 = new Point2D.Float(seg[0],seg[1]);
75 if(passedGo == false && vertexShape.contains(p2)) {
76 passedGo = true;
77 } else if(passedGo==true &&
78 vertexShape.contains(p2)==false) {
79 at = getReverseArrowTransform(rc, new Line2D.Float(p1,p2),vertexShape);
80 break;
81 }
82 }
83 }
84 return at;
85 }
86
87
88
89
90 public AffineTransform getArrowTransform(RenderContext<V,E> rc, Line2D edgeShape, Shape vertexShape) {
91 float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
92 float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
93
94
95 while((dx*dx+dy*dy) > rc.getArrowPlacementTolerance()) {
96 try {
97 edgeShape = getLastOutsideSegment(edgeShape, vertexShape);
98 } catch(IllegalArgumentException e) {
99 System.err.println(e.toString());
100 return null;
101 }
102 dx = (float) (edgeShape.getX1()-edgeShape.getX2());
103 dy = (float) (edgeShape.getY1()-edgeShape.getY2());
104 }
105 double atheta = Math.atan2(dx,dy)+Math.PI/2;
106 AffineTransform at =
107 AffineTransform.getTranslateInstance(edgeShape.getX1(), edgeShape.getY1());
108 at.rotate(-atheta);
109 return at;
110 }
111
112
113
114
115
116
117
118
119
120 protected AffineTransform getReverseArrowTransform(RenderContext<V,E> rc, Line2D edgeShape, Shape vertexShape) {
121 float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
122 float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
123
124
125 while((dx*dx+dy*dy) > rc.getArrowPlacementTolerance()) {
126 try {
127 edgeShape = getFirstOutsideSegment(edgeShape, vertexShape);
128 } catch(IllegalArgumentException e) {
129 System.err.println(e.toString());
130 return null;
131 }
132 dx = (float) (edgeShape.getX1()-edgeShape.getX2());
133 dy = (float) (edgeShape.getY1()-edgeShape.getY2());
134 }
135
136 double atheta = Math.atan2(dx,dy)-Math.PI/2;
137 AffineTransform at = AffineTransform.getTranslateInstance(edgeShape.getX1(),edgeShape.getY1());
138 at.rotate(-atheta);
139 return at;
140 }
141
142
143
144
145
146
147
148
149
150 protected Line2D getLastOutsideSegment(Line2D line, Shape shape) {
151 if(shape.contains(line.getP2())==false) {
152 String errorString =
153 "line end point: "+line.getP2()+" is not contained in shape: "+shape.getBounds2D();
154 throw new IllegalArgumentException(errorString);
155
156 }
157 Line2D left = new Line2D.Double();
158 Line2D right = new Line2D.Double();
159
160
161 do {
162 subdivide(line, left, right);
163 line = right;
164 } while(shape.contains(line.getP1())==false);
165
166
167 return left;
168 }
169
170
171
172
173
174
175
176
177
178 protected Line2D getFirstOutsideSegment(Line2D line, Shape shape) {
179
180 if(shape.contains(line.getP1())==false) {
181 String errorString =
182 "line start point: "+line.getP1()+" is not contained in shape: "+shape.getBounds2D();
183 throw new IllegalArgumentException(errorString);
184 }
185 Line2D left = new Line2D.Float();
186 Line2D right = new Line2D.Float();
187
188
189 do {
190 subdivide(line, left, right);
191 line = left;
192 } while(shape.contains(line.getP2())==false);
193
194
195 return right;
196 }
197
198
199
200
201
202
203
204
205 protected void subdivide(Line2D src,
206 Line2D left,
207 Line2D right) {
208 double x1 = src.getX1();
209 double y1 = src.getY1();
210 double x2 = src.getX2();
211 double y2 = src.getY2();
212
213 double mx = x1 + (x2-x1)/2.0;
214 double my = y1 + (y2-y1)/2.0;
215 if (left != null) {
216 left.setLine(x1, y1, mx, my);
217 }
218 if (right != null) {
219 right.setLine(mx, my, x2, y2);
220 }
221 }
222
223 }