9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.marlin; 27 28 import static java.lang.Math.PI; 29 import static java.lang.Math.cos; 30 import static java.lang.Math.sqrt; 31 import static java.lang.Math.cbrt; 32 import static java.lang.Math.acos; 33 34 final class DHelpers implements MarlinConst { 35 36 private DHelpers() { 37 throw new Error("This is a non instantiable class"); 38 } 39 40 static boolean within(final double x, final double y, final double err) { 41 final double d = y - x; 42 return (d <= err && d >= -err); 43 } 44 45 static int quadraticRoots(final double a, final double b, 46 final double c, double[] zeroes, final int off) 47 { 48 int ret = off; 49 double t; 50 if (a != 0.0d) { 51 final double dis = b*b - 4*a*c; 52 if (dis > 0.0d) { 98 // substitute x = y - A/3 to eliminate quadratic term: 99 // x^3 +Px + Q = 0 100 // 101 // Since we actually need P/3 and Q/2 for all of the 102 // calculations that follow, we will calculate 103 // p = P/3 104 // q = Q/2 105 // instead and use those values for simplicity of the code. 106 double sq_A = a * a; 107 double p = (1.0d/3.0d) * ((-1.0d/3.0d) * sq_A + b); 108 double q = (1.0d/2.0d) * ((2.0d/27.0d) * a * sq_A - (1.0d/3.0d) * a * b + c); 109 110 // use Cardano's formula 111 112 double cb_p = p * p * p; 113 double D = q * q + cb_p; 114 115 int num; 116 if (D < 0.0d) { 117 // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method 118 final double phi = (1.0d/3.0d) * acos(-q / sqrt(-cb_p)); 119 final double t = 2.0d * sqrt(-p); 120 121 pts[ off+0 ] = ( t * cos(phi)); 122 pts[ off+1 ] = (-t * cos(phi + (PI / 3.0d))); 123 pts[ off+2 ] = (-t * cos(phi - (PI / 3.0d))); 124 num = 3; 125 } else { 126 final double sqrt_D = sqrt(D); 127 final double u = cbrt(sqrt_D - q); 128 final double v = - cbrt(sqrt_D + q); 129 130 pts[ off ] = (u + v); 131 num = 1; 132 133 if (within(D, 0.0d, 1e-8d)) { 134 pts[off+1] = -(pts[off] / 2.0d); 135 num = 2; 136 } 137 } 138 139 final double sub = (1.0d/3.0d) * a; 140 141 for (int i = 0; i < num; ++i) { 142 pts[ off+i ] -= sub; 143 } 144 145 return filterOutNotInAB(pts, off, num, A, B) - off; 146 } 147 148 static double evalCubic(final double a, final double b, 154 155 static double evalQuad(final double a, final double b, 156 final double c, final double t) 157 { 158 return t * (t * a + b) + c; 159 } 160 161 // returns the index 1 past the last valid element remaining after filtering 162 static int filterOutNotInAB(double[] nums, final int off, final int len, 163 final double a, final double b) 164 { 165 int ret = off; 166 for (int i = off, end = off + len; i < end; i++) { 167 if (nums[i] >= a && nums[i] < b) { 168 nums[ret++] = nums[i]; 169 } 170 } 171 return ret; 172 } 173 174 static double polyLineLength(double[] poly, final int off, final int nCoords) { 175 assert nCoords % 2 == 0 && poly.length >= off + nCoords : ""; 176 double acc = 0.0d; 177 for (int i = off + 2; i < off + nCoords; i += 2) { 178 acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]); 179 } 180 return acc; 181 } 182 183 static double linelen(double x1, double y1, double x2, double y2) { 184 final double dx = x2 - x1; 185 final double dy = y2 - y1; 186 return Math.sqrt(dx*dx + dy*dy); 187 } 188 189 static void subdivide(double[] src, int srcoff, double[] left, int leftoff, 190 double[] right, int rightoff, int type) 191 { 192 switch(type) { 193 case 6: 194 DHelpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff); 195 return; 196 case 8: 197 DHelpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff); 198 return; 199 default: 200 throw new InternalError("Unsupported curve type"); 201 } 202 } 414 } 415 if (right != null) { 416 right[rightoff + 0] = ctrlx; 417 right[rightoff + 1] = ctrly; 418 right[rightoff + 2] = x2; 419 right[rightoff + 3] = y2; 420 } 421 } 422 423 static void subdivideAt(double t, double[] src, int srcoff, 424 double[] left, int leftoff, 425 double[] right, int rightoff, int size) 426 { 427 switch(size) { 428 case 8: 429 subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff); 430 return; 431 case 6: 432 subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff); 433 return; 434 } 435 } 436 } | 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.java2d.marlin; 27 28 import static java.lang.Math.PI; 29 import java.util.Arrays; 30 import static sun.java2d.marlin.MarlinConst.INITIAL_EDGES_COUNT; 31 import sun.java2d.marlin.stats.Histogram; 32 import sun.java2d.marlin.stats.StatLong; 33 34 final class DHelpers implements MarlinConst { 35 36 private DHelpers() { 37 throw new Error("This is a non instantiable class"); 38 } 39 40 static boolean within(final double x, final double y, final double err) { 41 final double d = y - x; 42 return (d <= err && d >= -err); 43 } 44 45 static int quadraticRoots(final double a, final double b, 46 final double c, double[] zeroes, final int off) 47 { 48 int ret = off; 49 double t; 50 if (a != 0.0d) { 51 final double dis = b*b - 4*a*c; 52 if (dis > 0.0d) { 98 // substitute x = y - A/3 to eliminate quadratic term: 99 // x^3 +Px + Q = 0 100 // 101 // Since we actually need P/3 and Q/2 for all of the 102 // calculations that follow, we will calculate 103 // p = P/3 104 // q = Q/2 105 // instead and use those values for simplicity of the code. 106 double sq_A = a * a; 107 double p = (1.0d/3.0d) * ((-1.0d/3.0d) * sq_A + b); 108 double q = (1.0d/2.0d) * ((2.0d/27.0d) * a * sq_A - (1.0d/3.0d) * a * b + c); 109 110 // use Cardano's formula 111 112 double cb_p = p * p * p; 113 double D = q * q + cb_p; 114 115 int num; 116 if (D < 0.0d) { 117 // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method 118 final double phi = (1.0d/3.0d) * Math.acos(-q / Math.sqrt(-cb_p)); 119 final double t = 2.0d * Math.sqrt(-p); 120 121 pts[ off+0 ] = ( t * Math.cos(phi)); 122 pts[ off+1 ] = (-t * Math.cos(phi + (PI / 3.0d))); 123 pts[ off+2 ] = (-t * Math.cos(phi - (PI / 3.0d))); 124 num = 3; 125 } else { 126 final double sqrt_D = Math.sqrt(D); 127 final double u = Math.cbrt(sqrt_D - q); 128 final double v = - Math.cbrt(sqrt_D + q); 129 130 pts[ off ] = (u + v); 131 num = 1; 132 133 if (within(D, 0.0d, 1e-8d)) { 134 pts[off+1] = -(pts[off] / 2.0d); 135 num = 2; 136 } 137 } 138 139 final double sub = (1.0d/3.0d) * a; 140 141 for (int i = 0; i < num; ++i) { 142 pts[ off+i ] -= sub; 143 } 144 145 return filterOutNotInAB(pts, off, num, A, B) - off; 146 } 147 148 static double evalCubic(final double a, final double b, 154 155 static double evalQuad(final double a, final double b, 156 final double c, final double t) 157 { 158 return t * (t * a + b) + c; 159 } 160 161 // returns the index 1 past the last valid element remaining after filtering 162 static int filterOutNotInAB(double[] nums, final int off, final int len, 163 final double a, final double b) 164 { 165 int ret = off; 166 for (int i = off, end = off + len; i < end; i++) { 167 if (nums[i] >= a && nums[i] < b) { 168 nums[ret++] = nums[i]; 169 } 170 } 171 return ret; 172 } 173 174 static double linelen(double x1, double y1, double x2, double y2) { 175 final double dx = x2 - x1; 176 final double dy = y2 - y1; 177 return Math.sqrt(dx*dx + dy*dy); 178 } 179 180 static void subdivide(double[] src, int srcoff, double[] left, int leftoff, 181 double[] right, int rightoff, int type) 182 { 183 switch(type) { 184 case 6: 185 DHelpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff); 186 return; 187 case 8: 188 DHelpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff); 189 return; 190 default: 191 throw new InternalError("Unsupported curve type"); 192 } 193 } 405 } 406 if (right != null) { 407 right[rightoff + 0] = ctrlx; 408 right[rightoff + 1] = ctrly; 409 right[rightoff + 2] = x2; 410 right[rightoff + 3] = y2; 411 } 412 } 413 414 static void subdivideAt(double t, double[] src, int srcoff, 415 double[] left, int leftoff, 416 double[] right, int rightoff, int size) 417 { 418 switch(size) { 419 case 8: 420 subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff); 421 return; 422 case 6: 423 subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff); 424 return; 425 } 426 } 427 428 // From sun.java2d.loops.GeneralRenderer: 429 430 static int outcode(final double x, final double y, 431 final double[] clipRect) 432 { 433 int code; 434 if (y < clipRect[0]) { 435 code = OUTCODE_TOP; 436 } else if (y >= clipRect[1]) { 437 code = OUTCODE_BOTTOM; 438 } else { 439 code = 0; 440 } 441 if (x < clipRect[2]) { 442 code |= OUTCODE_LEFT; 443 } else if (x >= clipRect[3]) { 444 code |= OUTCODE_RIGHT; 445 } 446 return code; 447 } 448 449 // a stack of polynomial curves where each curve shares endpoints with 450 // adjacent ones. 451 static final class PolyStack { 452 private static final byte TYPE_LINETO = (byte) 0; 453 private static final byte TYPE_QUADTO = (byte) 1; 454 private static final byte TYPE_CUBICTO = (byte) 2; 455 456 // curves capacity = edges count (8192) = edges x 2 (coords) 457 private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1; 458 459 // types capacity = edges count (4096) 460 private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT; 461 462 double[] curves; 463 int end; 464 byte[] curveTypes; 465 int numCurves; 466 467 // curves ref (dirty) 468 final DoubleArrayCache.Reference curves_ref; 469 // curveTypes ref (dirty) 470 final ByteArrayCache.Reference curveTypes_ref; 471 472 // used marks (stats only) 473 int curveTypesUseMark; 474 int curvesUseMark; 475 476 private final StatLong stat_polystack_types; 477 private final StatLong stat_polystack_curves; 478 private final Histogram hist_polystack_curves; 479 private final StatLong stat_array_polystack_curves; 480 private final StatLong stat_array_polystack_curveTypes; 481 482 PolyStack(final DRendererContext rdrCtx) { 483 this(rdrCtx, null, null, null, null, null); 484 } 485 486 PolyStack(final DRendererContext rdrCtx, 487 final StatLong stat_polystack_types, 488 final StatLong stat_polystack_curves, 489 final Histogram hist_polystack_curves, 490 final StatLong stat_array_polystack_curves, 491 final StatLong stat_array_polystack_curveTypes) 492 { 493 curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K 494 curves = curves_ref.initial; 495 496 curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K 497 curveTypes = curveTypes_ref.initial; 498 numCurves = 0; 499 end = 0; 500 501 if (DO_STATS) { 502 curveTypesUseMark = 0; 503 curvesUseMark = 0; 504 } 505 this.stat_polystack_types = stat_polystack_types; 506 this.stat_polystack_curves = stat_polystack_curves; 507 this.hist_polystack_curves = hist_polystack_curves; 508 this.stat_array_polystack_curves = stat_array_polystack_curves; 509 this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes; 510 } 511 512 /** 513 * Disposes this PolyStack: 514 * clean up before reusing this instance 515 */ 516 void dispose() { 517 end = 0; 518 numCurves = 0; 519 520 if (DO_STATS) { 521 stat_polystack_types.add(curveTypesUseMark); 522 stat_polystack_curves.add(curvesUseMark); 523 hist_polystack_curves.add(curvesUseMark); 524 525 // reset marks 526 curveTypesUseMark = 0; 527 curvesUseMark = 0; 528 } 529 530 // Return arrays: 531 // curves and curveTypes are kept dirty 532 curves = curves_ref.putArray(curves); 533 curveTypes = curveTypes_ref.putArray(curveTypes); 534 } 535 536 private void ensureSpace(final int n) { 537 // use substraction to avoid integer overflow: 538 if (curves.length - end < n) { 539 if (DO_STATS) { 540 stat_array_polystack_curves.add(end + n); 541 } 542 curves = curves_ref.widenArray(curves, end, end + n); 543 } 544 if (curveTypes.length <= numCurves) { 545 if (DO_STATS) { 546 stat_array_polystack_curveTypes.add(numCurves + 1); 547 } 548 curveTypes = curveTypes_ref.widenArray(curveTypes, 549 numCurves, 550 numCurves + 1); 551 } 552 } 553 554 void pushCubic(double x0, double y0, 555 double x1, double y1, 556 double x2, double y2) 557 { 558 ensureSpace(6); 559 curveTypes[numCurves++] = TYPE_CUBICTO; 560 // we reverse the coordinate order to make popping easier 561 final double[] _curves = curves; 562 int e = end; 563 _curves[e++] = x2; _curves[e++] = y2; 564 _curves[e++] = x1; _curves[e++] = y1; 565 _curves[e++] = x0; _curves[e++] = y0; 566 end = e; 567 } 568 569 void pushQuad(double x0, double y0, 570 double x1, double y1) 571 { 572 ensureSpace(4); 573 curveTypes[numCurves++] = TYPE_QUADTO; 574 final double[] _curves = curves; 575 int e = end; 576 _curves[e++] = x1; _curves[e++] = y1; 577 _curves[e++] = x0; _curves[e++] = y0; 578 end = e; 579 } 580 581 void pushLine(double x, double y) { 582 ensureSpace(2); 583 curveTypes[numCurves++] = TYPE_LINETO; 584 curves[end++] = x; curves[end++] = y; 585 } 586 587 void pullAll(final DPathConsumer2D io) { 588 final int nc = numCurves; 589 if (nc == 0) { 590 return; 591 } 592 if (DO_STATS) { 593 // update used marks: 594 if (numCurves > curveTypesUseMark) { 595 curveTypesUseMark = numCurves; 596 } 597 if (end > curvesUseMark) { 598 curvesUseMark = end; 599 } 600 } 601 final byte[] _curveTypes = curveTypes; 602 final double[] _curves = curves; 603 int e = 0; 604 605 for (int i = 0; i < nc; i++) { 606 switch(_curveTypes[i]) { 607 case TYPE_LINETO: 608 io.lineTo(_curves[e], _curves[e+1]); 609 e += 2; 610 continue; 611 case TYPE_QUADTO: 612 io.quadTo(_curves[e+0], _curves[e+1], 613 _curves[e+2], _curves[e+3]); 614 e += 4; 615 continue; 616 case TYPE_CUBICTO: 617 io.curveTo(_curves[e+0], _curves[e+1], 618 _curves[e+2], _curves[e+3], 619 _curves[e+4], _curves[e+5]); 620 e += 6; 621 continue; 622 default: 623 } 624 } 625 numCurves = 0; 626 end = 0; 627 } 628 629 void popAll(final DPathConsumer2D io) { 630 int nc = numCurves; 631 if (nc == 0) { 632 return; 633 } 634 if (DO_STATS) { 635 // update used marks: 636 if (numCurves > curveTypesUseMark) { 637 curveTypesUseMark = numCurves; 638 } 639 if (end > curvesUseMark) { 640 curvesUseMark = end; 641 } 642 } 643 final byte[] _curveTypes = curveTypes; 644 final double[] _curves = curves; 645 int e = end; 646 647 while (nc != 0) { 648 switch(_curveTypes[--nc]) { 649 case TYPE_LINETO: 650 e -= 2; 651 io.lineTo(_curves[e], _curves[e+1]); 652 continue; 653 case TYPE_QUADTO: 654 e -= 4; 655 io.quadTo(_curves[e+0], _curves[e+1], 656 _curves[e+2], _curves[e+3]); 657 continue; 658 case TYPE_CUBICTO: 659 e -= 6; 660 io.curveTo(_curves[e+0], _curves[e+1], 661 _curves[e+2], _curves[e+3], 662 _curves[e+4], _curves[e+5]); 663 continue; 664 default: 665 } 666 } 667 numCurves = 0; 668 end = 0; 669 } 670 671 @Override 672 public String toString() { 673 String ret = ""; 674 int nc = numCurves; 675 int last = end; 676 int len; 677 while (nc != 0) { 678 switch(curveTypes[--nc]) { 679 case TYPE_LINETO: 680 len = 2; 681 ret += "line: "; 682 break; 683 case TYPE_QUADTO: 684 len = 4; 685 ret += "quad: "; 686 break; 687 case TYPE_CUBICTO: 688 len = 6; 689 ret += "cubic: "; 690 break; 691 default: 692 len = 0; 693 } 694 last -= len; 695 ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len)) 696 + "\n"; 697 } 698 return ret; 699 } 700 } 701 702 // a stack of integer indices 703 static final class IndexStack { 704 705 // integer capacity = edges count / 4 ~ 1024 706 private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2; 707 708 private int end; 709 private int[] indices; 710 711 // indices ref (dirty) 712 private final IntArrayCache.Reference indices_ref; 713 714 // used marks (stats only) 715 private int indicesUseMark; 716 717 private final StatLong stat_idxstack_indices; 718 private final Histogram hist_idxstack_indices; 719 private final StatLong stat_array_idxstack_indices; 720 721 IndexStack(final DRendererContext rdrCtx) { 722 this(rdrCtx, null, null, null); 723 } 724 725 IndexStack(final DRendererContext rdrCtx, 726 final StatLong stat_idxstack_indices, 727 final Histogram hist_idxstack_indices, 728 final StatLong stat_array_idxstack_indices) 729 { 730 indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K 731 indices = indices_ref.initial; 732 end = 0; 733 734 if (DO_STATS) { 735 indicesUseMark = 0; 736 } 737 this.stat_idxstack_indices = stat_idxstack_indices; 738 this.hist_idxstack_indices = hist_idxstack_indices; 739 this.stat_array_idxstack_indices = stat_array_idxstack_indices; 740 } 741 742 /** 743 * Disposes this PolyStack: 744 * clean up before reusing this instance 745 */ 746 void dispose() { 747 end = 0; 748 749 if (DO_STATS) { 750 stat_idxstack_indices.add(indicesUseMark); 751 hist_idxstack_indices.add(indicesUseMark); 752 753 // reset marks 754 indicesUseMark = 0; 755 } 756 757 // Return arrays: 758 // values is kept dirty 759 indices = indices_ref.putArray(indices); 760 } 761 762 boolean isEmpty() { 763 return (end == 0); 764 } 765 766 void reset() { 767 end = 0; 768 } 769 770 void push(final int v) { 771 // remove redundant values (reverse order): 772 int[] _values = indices; 773 final int nc = end; 774 if (nc != 0) { 775 if (_values[nc - 1] == v) { 776 // remove both duplicated values: 777 end--; 778 return; 779 } 780 } 781 if (_values.length <= nc) { 782 if (DO_STATS) { 783 stat_array_idxstack_indices.add(nc + 1); 784 } 785 indices = _values = indices_ref.widenArray(_values, nc, nc + 1); 786 } 787 _values[end++] = v; 788 789 if (DO_STATS) { 790 // update used marks: 791 if (end > indicesUseMark) { 792 indicesUseMark = end; 793 } 794 } 795 } 796 797 void pullAll(final double[] points, final DPathConsumer2D io) { 798 final int nc = end; 799 if (nc == 0) { 800 return; 801 } 802 final int[] _values = indices; 803 804 for (int i = 0, j; i < nc; i++) { 805 j = _values[i] << 1; 806 io.lineTo(points[j], points[j + 1]); 807 } 808 end = 0; 809 } 810 } 811 } |