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 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 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 } 152 153 if(labelPositionAbs != null) { 154 label.setPosition(labelPositionAbs.getX(), labelPositionAbs.getY()); 155 label.draw(g); 156 } 157 } 158 159 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 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 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++) { 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 } 249 } 250 251 Vector2D p0 = controlPointsAbs[0]; 253 g.drawLine((int) p0.getX(), (int) p0.getY(), (int) fx, (int) fy); 254 255 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 |