KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antlr > xjlib > appkit > gview > shape > SLinkArc


1 /*
2
3 [The "BSD licence"]
4 Copyright (c) 2005 Jean Bovet
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. The name of the author may not be used to endorse or promote products
17 derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 */

31
32 package org.antlr.xjlib.appkit.gview.shape;
33
34 import org.antlr.xjlib.appkit.gview.base.Vector2D;
35 import org.antlr.xjlib.foundation.XJXMLSerializable;
36
37 import java.awt.*;
38 import java.awt.geom.CubicCurve2D JavaDoc;
39 import java.awt.geom.FlatteningPathIterator JavaDoc;
40 import java.awt.geom.PathIterator JavaDoc;
41 import java.awt.geom.QuadCurve2D JavaDoc;
42
43 public class SLinkArc extends SLink implements XJXMLSerializable {
44
45     protected transient QuadCurve2D.Double JavaDoc quad;
46     protected transient CubicCurve2D.Double JavaDoc cubic;
47
48     protected transient Shape shape;
49
50     Vector2D vlabel;
51     Vector2D pmiddle;
52
53     public SLinkArc() {
54         super();
55     }
56
57     public void setMouse(Point mouse) {
58         setMouse(Vector2D.vector(mouse));
59     }
60
61     public void setMouse(Vector2D mouse) {
62         setDirection(mouse.sub(end));
63     }
64
65     public void setFlatenessByMouse(Vector2D mouse) {
66         Vector2D corde = getEndWithOffset().sub(getStartWithOffset());
67         double dot = mouse.sub(getStartWithOffset()).dot(corde.normalize());
68         corde.setLength(dot);
69
70         Vector2D z = getStartWithOffset().add(corde);
71         Vector2D f = mouse.sub(z);
72         double cross = corde.cross(f);
73         if(cross == 0)
74             setFlateness(0);
75         else
76             setFlateness(-2*f.length()*cross/Math.abs(cross));
77     }
78
79     public void setMousePosition(Vector2D position) {
80         setFlatenessByMouse(position);
81     }
82
83     public boolean contains(PathIterator JavaDoc iterator, double x, double y) {
84         double coord[] = new double[6];
85         double oldx = -1, oldy = -1;
86
87         final double flateness = 0.8;
88         final double inset = 4;
89
90         FlatteningPathIterator JavaDoc i = new FlatteningPathIterator JavaDoc(iterator, flateness);
91         while(!i.isDone()) {
92             switch(i.currentSegment(coord)) {
93                 case FlatteningPathIterator.SEG_MOVETO:
94                     oldx = coord[0];
95                     oldy = coord[1];
96                     break;
97
98                 case FlatteningPathIterator.SEG_LINETO:
99                     double nx = coord[0];
100                     double ny = coord[1];
101
102                     double rx1 = Math.min(oldx, nx);
103                     double ry1 = Math.min(oldy, ny);
104                     double rx2 = Math.max(oldx, nx);
105                     double ry2 = Math.max(oldy, ny);
106
107                     if(Math.abs(rx1-rx2)<inset || Math.abs(ry1-ry2)<inset) {
108                         rx1 -= inset;
109                         ry1 -= inset;
110                         rx2 += inset;
111                         ry2 += inset;
112                     }
113
114                     if(x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2)
115                         return true;
116
117                     oldx = nx;
118                     oldy = ny;
119                     break;
120             }
121             i.next();
122         }
123         return false;
124     }
125
126     public boolean contains(double x, double y) {
127         if(selfLoop && cubic != null)
128             return contains(cubic.getPathIterator(null), x, y);
129         if(!selfLoop && quad != null)
130             return contains(quad.getPathIterator(null), x, y);
131
132         return false;
133     }
134
135     public void update() {
136         // Compute the control point of the curve
137

138         if(selfLoop) {
139             if(cubic == null)
140                 cubic = new CubicCurve2D.Double JavaDoc();
141
142             Vector2D corde = direction.copy();
143             corde.stretch(1.7);
144             if(corde.length()<100)
145                 corde.setLength(100);
146
147             corde.rotate(-40);
148             cubic.ctrlx1 = getStartWithOffset().getX()+corde.getX();
149             cubic.ctrly1 = getStartWithOffset().getY()+corde.getY();
150
151             corde.rotate(+80);
152             cubic.ctrlx2 = getStartWithOffset().getX()+corde.getX();
153             cubic.ctrly2 = getStartWithOffset().getY()+corde.getY();
154
155             // Move the start/end point according to offset
156

157             Vector2D v1 = new Vector2D(cubic.ctrlx1, cubic.ctrly1).sub(getStartWithOffset());
158             Vector2D v2 = new Vector2D(cubic.ctrlx2, cubic.ctrly2).sub(getStartWithOffset());
159
160             v1 = v1.normalize();
161             v1.stretch(startTangentOffset);
162
163             v2 = v2.normalize();
164             v2.stretch(endTangentOffset);
165
166             cubic.x1 = getStartWithOffset().getX()+v1.getX();
167             cubic.y1 = getStartWithOffset().getY()+v1.getY();
168             cubic.x2 = getEndWithOffset().getX()+v2.getX();
169             cubic.y2 = getEndWithOffset().getY()+v2.getY();
170
171             // Position of the label
172

173             Vector2D vlabel = direction.copy();
174             vlabel.setLength(vlabel.length()+15);
175             if(vlabel.length()<75)
176                 vlabel.setLength(75);
177
178             Vector2D plabel = getStartWithOffset().add(vlabel);
179             label.setPosition(plabel);
180
181             // Create the arrow at the end of the path
182

183             arrow.setAnchor(cubic.x2, cubic.y2);
184             arrow.setDirection(new Vector2D(cubic.ctrlx2-cubic.x2, cubic.ctrly2-cubic.y2));
185
186             shape = cubic;
187         } else {
188             Vector2D middle = getEndWithOffset().sub(getStartWithOffset());
189             middle.stretch(0.5);
190
191             Vector2D height = middle.normalize();
192             height.rotate(-90);
193
194             if(flateness == 0)
195                 height.setLength(0.01);
196             else
197                 height.setLength(flateness);
198
199             Vector2D ctrl = middle.add(height);
200
201             if(quad == null)
202                 quad = new QuadCurve2D.Double JavaDoc();
203
204             quad.x1 = getStartWithOffset().getX();
205             quad.y1 = getStartWithOffset().getY();
206             quad.x2 = getEndWithOffset().getX();
207             quad.y2 = getEndWithOffset().getY();
208             quad.ctrlx = getStartWithOffset().getX()+ctrl.getX();
209             quad.ctrly = getStartWithOffset().getY()+ctrl.getY();
210
211             Vector2D controlPoint = new Vector2D(quad.ctrlx, quad.ctrly);
212
213             // Move the start/end point according to offset
214

215             Vector2D v1 = controlPoint.sub(getStartWithOffset());
216             Vector2D v2 = controlPoint.sub(getEndWithOffset());
217
218             v1 = v1.normalize();
219             v1.stretch(startTangentOffset);
220
221             v2 = v2.normalize();
222             v2.stretch(endTangentOffset);
223
224             quad.x1 = getStartWithOffset().getX()+v1.getX();
225             quad.y1 = getStartWithOffset().getY()+v1.getY();
226             quad.x2 = getEndWithOffset().getX()+v2.getX();
227             quad.y2 = getEndWithOffset().getY()+v2.getY();
228
229             // Position of the label
230

231             pmiddle = new Vector2D(quad.x1+(quad.x2-quad.x1)*0.5, quad.y1+(quad.y2-quad.y1)*0.5);
232             vlabel = new Vector2D(quad.x2-quad.x1, quad.y2-quad.y1).rotate(90*(flateness<0?1:-1));
233
234             vlabel.setLength(Math.abs(flateness)*0.5+20);
235             label.setPosition(pmiddle.add(vlabel));
236
237             // Create the arrow at the end of the path
238

239             arrow.setAnchor(quad.x2, quad.y2);
240             arrow.setDirection(controlPoint.sub(getEndWithOffset()));
241
242             shape = quad;
243         }
244     }
245
246     public void draw(Graphics2D g) {
247         if(shape == null || arrow == null || label == null)
248             return;
249
250         g.setColor(color);
251
252         drawShape(g);
253         label.draw(g);
254     }
255
256     public void drawShape(Graphics2D g) {
257         if(shape == null || arrow == null || label == null)
258             return;
259
260         g.draw(shape);
261         if(arrowVisible)
262             arrow.draw(g);
263     }
264
265 }
266
Popular Tags