1 /*
2 * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
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
36 private double cx0;
37 private double cy0;
38 private double cx1;
39 private double cy1;
40 private double x1;
41 private double y1;
42
43 private double xmin;
44 private double xmax;
45
46 private double xcoeff0;
47 private double xcoeff1;
48 private double xcoeff2;
49 private double xcoeff3;
50
51 private double ycoeff0;
52 private double ycoeff1;
53 private double ycoeff2;
54 private double ycoeff3;
55
56 public static void insert(Vector<Curve> curves, double tmp[],
57 double x0, double y0,
58 double cx0, double cy0,
59 double cx1, double cy1,
60 double x1, double y1,
61 int direction)
62 {
63 int numparams = getHorizontalParams(y0, cy0, cy1, y1, tmp);
64 if (numparams == 0) {
65 // We are using addInstance here to avoid inserting horisontal
66 // segments
67 addInstance(curves, x0, y0, cx0, cy0, cx1, cy1, x1, y1, direction);
68 return;
69 }
70 // Store coordinates for splitting at tmp[3..10]
71 tmp[3] = x0; tmp[4] = y0;
72 tmp[5] = cx0; tmp[6] = cy0;
73 tmp[7] = cx1; tmp[8] = cy1;
74 tmp[9] = x1; tmp[10] = y1;
75 double t = tmp[0];
76 if (numparams > 1 && t > tmp[1]) {
143 * + (3*CP0 - 3*C0)
144 * 0 = 3*(C1 - 3*CP1 + 3*CP0 - C0)t^2
145 * + 3*2*(CP1 - 2*CP0 + C0)t
146 * + 3*(CP0 - C0)
147 * 0 = (C1 - CP1 - CP1 - CP1 + CP0 + CP0 + CP0 - C0)t^2
148 * + 2*(CP1 - CP0 - CP0 + C0)t
149 * + (CP0 - C0)
150 * 0 = (C1 - CP1 + CP0 - CP1 + CP0 - CP1 + CP0 - C0)t^2
151 * + 2*(CP1 - CP0 - CP0 + C0)t
152 * + (CP0 - C0)
153 * 0 = ((C1 - CP1) - (CP1 - CP0) - (CP1 - CP0) + (CP0 - C0))t^2
154 * + 2*((CP1 - CP0) - (CP0 - C0))t
155 * + (CP0 - C0)
156 * Note that this method will return 0 if the equation is a line,
157 * which is either always horizontal or never horizontal.
158 * Completely horizontal curves need to be eliminated by other
159 * means outside of this method.
160 */
161 public static int getHorizontalParams(double c0, double cp0,
162 double cp1, double c1,
163 double ret[]) {
164 if (c0 <= cp0 && cp0 <= cp1 && cp1 <= c1) {
165 return 0;
166 }
167 c1 -= cp1;
168 cp1 -= cp0;
169 cp0 -= c0;
170 ret[0] = cp0;
171 ret[1] = (cp1 - cp0) * 2;
172 ret[2] = (c1 - cp1 - cp1 + cp0);
173 int numroots = QuadCurve2D.solveQuadratic(ret, ret);
174 int j = 0;
175 for (int i = 0; i < numroots; i++) {
176 double t = ret[i];
177 // No splits at t==0 and t==1
178 if (t > 0 && t < 1) {
179 if (j < i) {
180 ret[j] = t;
181 }
182 j++;
183 }
184 }
185 return j;
186 }
187
188 /*
189 * Split the cubic Bezier stored at coords[pos...pos+7] representing
190 * the parametric range [0..1] into two subcurves representing the
191 * parametric subranges [0..t] and [t..1]. Store the results back
192 * into the array at coords[pos...pos+7] and coords[pos+6...pos+13].
193 */
194 public static void split(double coords[], int pos, double t) {
195 double x0, y0, cx0, cy0, cx1, cy1, x1, y1;
196 coords[pos+12] = x1 = coords[pos+6];
197 coords[pos+13] = y1 = coords[pos+7];
198 cx1 = coords[pos+4];
199 cy1 = coords[pos+5];
200 x1 = cx1 + (x1 - cx1) * t;
201 y1 = cy1 + (y1 - cy1) * t;
202 x0 = coords[pos+0];
203 y0 = coords[pos+1];
204 cx0 = coords[pos+2];
205 cy0 = coords[pos+3];
206 x0 = x0 + (cx0 - x0) * t;
207 y0 = y0 + (cy0 - y0) * t;
208 cx0 = cx0 + (cx1 - cx0) * t;
209 cy0 = cy0 + (cy1 - cy0) * t;
210 cx1 = cx0 + (x1 - cx0) * t;
211 cy1 = cy0 + (y1 - cy0) * t;
212 cx0 = x0 + (cx0 - x0) * t;
213 cy0 = y0 + (cy0 - y0) * t;
214 coords[pos+2] = x0;
512 return 0;
513 }
514 }
515
516 public double dYforT(double t, int deriv) {
517 switch (deriv) {
518 case 0:
519 return (((ycoeff3 * t) + ycoeff2) * t + ycoeff1) * t + ycoeff0;
520 case 1:
521 return ((3 * ycoeff3 * t) + 2 * ycoeff2) * t + ycoeff1;
522 case 2:
523 return (6 * ycoeff3 * t) + 2 * ycoeff2;
524 case 3:
525 return 6 * ycoeff3;
526 default:
527 return 0;
528 }
529 }
530
531 public double nextVertical(double t0, double t1) {
532 double eqn[] = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
533 int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
534 for (int i = 0; i < numroots; i++) {
535 if (eqn[i] > t0 && eqn[i] < t1) {
536 t1 = eqn[i];
537 }
538 }
539 return t1;
540 }
541
542 public void enlarge(Rectangle2D r) {
543 r.add(x0, y0);
544 double eqn[] = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
545 int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
546 for (int i = 0; i < numroots; i++) {
547 double t = eqn[i];
548 if (t > 0 && t < 1) {
549 r.add(XforT(t), YforT(t));
550 }
551 }
552 r.add(x1, y1);
553 }
554
555 public Curve getSubCurve(double ystart, double yend, int dir) {
556 if (ystart <= y0 && yend >= y1) {
557 return getWithDirection(dir);
558 }
559 double eqn[] = new double[14];
560 double t0, t1;
561 t0 = TforY(ystart);
562 t1 = TforY(yend);
563 eqn[0] = x0;
564 eqn[1] = y0;
565 eqn[2] = cx0;
566 eqn[3] = cy0;
567 eqn[4] = cx1;
568 eqn[5] = cy1;
569 eqn[6] = x1;
570 eqn[7] = y1;
571 if (t0 > t1) {
572 /* This happens in only rare cases where ystart is
573 * very near yend and solving for the yend root ends
574 * up stepping slightly lower in t than solving for
575 * the ystart root.
576 * Ideally we might want to skip this tiny little
577 * segment and just fudge the surrounding coordinates
578 * to bridge the gap left behind, but there is no way
579 * to do that from here. Higher levels could
591 split(eqn, 0, t1);
592 }
593 int i;
594 if (t0 <= 0) {
595 i = 0;
596 } else {
597 split(eqn, 0, t0 / t1);
598 i = 6;
599 }
600 return new Order3(eqn[i+0], ystart,
601 eqn[i+2], eqn[i+3],
602 eqn[i+4], eqn[i+5],
603 eqn[i+6], yend,
604 dir);
605 }
606
607 public Curve getReversedCurve() {
608 return new Order3(x0, y0, cx0, cy0, cx1, cy1, x1, y1, -direction);
609 }
610
611 public int getSegment(double coords[]) {
612 if (direction == INCREASING) {
613 coords[0] = cx0;
614 coords[1] = cy0;
615 coords[2] = cx1;
616 coords[3] = cy1;
617 coords[4] = x1;
618 coords[5] = y1;
619 } else {
620 coords[0] = cx1;
621 coords[1] = cy1;
622 coords[2] = cx0;
623 coords[3] = cy0;
624 coords[4] = x0;
625 coords[5] = y0;
626 }
627 return PathIterator.SEG_CUBICTO;
628 }
629
630 public String controlPointString() {
631 return (("("+round(getCX0())+", "+round(getCY0())+"), ")+
|
1 /*
2 * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
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
36 private double cx0;
37 private double cy0;
38 private double cx1;
39 private double cy1;
40 private double x1;
41 private double y1;
42
43 private double xmin;
44 private double xmax;
45
46 private double xcoeff0;
47 private double xcoeff1;
48 private double xcoeff2;
49 private double xcoeff3;
50
51 private double ycoeff0;
52 private double ycoeff1;
53 private double ycoeff2;
54 private double ycoeff3;
55
56 public static void insert(Vector<Curve> curves, double[] tmp,
57 double x0, double y0,
58 double cx0, double cy0,
59 double cx1, double cy1,
60 double x1, double y1,
61 int direction)
62 {
63 int numparams = getHorizontalParams(y0, cy0, cy1, y1, tmp);
64 if (numparams == 0) {
65 // We are using addInstance here to avoid inserting horisontal
66 // segments
67 addInstance(curves, x0, y0, cx0, cy0, cx1, cy1, x1, y1, direction);
68 return;
69 }
70 // Store coordinates for splitting at tmp[3..10]
71 tmp[3] = x0; tmp[4] = y0;
72 tmp[5] = cx0; tmp[6] = cy0;
73 tmp[7] = cx1; tmp[8] = cy1;
74 tmp[9] = x1; tmp[10] = y1;
75 double t = tmp[0];
76 if (numparams > 1 && t > tmp[1]) {
143 * + (3*CP0 - 3*C0)
144 * 0 = 3*(C1 - 3*CP1 + 3*CP0 - C0)t^2
145 * + 3*2*(CP1 - 2*CP0 + C0)t
146 * + 3*(CP0 - C0)
147 * 0 = (C1 - CP1 - CP1 - CP1 + CP0 + CP0 + CP0 - C0)t^2
148 * + 2*(CP1 - CP0 - CP0 + C0)t
149 * + (CP0 - C0)
150 * 0 = (C1 - CP1 + CP0 - CP1 + CP0 - CP1 + CP0 - C0)t^2
151 * + 2*(CP1 - CP0 - CP0 + C0)t
152 * + (CP0 - C0)
153 * 0 = ((C1 - CP1) - (CP1 - CP0) - (CP1 - CP0) + (CP0 - C0))t^2
154 * + 2*((CP1 - CP0) - (CP0 - C0))t
155 * + (CP0 - C0)
156 * Note that this method will return 0 if the equation is a line,
157 * which is either always horizontal or never horizontal.
158 * Completely horizontal curves need to be eliminated by other
159 * means outside of this method.
160 */
161 public static int getHorizontalParams(double c0, double cp0,
162 double cp1, double c1,
163 double[] ret) {
164 if (c0 <= cp0 && cp0 <= cp1 && cp1 <= c1) {
165 return 0;
166 }
167 c1 -= cp1;
168 cp1 -= cp0;
169 cp0 -= c0;
170 ret[0] = cp0;
171 ret[1] = (cp1 - cp0) * 2;
172 ret[2] = (c1 - cp1 - cp1 + cp0);
173 int numroots = QuadCurve2D.solveQuadratic(ret, ret);
174 int j = 0;
175 for (int i = 0; i < numroots; i++) {
176 double t = ret[i];
177 // No splits at t==0 and t==1
178 if (t > 0 && t < 1) {
179 if (j < i) {
180 ret[j] = t;
181 }
182 j++;
183 }
184 }
185 return j;
186 }
187
188 /*
189 * Split the cubic Bezier stored at coords[pos...pos+7] representing
190 * the parametric range [0..1] into two subcurves representing the
191 * parametric subranges [0..t] and [t..1]. Store the results back
192 * into the array at coords[pos...pos+7] and coords[pos+6...pos+13].
193 */
194 public static void split(double[] coords, int pos, double t) {
195 double x0, y0, cx0, cy0, cx1, cy1, x1, y1;
196 coords[pos+12] = x1 = coords[pos+6];
197 coords[pos+13] = y1 = coords[pos+7];
198 cx1 = coords[pos+4];
199 cy1 = coords[pos+5];
200 x1 = cx1 + (x1 - cx1) * t;
201 y1 = cy1 + (y1 - cy1) * t;
202 x0 = coords[pos+0];
203 y0 = coords[pos+1];
204 cx0 = coords[pos+2];
205 cy0 = coords[pos+3];
206 x0 = x0 + (cx0 - x0) * t;
207 y0 = y0 + (cy0 - y0) * t;
208 cx0 = cx0 + (cx1 - cx0) * t;
209 cy0 = cy0 + (cy1 - cy0) * t;
210 cx1 = cx0 + (x1 - cx0) * t;
211 cy1 = cy0 + (y1 - cy0) * t;
212 cx0 = x0 + (cx0 - x0) * t;
213 cy0 = y0 + (cy0 - y0) * t;
214 coords[pos+2] = x0;
512 return 0;
513 }
514 }
515
516 public double dYforT(double t, int deriv) {
517 switch (deriv) {
518 case 0:
519 return (((ycoeff3 * t) + ycoeff2) * t + ycoeff1) * t + ycoeff0;
520 case 1:
521 return ((3 * ycoeff3 * t) + 2 * ycoeff2) * t + ycoeff1;
522 case 2:
523 return (6 * ycoeff3 * t) + 2 * ycoeff2;
524 case 3:
525 return 6 * ycoeff3;
526 default:
527 return 0;
528 }
529 }
530
531 public double nextVertical(double t0, double t1) {
532 double[] eqn = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
533 int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
534 for (int i = 0; i < numroots; i++) {
535 if (eqn[i] > t0 && eqn[i] < t1) {
536 t1 = eqn[i];
537 }
538 }
539 return t1;
540 }
541
542 public void enlarge(Rectangle2D r) {
543 r.add(x0, y0);
544 double[] eqn = {xcoeff1, 2 * xcoeff2, 3 * xcoeff3};
545 int numroots = QuadCurve2D.solveQuadratic(eqn, eqn);
546 for (int i = 0; i < numroots; i++) {
547 double t = eqn[i];
548 if (t > 0 && t < 1) {
549 r.add(XforT(t), YforT(t));
550 }
551 }
552 r.add(x1, y1);
553 }
554
555 public Curve getSubCurve(double ystart, double yend, int dir) {
556 if (ystart <= y0 && yend >= y1) {
557 return getWithDirection(dir);
558 }
559 double[] eqn = new double[14];
560 double t0, t1;
561 t0 = TforY(ystart);
562 t1 = TforY(yend);
563 eqn[0] = x0;
564 eqn[1] = y0;
565 eqn[2] = cx0;
566 eqn[3] = cy0;
567 eqn[4] = cx1;
568 eqn[5] = cy1;
569 eqn[6] = x1;
570 eqn[7] = y1;
571 if (t0 > t1) {
572 /* This happens in only rare cases where ystart is
573 * very near yend and solving for the yend root ends
574 * up stepping slightly lower in t than solving for
575 * the ystart root.
576 * Ideally we might want to skip this tiny little
577 * segment and just fudge the surrounding coordinates
578 * to bridge the gap left behind, but there is no way
579 * to do that from here. Higher levels could
591 split(eqn, 0, t1);
592 }
593 int i;
594 if (t0 <= 0) {
595 i = 0;
596 } else {
597 split(eqn, 0, t0 / t1);
598 i = 6;
599 }
600 return new Order3(eqn[i+0], ystart,
601 eqn[i+2], eqn[i+3],
602 eqn[i+4], eqn[i+5],
603 eqn[i+6], yend,
604 dir);
605 }
606
607 public Curve getReversedCurve() {
608 return new Order3(x0, y0, cx0, cy0, cx1, cy1, x1, y1, -direction);
609 }
610
611 public int getSegment(double[] coords) {
612 if (direction == INCREASING) {
613 coords[0] = cx0;
614 coords[1] = cy0;
615 coords[2] = cx1;
616 coords[3] = cy1;
617 coords[4] = x1;
618 coords[5] = y1;
619 } else {
620 coords[0] = cx1;
621 coords[1] = cy1;
622 coords[2] = cx0;
623 coords[3] = cy0;
624 coords[4] = x0;
625 coords[5] = y0;
626 }
627 return PathIterator.SEG_CUBICTO;
628 }
629
630 public String controlPointString() {
631 return (("("+round(getCX0())+", "+round(getCY0())+"), ")+
|