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