1 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 ; 39 import java.awt.geom.FlatteningPathIterator ; 40 import java.awt.geom.PathIterator ; 41 import java.awt.geom.QuadCurve2D ; 42 43 public class SLinkArc extends SLink implements XJXMLSerializable { 44 45 protected transient QuadCurve2D.Double quad; 46 protected transient CubicCurve2D.Double 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 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 i = new FlatteningPathIterator (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 138 if(selfLoop) { 139 if(cubic == null) 140 cubic = new CubicCurve2D.Double (); 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 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 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 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 (); 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 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 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 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 |