KickJava   Java API By Example, From Geeks To Geeks.

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


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

38
39 public class SLinkBezier extends SLinkArc implements XJXMLSerializable {
40
41     protected Vector2D controlPointsAbs[];
42     protected Vector2D labelPositionAbs;
43
44     protected Vector2D controlPointsRel[];
45     protected Vector2D labelPositionRel;
46
47     protected Vector2D oldStart, oldEnd;
48     protected Vector2D originalEndPointOffset;
49     protected double originalZLength;
50
51     protected double x0 = 0;
52     protected double y0 = 0;
53     protected double x1 = 0;
54     protected double y1 = 0;
55
56     protected static final int MODE_END = 1;
57     protected static final int MODE_NOSTRETCH = 0;
58     protected static final int MODE_STRETCH = -1;
59
60     public void setControlPoints(Vector2D points[]) {
61         this.controlPointsAbs = points;
62         resetFrame();
63         for(int i=0; i<points.length; i++) {
64             updateFrame(points[i]);
65         }
66     }
67
68     public void setLabelPosition(Vector2D position) {
69         this.labelPositionAbs = position;
70     }
71
72     public Rect getFrame() {
73         return new Rect(x0, y0, x1-x0, y1-y0);
74     }
75
76     public boolean contains(double x, double y) {
77         return false;
78     }
79
80     public Vector2D absToRel(Vector2D p) {
81         if(selfLoop) {
82             return p.sub(start);
83         } else {
84             Vector2D z = end.sub(start);
85             Vector2D a = p.sub(start);
86
87             double lb = a.dot(z)/z.length();
88             Vector2D b = z.normalize().setLength(lb);
89
90             Vector2D c = a.sub(b);
91             double lc = c.length()*(a.crossSign(z));
92
93             return new Vector2D(lb, lc);
94         }
95     }
96
97     public Vector2D relToAbs(Vector2D p, int mode) {
98         if(selfLoop) {
99             return start.add(p);
100         } else {
101             Vector2D nz = end.sub(start);
102             double f = nz.length()/originalZLength;
103             double lb = p.getX();
104             double lc = p.getY();
105             if(mode == MODE_END) {
106                 // End-point is always at the same relative position
107
return end.add(originalEndPointOffset);
108             } else {
109                 if(mode == MODE_NOSTRETCH)
110                     f = 1;
111                 Vector2D nb = nz.normalize().setLength(f*lb);
112                 Vector2D nc = nz.copy().rotate(-90).normalize().setLength(lc);
113                 return start.add(nb.add(nc));
114             }
115         }
116     }
117
118     public void update() {
119         int max = controlPointsAbs.length;
120         if(controlPointsRel == null) {
121             controlPointsRel = new Vector2D[controlPointsAbs.length];
122             for(int i=0; i<max; i++) {
123                 controlPointsRel[i] = absToRel(controlPointsAbs[i]);
124             }
125             if(labelPositionAbs != null)
126                 labelPositionRel = absToRel(labelPositionAbs);
127
128             originalEndPointOffset = controlPointsAbs[max-1].sub(end);
129             originalZLength = end.sub(start).length();
130         } else if(!oldStart.equals(start) || !oldEnd.equals(end)) {
131             resetFrame();
132             for(int i=0; i<max; i++) {
133                 controlPointsAbs[i] = relToAbs(controlPointsRel[i], i == 0 ? MODE_NOSTRETCH: (i==max-1?MODE_END:MODE_STRETCH));
134                 updateFrame(controlPointsAbs[i]);
135             }
136             if(labelPositionRel != null)
137                 labelPositionAbs = relToAbs(labelPositionRel, MODE_STRETCH);
138         }
139         oldStart = start;
140         oldEnd = end;
141     }
142
143     public void draw(Graphics2D g) {
144         drawShape(g);
145     }
146
147     public void drawShape(Graphics2D g) {
148         if(controlPointsAbs != null) {
149             bspline(g);
150             //lines(g);
151
}
152
153         if(labelPositionAbs != null) {
154             label.setPosition(labelPositionAbs.getX(), labelPositionAbs.getY());
155             label.draw(g);
156         }
157     }
158
159     /** Debug method used to print only the control points
160      *
161      */

162
163     public void lines(Graphics g) {
164
165         g.setColor(color);
166
167         for (int i = 0; i < controlPointsAbs.length; i++) {
168             Vector2D pt = controlPointsAbs[i];
169             double x = pt.x;
170             double y = pt.y;
171             g.fillRect((int)(x-2), (int)(y-2), 4, 4);
172         }
173     }
174
175     /** This method comes from:
176      *
177     Code used from BSpline.java (c) Leen Ammeraal with its authorization (see e-mail below)
178     http://home.wxs.nl/~ammeraal/grjava.html
179
180      Hello Jean,
181 Thank you for your interest in my program Bspline.java. Yes, you can use it in your software,
182 preferably giving me credit in the about box, as you suggest. If this cannot be done, I trust you
183 will refer to my book in other ways, as you think appropriate.
184 Best wishes,
185 Leen Ammeraal
186     */

187
188     public void bspline(Graphics g) {
189
190         g.setColor(color);
191
192         int n = controlPointsAbs.length;
193
194         double xA, yA, xB, yB, xC, yC, xD, yD,
195                 a0, a1, a2, a3, b0, b1, b2, b3, x = 0, y = 0, x0, y0;
196         // this chooses how many point to go trough the curve, smaller number, more points.
197
double time_delta = 0.1;
198         boolean first = true;
199         double fx = 0, fy = 0;
200
201         for (int i = 1; i < n - 2; i++) { // Loop Through Control Points
202

203             Vector2D p0 = controlPointsAbs[i - 1];
204             Vector2D p1 = controlPointsAbs[i];
205             Vector2D p2 = controlPointsAbs[i + 1];
206             Vector2D p3 = controlPointsAbs[i + 2];
207
208             xA = p0.x;
209             xB = p1.x;
210             xC = p2.x;
211             xD = p3.x;
212
213             yA = p0.y;
214             yB = p1.y;
215             yC = p2.y;
216             yD = p3.y;
217
218             a3 = (-xA + 3 * (xB - xC) + xD) / 6;
219             b3 = (-yA + 3 * (yB - yC) + yD) / 6;
220             a2 = (xA - 2 * xB + xC) / 2;
221             b2 = (yA - 2 * yB + yC) / 2;
222             a1 = (xC - xA) / 2;
223             b1 = (yC - yA) / 2;
224             a0 = (xA + 4 * xB + xC) / 6;
225             b0 = (yA + 4 * yB + yC) / 6;
226
227
228             for (double t = 0; t <=1.0; t += time_delta) {
229                 x0 = x;
230                 y0 = y;
231
232                 double x1 = ((a3 * t + a2) * t + a1) * t + a0;
233                 double y1 = ((b3 * t + b2) * t + b1) * t + b0;
234
235                 x = (int) Math.round(x1);
236                 y = (int) Math.round(y1);
237
238                 if (first) {
239                     first = false;
240                     fx = x;
241                     fy = y;
242                 } else {
243                     g.drawLine((int) x0, (int) y0, (int) x, (int) y);
244                 }
245
246                 //g.setColor(Color.red);
247
//g.fillRect((int)(x-2), (int)(y-2), 4, 4);
248
}
249         }
250
251         // Perimeter of the source to the first point of the bezier curve
252
Vector2D p0 = controlPointsAbs[0];
253         g.drawLine((int) p0.getX(), (int) p0.getY(), (int) fx, (int) fy);
254
255         // Last point of the bezier curve to the perimeter of the target
256
Vector2D p1 = controlPointsAbs[n-1];
257         g.drawLine((int) x, (int) y, (int) p1.getX(), (int) p1.getY());
258
259         arrow.setAnchor(p1.getX(), p1.getY());
260         arrow.setDirection(new Vector2D(x-p1.getX(), y-p1.getY()));
261         arrow.draw(g);
262     }
263
264     private void resetFrame() {
265         if(start != null && end != null) {
266             x0 = Math.min(start.x, end.x);
267             y0 = Math.min(start.y, end.y);
268             x1 = Math.max(start.x, end.x);
269             y1 = Math.max(start.y, end.y);
270         } else {
271             x0 = Integer.MAX_VALUE;
272             y0 = Integer.MAX_VALUE;
273             x1 = Integer.MIN_VALUE;
274             y1 = Integer.MIN_VALUE;
275         }
276     }
277
278     private void updateFrame(Vector2D point) {
279         updateFrame(point.x, point.y);
280     }
281
282     private void updateFrame(double x, double y) {
283         x0 = Math.min(x0, x);
284         y0 = Math.min(y0, y);
285         x1 = Math.max(x1, x);
286         y1 = Math.max(y1, y);
287     }
288 }
289
Popular Tags