1 18 package org.apache.batik.ext.awt.geom; 19 20 import java.awt.Shape ; 21 import java.awt.geom.AffineTransform ; 22 import java.awt.geom.Arc2D ; 23 import java.awt.geom.GeneralPath ; 24 import java.awt.geom.PathIterator ; 25 import java.awt.geom.Point2D ; 26 import java.awt.geom.Rectangle2D ; 27 28 41 public class ExtendedGeneralPath implements ExtendedShape, Cloneable { 42 43 44 protected GeneralPath path; 45 46 int numVals = 0; 47 int numSeg = 0; 48 float [] values = null; 49 int [] types = null; 50 51 float mx, my, cx, cy; 52 53 56 public ExtendedGeneralPath() { 57 path = new GeneralPath (); 58 } 59 60 65 public ExtendedGeneralPath(int rule) { 66 path = new GeneralPath (rule); 67 } 68 69 74 public ExtendedGeneralPath(int rule, int initialCapacity) { 75 path = new GeneralPath (rule, initialCapacity); 76 } 77 78 82 public ExtendedGeneralPath(Shape s) { 83 this(); 84 append(s, false); 85 } 86 87 110 public synchronized void arcTo(float rx, float ry, 111 float angle, 112 boolean largeArcFlag, 113 boolean sweepFlag, 114 float x, float y) { 115 116 if (rx == 0 || ry == 0) { 118 lineTo((float) x, (float) y); 119 return; 120 } 121 122 checkMoveTo(); 124 double x0 = cx; 126 double y0 = cy; 127 if (x0 == x && y0 == y) { 128 return; 131 } 132 133 Arc2D arc = computeArc(x0, y0, rx, ry, angle, 134 largeArcFlag, sweepFlag, x, y); 135 if (arc == null) return; 136 137 AffineTransform t = AffineTransform.getRotateInstance 138 (Math.toRadians(angle), arc.getCenterX(), arc.getCenterY()); 139 Shape s = t.createTransformedShape(arc); 140 path.append(s, true); 141 142 makeRoom(7); 143 types [numSeg++] = ExtendedPathIterator.SEG_ARCTO; 144 values[numVals++] = rx; 145 values[numVals++] = ry; 146 values[numVals++] = angle; 147 values[numVals++] = largeArcFlag?1:0; 148 values[numVals++] = sweepFlag?1:0; 149 cx = values[numVals++] = x; 150 cy = values[numVals++] = y; 151 } 152 153 154 162 public static Arc2D computeArc(double x0, double y0, 163 double rx, double ry, 164 double angle, 165 boolean largeArcFlag, 166 boolean sweepFlag, 167 double x, double y) { 168 172 double dx2 = (x0 - x) / 2.0; 174 double dy2 = (y0 - y) / 2.0; 175 angle = Math.toRadians(angle % 360.0); 177 double cosAngle = Math.cos(angle); 178 double sinAngle = Math.sin(angle); 179 180 double x1 = (cosAngle * dx2 + sinAngle * dy2); 184 double y1 = (-sinAngle * dx2 + cosAngle * dy2); 185 rx = Math.abs(rx); 187 ry = Math.abs(ry); 188 double Prx = rx * rx; 189 double Pry = ry * ry; 190 double Px1 = x1 * x1; 191 double Py1 = y1 * y1; 192 double radiiCheck = Px1/Prx + Py1/Pry; 194 if (radiiCheck > 1) { 195 rx = Math.sqrt(radiiCheck) * rx; 196 ry = Math.sqrt(radiiCheck) * ry; 197 Prx = rx * rx; 198 Pry = ry * ry; 199 } 200 201 double sign = (largeArcFlag == sweepFlag) ? -1 : 1; 205 double sq = ((Prx*Pry)-(Prx*Py1)-(Pry*Px1)) / ((Prx*Py1)+(Pry*Px1)); 206 sq = (sq < 0) ? 0 : sq; 207 double coef = (sign * Math.sqrt(sq)); 208 double cx1 = coef * ((rx * y1) / ry); 209 double cy1 = coef * -((ry * x1) / rx); 210 211 double sx2 = (x0 + x) / 2.0; 215 double sy2 = (y0 + y) / 2.0; 216 double cx = sx2 + (cosAngle * cx1 - sinAngle * cy1); 217 double cy = sy2 + (sinAngle * cx1 + cosAngle * cy1); 218 219 double ux = (x1 - cx1) / rx; 223 double uy = (y1 - cy1) / ry; 224 double vx = (-x1 - cx1) / rx; 225 double vy = (-y1 - cy1) / ry; 226 double p, n; 227 n = Math.sqrt((ux * ux) + (uy * uy)); 229 p = ux; sign = (uy < 0) ? -1d : 1d; 231 double angleStart = Math.toDegrees(sign * Math.acos(p / n)); 232 233 n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy)); 235 p = ux * vx + uy * vy; 236 sign = (ux * vy - uy * vx < 0) ? -1d : 1d; 237 double angleExtent = Math.toDegrees(sign * Math.acos(p / n)); 238 if(!sweepFlag && angleExtent > 0) { 239 angleExtent -= 360f; 240 } else if (sweepFlag && angleExtent < 0) { 241 angleExtent += 360f; 242 } 243 angleExtent %= 360f; 244 angleStart %= 360f; 245 246 Arc2D.Double arc = new Arc2D.Double (); 250 arc.x = cx - rx; 251 arc.y = cy - ry; 252 arc.width = rx * 2.0; 253 arc.height = ry * 2.0; 254 arc.start = -angleStart; 255 arc.extent = -angleExtent; 256 257 return arc; 258 } 259 260 263 public synchronized void moveTo(float x, float y) { 264 makeRoom(2); 266 types [numSeg++] = PathIterator.SEG_MOVETO; 267 cx = mx = values[numVals++] = x; 268 cy = my = values[numVals++] = y; 269 270 } 271 272 275 public synchronized void lineTo(float x, float y) { 276 checkMoveTo(); path.lineTo(x, y); 278 279 makeRoom(2); 280 types [numSeg++] = PathIterator.SEG_LINETO; 281 cx = values[numVals++] = x; 282 cy = values[numVals++] = y; 283 } 284 285 288 public synchronized void quadTo(float x1, float y1, float x2, float y2) { 289 checkMoveTo(); path.quadTo(x1, y1, x2, y2); 291 292 makeRoom(4); 293 types [numSeg++] = PathIterator.SEG_QUADTO; 294 values[numVals++] = x1; 295 values[numVals++] = y1; 296 cx = values[numVals++] = x2; 297 cy = values[numVals++] = y2; 298 } 299 300 303 public synchronized void curveTo(float x1, float y1, 304 float x2, float y2, 305 float x3, float y3) { 306 checkMoveTo(); path.curveTo(x1, y1, x2, y2, x3, y3); 308 309 makeRoom(6); 310 types [numSeg++] = PathIterator.SEG_CUBICTO; 311 values[numVals++] = x1; 312 values[numVals++] = y1; 313 values[numVals++] = x2; 314 values[numVals++] = y2; 315 cx = values[numVals++] = x3; 316 cy = values[numVals++] = y3; 317 } 318 319 322 public synchronized void closePath() { 323 if ((numSeg != 0) && (types[numSeg-1] == PathIterator.SEG_CLOSE)) 325 return; 326 327 if ((numSeg != 0) && (types[numSeg-1] != PathIterator.SEG_MOVETO)) 329 path.closePath(); 330 331 makeRoom(0); 332 types [numSeg++] = PathIterator.SEG_CLOSE; 333 cx = mx; 334 cy = my; 335 } 336 337 341 protected void checkMoveTo() { 342 if (numSeg == 0) return; 343 344 switch(types[numSeg-1]) { 345 346 case PathIterator.SEG_MOVETO: 347 path.moveTo(values[numVals-2], values[numVals-1]); 348 break; 349 350 case PathIterator.SEG_CLOSE: 351 if (numSeg == 1) return; 352 if (types[numSeg-2] == PathIterator.SEG_MOVETO) 353 path.moveTo(values[numVals-2], values[numVals-1]); 354 break; 355 356 default: 357 break; 358 } 359 } 360 361 364 public void append(Shape s, boolean connect) { 365 append(s.getPathIterator(new AffineTransform ()), connect); 366 } 367 368 371 public void append(PathIterator pi, boolean connect) { 372 373 while (!pi.isDone()) { 374 double [] vals = new double[6]; 375 int type = pi.currentSegment(vals); 376 pi.next(); 377 if (connect && (numVals != 0)) { 378 if (type == PathIterator.SEG_MOVETO) { 379 double x = vals[0]; 380 double y = vals[1]; 381 if ((x != cx) || 382 (y != cy)) { 383 type = PathIterator.SEG_LINETO; 385 } else { 386 if (pi.isDone()) break; type = pi.currentSegment(vals); 389 pi.next(); 390 } 391 } 392 connect = false; 393 } 394 395 switch(type) { 396 case PathIterator.SEG_CLOSE: closePath(); break; 397 case PathIterator.SEG_MOVETO: 398 moveTo ((float)vals[0], (float)vals[1]); break; 399 case PathIterator.SEG_LINETO: 400 lineTo ((float)vals[0], (float)vals[1]); break; 401 case PathIterator.SEG_QUADTO: 402 quadTo ((float)vals[0], (float)vals[1], 403 (float)vals[2], (float)vals[3]); break; 404 case PathIterator.SEG_CUBICTO: 405 curveTo((float)vals[0], (float)vals[1], 406 (float)vals[2], (float)vals[3], 407 (float)vals[4], (float)vals[5]); break; 408 } 409 } 410 } 411 412 415 public void append(ExtendedPathIterator epi, boolean connect) { 416 while (!epi.isDone()) { 417 float [] vals = new float[7]; 418 int type = epi.currentSegment(vals); 419 epi.next(); 420 if (connect && (numVals != 0)) { 421 if (type == PathIterator.SEG_MOVETO) { 422 float x = vals[0]; 423 float y = vals[1]; 424 if ((x != cx) || 425 (y != cy)) { 426 type = PathIterator.SEG_LINETO; 428 } else { 429 if (epi.isDone()) break; type = epi.currentSegment(vals); 432 epi.next(); 433 } 434 } 435 connect = false; 436 } 437 438 switch(type) { 439 case PathIterator.SEG_CLOSE: closePath(); break; 440 case PathIterator.SEG_MOVETO: 441 moveTo ((float)vals[0], (float)vals[1]); break; 442 case PathIterator.SEG_LINETO: 443 lineTo ((float)vals[0], (float)vals[1]); break; 444 case PathIterator.SEG_QUADTO: 445 quadTo ((float)vals[0], (float)vals[1], 446 (float)vals[2], (float)vals[3]); break; 447 case PathIterator.SEG_CUBICTO: 448 curveTo((float)vals[0], (float)vals[1], 449 (float)vals[2], (float)vals[3], 450 (float)vals[4], (float)vals[5]); break; 451 case ExtendedPathIterator.SEG_ARCTO: 452 arcTo (vals[0], vals[1], vals[2], 453 (vals[3]!=0), (vals[4]!=0), 454 vals[5], vals[6]); break; 455 } 456 } 457 } 458 459 462 public synchronized int getWindingRule() { 463 return path.getWindingRule(); 464 } 465 466 469 public void setWindingRule(int rule) { 470 path.setWindingRule(rule); 471 } 472 473 476 public synchronized Point2D getCurrentPoint() { 477 if (numVals == 0) return null; 478 return new Point2D.Double (cx, cy); 479 } 480 481 484 public synchronized void reset() { 485 path.reset(); 486 487 numSeg = 0; 488 numVals = 0; 489 } 490 491 494 public void transform(AffineTransform at) { 495 if (at.getType() != AffineTransform.TYPE_IDENTITY) 496 throw new IllegalArgumentException 497 ("ExtendedGeneralPaths can not be transformed"); 498 } 499 500 503 public synchronized Shape createTransformedShape(AffineTransform at) { 504 return path.createTransformedShape(at); 505 } 506 507 510 public java.awt.Rectangle getBounds() { 511 return path.getBounds(); 512 } 513 514 517 public synchronized Rectangle2D getBounds2D() { 518 return path.getBounds2D(); 519 } 520 521 524 public boolean contains(double x, double y) { 525 return path.contains(x, y); 526 } 527 528 531 public boolean contains(Point2D p) { 532 return path.contains(p); 533 } 534 535 538 public boolean contains(double x, double y, double w, double h) { 539 return path.contains(x, y, w, h); 540 } 541 542 545 public boolean contains(Rectangle2D r) { 546 return path.contains(r); 547 } 548 549 552 public boolean intersects(double x, double y, double w, double h) { 553 return path.intersects(x, y, w, h); 554 } 555 556 559 public boolean intersects(Rectangle2D r) { 560 return path.intersects(r); 561 } 562 563 566 public PathIterator getPathIterator(AffineTransform at) { 567 return path.getPathIterator(at); 568 } 569 570 573 public PathIterator getPathIterator(AffineTransform at, double flatness) { 574 return path.getPathIterator(at, flatness); 575 } 576 577 580 public ExtendedPathIterator getExtendedPathIterator() { 581 return new EPI(); 582 } 583 584 class EPI implements ExtendedPathIterator { 585 int segNum = 0; 586 int valsIdx = 0; 587 588 public int currentSegment(double[] coords) { 589 int ret = types[segNum]; 590 switch (ret) { 591 case SEG_CLOSE: break; 592 case SEG_MOVETO: 593 case SEG_LINETO: 594 coords[0] = values[valsIdx]; 595 coords[1] = values[valsIdx+1]; 596 break; 597 case SEG_QUADTO: 598 coords[0] = values[valsIdx]; 599 coords[1] = values[valsIdx+1]; 600 coords[2] = values[valsIdx+2]; 601 coords[3] = values[valsIdx+3]; 602 break; 603 case SEG_CUBICTO: 604 coords[0] = values[valsIdx]; 605 coords[1] = values[valsIdx+1]; 606 coords[2] = values[valsIdx+2]; 607 coords[3] = values[valsIdx+3]; 608 coords[4] = values[valsIdx+4]; 609 coords[5] = values[valsIdx+5]; 610 break; 611 case SEG_ARCTO: 612 coords[0] = values[valsIdx]; 613 coords[1] = values[valsIdx+1]; 614 coords[2] = values[valsIdx+2]; 615 coords[3] = values[valsIdx+3]; 616 coords[4] = values[valsIdx+4]; 617 coords[5] = values[valsIdx+5]; 618 coords[6] = values[valsIdx+6]; 619 break; 620 } 621 return ret; 625 } 626 627 public int currentSegment(float[] coords) { 628 int ret = types[segNum]; 629 switch (ret) { 630 case SEG_CLOSE: break; 631 case SEG_MOVETO: 632 case SEG_LINETO: 633 coords[0] = (float)values[valsIdx]; 634 coords[1] = (float)values[valsIdx+1]; 635 break; 636 case SEG_QUADTO: 637 coords[0] = (float)values[valsIdx]; 638 coords[1] = (float)values[valsIdx+1]; 639 coords[2] = (float)values[valsIdx+2]; 640 coords[3] = (float)values[valsIdx+3]; 641 break; 642 case SEG_CUBICTO: 643 coords[0] = (float)values[valsIdx]; 644 coords[1] = (float)values[valsIdx+1]; 645 coords[2] = (float)values[valsIdx+2]; 646 coords[3] = (float)values[valsIdx+3]; 647 coords[4] = (float)values[valsIdx+4]; 648 coords[5] = (float)values[valsIdx+5]; 649 break; 650 case SEG_ARCTO: 651 coords[0] = (float)values[valsIdx]; 652 coords[1] = (float)values[valsIdx+1]; 653 coords[2] = (float)values[valsIdx+2]; 654 coords[3] = (float)values[valsIdx+3]; 655 coords[4] = (float)values[valsIdx+4]; 656 coords[5] = (float)values[valsIdx+5]; 657 coords[6] = (float)values[valsIdx+6]; 658 break; 659 } 660 return ret; 661 } 662 663 public int getWindingRule() { 664 return path.getWindingRule(); 665 } 666 public boolean isDone() { 667 return segNum == numSeg; 668 } 669 public void next() { 670 int type = types[segNum++]; 671 switch (type) { 672 case SEG_CLOSE: break; 673 case SEG_MOVETO: 674 case SEG_LINETO: valsIdx+=2; break; 675 case SEG_QUADTO: valsIdx+=4; break; 676 case SEG_CUBICTO:valsIdx+=6; break; 677 case SEG_ARCTO: valsIdx+=7; break; 678 } 679 } 680 } 681 682 685 public Object clone() { 686 try { 687 ExtendedGeneralPath result = (ExtendedGeneralPath) super.clone(); 688 result.path = (GeneralPath ) path.clone(); 689 690 result.values = new float[values.length]; 691 System.arraycopy(result.values, 0, values, 0, values.length); 692 result.numVals = numVals; 693 694 result.types = new int[types.length]; 695 System.arraycopy(result.types, 0, types, 0, types.length); 696 result.numSeg = numSeg; 697 698 return result; 699 } catch (CloneNotSupportedException ex) {} 700 return null; 701 } 702 703 private void makeRoom(int numValues) { 704 if (values == null) { 705 values = new float[2*numValues]; 706 types = new int[2]; 707 numVals = 0; 708 numSeg = 0; 709 return; 710 } 711 712 if ((numVals + numValues) > values.length) { 713 int nlen = values.length*2; 714 if (nlen < (numVals + numValues)) 715 nlen = numVals + numValues; 716 717 float [] nvals = new float[nlen]; 718 System.arraycopy(values, 0, nvals, 0, numVals); 719 values = nvals; 720 } 721 722 if (numSeg == types.length) { 723 int [] ntypes = new int[types.length*2]; 724 System.arraycopy(types, 0, ntypes, 0, types.length); 725 types = ntypes; 726 } 727 } 728 } 729 | Popular Tags |