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 }
|