1 /*
2 * Copyright (c) 2006, 2017, 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
170 while (true) {
171 try {
172 // try allocating the larger array
173 return Arrays.copyOf(oldPointTypes, newSize);
174 } catch (OutOfMemoryError oome) {
175 if (newSize == newSizeMin) {
176 throw oome;
177 }
178 }
179 newSize = newSizeMin + (newSize - newSizeMin) / 2;
180 }
181 }
182
183 /**
184 * The {@code Float} class defines a geometric path with
185 * coordinates stored in single precision floating point.
186 *
187 * @since 1.6
188 */
189 public static class Float extends Path2D implements Serializable {
190 transient float floatCoords[];
191
192 /**
193 * Constructs a new empty single precision {@code Path2D} object
194 * with a default winding rule of {@link #WIND_NON_ZERO}.
195 *
196 * @since 1.6
197 */
198 public Float() {
199 this(WIND_NON_ZERO, INIT_SIZE);
200 }
201
202 /**
203 * Constructs a new empty single precision {@code Path2D} object
204 * with the specified winding rule to control operations that
205 * require the interior of the path to be defined.
206 *
207 * @param rule the winding rule
208 * @see #WIND_EVEN_ODD
209 * @see #WIND_NON_ZERO
210 * @since 1.6
273 this.pointTypes = new byte[INIT_SIZE];
274 this.floatCoords = new float[INIT_SIZE * 2];
275 append(pi, false);
276 }
277 }
278
279 @Override
280 public final void trimToSize() {
281 // trim arrays:
282 if (numTypes < pointTypes.length) {
283 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
284 }
285 if (numCoords < floatCoords.length) {
286 this.floatCoords = Arrays.copyOf(floatCoords, numCoords);
287 }
288 }
289
290 @Override
291 float[] cloneCoordsFloat(AffineTransform at) {
292 // trim arrays:
293 float ret[];
294 if (at == null) {
295 ret = Arrays.copyOf(floatCoords, numCoords);
296 } else {
297 ret = new float[numCoords];
298 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
299 }
300 return ret;
301 }
302
303 @Override
304 double[] cloneCoordsDouble(AffineTransform at) {
305 // trim arrays:
306 double ret[] = new double[numCoords];
307 if (at == null) {
308 for (int i = 0; i < numCoords; i++) {
309 ret[i] = floatCoords[i];
310 }
311 } else {
312 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
313 }
314 return ret;
315 }
316
317 void append(float x, float y) {
318 floatCoords[numCoords++] = x;
319 floatCoords[numCoords++] = y;
320 }
321
322 void append(double x, double y) {
323 floatCoords[numCoords++] = (float) x;
324 floatCoords[numCoords++] = (float) y;
325 }
326
538 */
539 public final synchronized void curveTo(float x1, float y1,
540 float x2, float y2,
541 float x3, float y3)
542 {
543 needRoom(true, 6);
544 pointTypes[numTypes++] = SEG_CUBICTO;
545 floatCoords[numCoords++] = x1;
546 floatCoords[numCoords++] = y1;
547 floatCoords[numCoords++] = x2;
548 floatCoords[numCoords++] = y2;
549 floatCoords[numCoords++] = x3;
550 floatCoords[numCoords++] = y3;
551 }
552
553 int pointCrossings(double px, double py) {
554 if (numTypes == 0) {
555 return 0;
556 }
557 double movx, movy, curx, cury, endx, endy;
558 float coords[] = floatCoords;
559 curx = movx = coords[0];
560 cury = movy = coords[1];
561 int crossings = 0;
562 int ci = 2;
563 for (int i = 1; i < numTypes; i++) {
564 switch (pointTypes[i]) {
565 case PathIterator.SEG_MOVETO:
566 if (cury != movy) {
567 crossings +=
568 Curve.pointCrossingsForLine(px, py,
569 curx, cury,
570 movx, movy);
571 }
572 movx = curx = coords[ci++];
573 movy = cury = coords[ci++];
574 break;
575 case PathIterator.SEG_LINETO:
576 crossings +=
577 Curve.pointCrossingsForLine(px, py,
578 curx, cury,
617 curx = movx;
618 cury = movy;
619 break;
620 }
621 }
622 if (cury != movy) {
623 crossings +=
624 Curve.pointCrossingsForLine(px, py,
625 curx, cury,
626 movx, movy);
627 }
628 return crossings;
629 }
630
631 int rectCrossings(double rxmin, double rymin,
632 double rxmax, double rymax)
633 {
634 if (numTypes == 0) {
635 return 0;
636 }
637 float coords[] = floatCoords;
638 double curx, cury, movx, movy, endx, endy;
639 curx = movx = coords[0];
640 cury = movy = coords[1];
641 int crossings = 0;
642 int ci = 2;
643 for (int i = 1;
644 crossings != Curve.RECT_INTERSECTS && i < numTypes;
645 i++)
646 {
647 switch (pointTypes[i]) {
648 case PathIterator.SEG_MOVETO:
649 if (curx != movx || cury != movy) {
650 crossings =
651 Curve.rectCrossingsForLine(crossings,
652 rxmin, rymin,
653 rxmax, rymax,
654 curx, cury,
655 movx, movy);
656 }
657 // Count should always be a multiple of 2 here.
719 if (crossings != Curve.RECT_INTERSECTS &&
720 (curx != movx || cury != movy))
721 {
722 crossings =
723 Curve.rectCrossingsForLine(crossings,
724 rxmin, rymin,
725 rxmax, rymax,
726 curx, cury,
727 movx, movy);
728 }
729 // Count should always be a multiple of 2 here.
730 // assert((crossings & 1) != 0);
731 return crossings;
732 }
733
734 /**
735 * {@inheritDoc}
736 * @since 1.6
737 */
738 public final void append(PathIterator pi, boolean connect) {
739 float coords[] = new float[6];
740 while (!pi.isDone()) {
741 switch (pi.currentSegment(coords)) {
742 case SEG_MOVETO:
743 if (!connect || numTypes < 1 || numCoords < 1) {
744 moveTo(coords[0], coords[1]);
745 break;
746 }
747 if (pointTypes[numTypes - 1] != SEG_CLOSE &&
748 floatCoords[numCoords-2] == coords[0] &&
749 floatCoords[numCoords-1] == coords[1])
750 {
751 // Collapse out initial moveto/lineto
752 break;
753 }
754 lineTo(coords[0], coords[1]);
755 break;
756 case SEG_LINETO:
757 lineTo(coords[0], coords[1]);
758 break;
759 case SEG_QUADTO:
987 /**
988 * Reads the default serializable fields from the
989 * {@code ObjectInputStream} followed by an explicit
990 * serialization of the path segments stored in this
991 * path.
992 * <p>
993 * There are no default serializable fields as of 1.6.
994 * <p>
995 * The serial data for this object is described in the
996 * writeObject method.
997 *
998 * @since 1.6
999 */
1000 private void readObject(java.io.ObjectInputStream s)
1001 throws java.lang.ClassNotFoundException, java.io.IOException
1002 {
1003 super.readObject(s, false);
1004 }
1005
1006 static class CopyIterator extends Path2D.Iterator {
1007 float floatCoords[];
1008
1009 CopyIterator(Path2D.Float p2df) {
1010 super(p2df);
1011 this.floatCoords = p2df.floatCoords;
1012 }
1013
1014 public int currentSegment(float[] coords) {
1015 int type = path.pointTypes[typeIdx];
1016 int numCoords = curvecoords[type];
1017 if (numCoords > 0) {
1018 System.arraycopy(floatCoords, pointIdx,
1019 coords, 0, numCoords);
1020 }
1021 return type;
1022 }
1023
1024 public int currentSegment(double[] coords) {
1025 int type = path.pointTypes[typeIdx];
1026 int numCoords = curvecoords[type];
1027 if (numCoords > 0) {
1028 for (int i = 0; i < numCoords; i++) {
1029 coords[i] = floatCoords[pointIdx + i];
1030 }
1031 }
1032 return type;
1033 }
1034 }
1035
1036 static class TxIterator extends Path2D.Iterator {
1037 float floatCoords[];
1038 AffineTransform affine;
1039
1040 TxIterator(Path2D.Float p2df, AffineTransform at) {
1041 super(p2df);
1042 this.floatCoords = p2df.floatCoords;
1043 this.affine = at;
1044 }
1045
1046 public int currentSegment(float[] coords) {
1047 int type = path.pointTypes[typeIdx];
1048 int numCoords = curvecoords[type];
1049 if (numCoords > 0) {
1050 affine.transform(floatCoords, pointIdx,
1051 coords, 0, numCoords / 2);
1052 }
1053 return type;
1054 }
1055
1056 public int currentSegment(double[] coords) {
1057 int type = path.pointTypes[typeIdx];
1058 int numCoords = curvecoords[type];
1059 if (numCoords > 0) {
1060 affine.transform(floatCoords, pointIdx,
1061 coords, 0, numCoords / 2);
1062 }
1063 return type;
1064 }
1065 }
1066
1067 }
1068
1069 /**
1070 * The {@code Double} class defines a geometric path with
1071 * coordinates stored in double precision floating point.
1072 *
1073 * @since 1.6
1074 */
1075 public static class Double extends Path2D implements Serializable {
1076 transient double doubleCoords[];
1077
1078 /**
1079 * Constructs a new empty double precision {@code Path2D} object
1080 * with a default winding rule of {@link #WIND_NON_ZERO}.
1081 *
1082 * @since 1.6
1083 */
1084 public Double() {
1085 this(WIND_NON_ZERO, INIT_SIZE);
1086 }
1087
1088 /**
1089 * Constructs a new empty double precision {@code Path2D} object
1090 * with the specified winding rule to control operations that
1091 * require the interior of the path to be defined.
1092 *
1093 * @param rule the winding rule
1094 * @see #WIND_EVEN_ODD
1095 * @see #WIND_NON_ZERO
1096 * @since 1.6
1159 this.pointTypes = new byte[INIT_SIZE];
1160 this.doubleCoords = new double[INIT_SIZE * 2];
1161 append(pi, false);
1162 }
1163 }
1164
1165 @Override
1166 public final void trimToSize() {
1167 // trim arrays:
1168 if (numTypes < pointTypes.length) {
1169 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
1170 }
1171 if (numCoords < doubleCoords.length) {
1172 this.doubleCoords = Arrays.copyOf(doubleCoords, numCoords);
1173 }
1174 }
1175
1176 @Override
1177 float[] cloneCoordsFloat(AffineTransform at) {
1178 // trim arrays:
1179 float ret[] = new float[numCoords];
1180 if (at == null) {
1181 for (int i = 0; i < numCoords; i++) {
1182 ret[i] = (float) doubleCoords[i];
1183 }
1184 } else {
1185 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1186 }
1187 return ret;
1188 }
1189
1190 @Override
1191 double[] cloneCoordsDouble(AffineTransform at) {
1192 // trim arrays:
1193 double ret[];
1194 if (at == null) {
1195 ret = Arrays.copyOf(doubleCoords, numCoords);
1196 } else {
1197 ret = new double[numCoords];
1198 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1199 }
1200 return ret;
1201 }
1202
1203 void append(float x, float y) {
1204 doubleCoords[numCoords++] = x;
1205 doubleCoords[numCoords++] = y;
1206 }
1207
1208 void append(double x, double y) {
1209 doubleCoords[numCoords++] = x;
1210 doubleCoords[numCoords++] = y;
1211 }
1212
1213 Point2D getPoint(int coordindex) {
1313 */
1314 public final synchronized void curveTo(double x1, double y1,
1315 double x2, double y2,
1316 double x3, double y3)
1317 {
1318 needRoom(true, 6);
1319 pointTypes[numTypes++] = SEG_CUBICTO;
1320 doubleCoords[numCoords++] = x1;
1321 doubleCoords[numCoords++] = y1;
1322 doubleCoords[numCoords++] = x2;
1323 doubleCoords[numCoords++] = y2;
1324 doubleCoords[numCoords++] = x3;
1325 doubleCoords[numCoords++] = y3;
1326 }
1327
1328 int pointCrossings(double px, double py) {
1329 if (numTypes == 0) {
1330 return 0;
1331 }
1332 double movx, movy, curx, cury, endx, endy;
1333 double coords[] = doubleCoords;
1334 curx = movx = coords[0];
1335 cury = movy = coords[1];
1336 int crossings = 0;
1337 int ci = 2;
1338 for (int i = 1; i < numTypes; i++) {
1339 switch (pointTypes[i]) {
1340 case PathIterator.SEG_MOVETO:
1341 if (cury != movy) {
1342 crossings +=
1343 Curve.pointCrossingsForLine(px, py,
1344 curx, cury,
1345 movx, movy);
1346 }
1347 movx = curx = coords[ci++];
1348 movy = cury = coords[ci++];
1349 break;
1350 case PathIterator.SEG_LINETO:
1351 crossings +=
1352 Curve.pointCrossingsForLine(px, py,
1353 curx, cury,
1392 curx = movx;
1393 cury = movy;
1394 break;
1395 }
1396 }
1397 if (cury != movy) {
1398 crossings +=
1399 Curve.pointCrossingsForLine(px, py,
1400 curx, cury,
1401 movx, movy);
1402 }
1403 return crossings;
1404 }
1405
1406 int rectCrossings(double rxmin, double rymin,
1407 double rxmax, double rymax)
1408 {
1409 if (numTypes == 0) {
1410 return 0;
1411 }
1412 double coords[] = doubleCoords;
1413 double curx, cury, movx, movy, endx, endy;
1414 curx = movx = coords[0];
1415 cury = movy = coords[1];
1416 int crossings = 0;
1417 int ci = 2;
1418 for (int i = 1;
1419 crossings != Curve.RECT_INTERSECTS && i < numTypes;
1420 i++)
1421 {
1422 switch (pointTypes[i]) {
1423 case PathIterator.SEG_MOVETO:
1424 if (curx != movx || cury != movy) {
1425 crossings =
1426 Curve.rectCrossingsForLine(crossings,
1427 rxmin, rymin,
1428 rxmax, rymax,
1429 curx, cury,
1430 movx, movy);
1431 }
1432 // Count should always be a multiple of 2 here.
1495 if (crossings != Curve.RECT_INTERSECTS &&
1496 (curx != movx || cury != movy))
1497 {
1498 crossings =
1499 Curve.rectCrossingsForLine(crossings,
1500 rxmin, rymin,
1501 rxmax, rymax,
1502 curx, cury,
1503 movx, movy);
1504 }
1505 // Count should always be a multiple of 2 here.
1506 // assert((crossings & 1) != 0);
1507 return crossings;
1508 }
1509
1510 /**
1511 * {@inheritDoc}
1512 * @since 1.6
1513 */
1514 public final void append(PathIterator pi, boolean connect) {
1515 double coords[] = new double[6];
1516 while (!pi.isDone()) {
1517 switch (pi.currentSegment(coords)) {
1518 case SEG_MOVETO:
1519 if (!connect || numTypes < 1 || numCoords < 1) {
1520 moveTo(coords[0], coords[1]);
1521 break;
1522 }
1523 if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1524 doubleCoords[numCoords-2] == coords[0] &&
1525 doubleCoords[numCoords-1] == coords[1])
1526 {
1527 // Collapse out initial moveto/lineto
1528 break;
1529 }
1530 lineTo(coords[0], coords[1]);
1531 break;
1532 case SEG_LINETO:
1533 lineTo(coords[0], coords[1]);
1534 break;
1535 case SEG_QUADTO:
1762 /**
1763 * Reads the default serializable fields from the
1764 * {@code ObjectInputStream} followed by an explicit
1765 * serialization of the path segments stored in this
1766 * path.
1767 * <p>
1768 * There are no default serializable fields as of 1.6.
1769 * <p>
1770 * The serial data for this object is described in the
1771 * writeObject method.
1772 *
1773 * @since 1.6
1774 */
1775 private void readObject(java.io.ObjectInputStream s)
1776 throws java.lang.ClassNotFoundException, java.io.IOException
1777 {
1778 super.readObject(s, true);
1779 }
1780
1781 static class CopyIterator extends Path2D.Iterator {
1782 double doubleCoords[];
1783
1784 CopyIterator(Path2D.Double p2dd) {
1785 super(p2dd);
1786 this.doubleCoords = p2dd.doubleCoords;
1787 }
1788
1789 public int currentSegment(float[] coords) {
1790 int type = path.pointTypes[typeIdx];
1791 int numCoords = curvecoords[type];
1792 if (numCoords > 0) {
1793 for (int i = 0; i < numCoords; i++) {
1794 coords[i] = (float) doubleCoords[pointIdx + i];
1795 }
1796 }
1797 return type;
1798 }
1799
1800 public int currentSegment(double[] coords) {
1801 int type = path.pointTypes[typeIdx];
1802 int numCoords = curvecoords[type];
1803 if (numCoords > 0) {
1804 System.arraycopy(doubleCoords, pointIdx,
1805 coords, 0, numCoords);
1806 }
1807 return type;
1808 }
1809 }
1810
1811 static class TxIterator extends Path2D.Iterator {
1812 double doubleCoords[];
1813 AffineTransform affine;
1814
1815 TxIterator(Path2D.Double p2dd, AffineTransform at) {
1816 super(p2dd);
1817 this.doubleCoords = p2dd.doubleCoords;
1818 this.affine = at;
1819 }
1820
1821 public int currentSegment(float[] coords) {
1822 int type = path.pointTypes[typeIdx];
1823 int numCoords = curvecoords[type];
1824 if (numCoords > 0) {
1825 affine.transform(doubleCoords, pointIdx,
1826 coords, 0, numCoords / 2);
1827 }
1828 return type;
1829 }
1830
1831 public int currentSegment(double[] coords) {
1832 int type = path.pointTypes[typeIdx];
2520 private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2521
2522 private static final byte SERIAL_SEG_FLT_MOVETO = 0x40;
2523 private static final byte SERIAL_SEG_FLT_LINETO = 0x41;
2524 private static final byte SERIAL_SEG_FLT_QUADTO = 0x42;
2525 private static final byte SERIAL_SEG_FLT_CUBICTO = 0x43;
2526
2527 private static final byte SERIAL_SEG_DBL_MOVETO = 0x50;
2528 private static final byte SERIAL_SEG_DBL_LINETO = 0x51;
2529 private static final byte SERIAL_SEG_DBL_QUADTO = 0x52;
2530 private static final byte SERIAL_SEG_DBL_CUBICTO = 0x53;
2531
2532 private static final byte SERIAL_SEG_CLOSE = 0x60;
2533 private static final byte SERIAL_PATH_END = 0x61;
2534
2535 final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2536 throws java.io.IOException
2537 {
2538 s.defaultWriteObject();
2539
2540 float fCoords[];
2541 double dCoords[];
2542
2543 if (isdbl) {
2544 dCoords = ((Path2D.Double) this).doubleCoords;
2545 fCoords = null;
2546 } else {
2547 fCoords = ((Path2D.Float) this).floatCoords;
2548 dCoords = null;
2549 }
2550
2551 int numTypes = this.numTypes;
2552
2553 s.writeByte(isdbl
2554 ? SERIAL_STORAGE_DBL_ARRAY
2555 : SERIAL_STORAGE_FLT_ARRAY);
2556 s.writeInt(numTypes);
2557 s.writeInt(numCoords);
2558 s.writeByte((byte) windingRule);
2559
2560 int cindex = 0;
2561 for (int i = 0; i < numTypes; i++) {
2709 while (--npoints >= 0) {
2710 append(s.readDouble(), s.readDouble());
2711 }
2712 } else {
2713 while (--npoints >= 0) {
2714 append(s.readFloat(), s.readFloat());
2715 }
2716 }
2717 pointTypes[numTypes++] = segtype;
2718 }
2719 if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2720 throw new StreamCorruptedException("missing PATH_END");
2721 }
2722 }
2723
2724 abstract static class Iterator implements PathIterator {
2725 int typeIdx;
2726 int pointIdx;
2727 Path2D path;
2728
2729 static final int curvecoords[] = {2, 2, 4, 6, 0};
2730
2731 Iterator(Path2D path) {
2732 this.path = path;
2733 }
2734
2735 public int getWindingRule() {
2736 return path.getWindingRule();
2737 }
2738
2739 public boolean isDone() {
2740 return (typeIdx >= path.numTypes);
2741 }
2742
2743 public void next() {
2744 int type = path.pointTypes[typeIdx++];
2745 pointIdx += curvecoords[type];
2746 }
2747 }
2748 }
|
1 /*
2 * Copyright (c) 2006, 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
170 while (true) {
171 try {
172 // try allocating the larger array
173 return Arrays.copyOf(oldPointTypes, newSize);
174 } catch (OutOfMemoryError oome) {
175 if (newSize == newSizeMin) {
176 throw oome;
177 }
178 }
179 newSize = newSizeMin + (newSize - newSizeMin) / 2;
180 }
181 }
182
183 /**
184 * The {@code Float} class defines a geometric path with
185 * coordinates stored in single precision floating point.
186 *
187 * @since 1.6
188 */
189 public static class Float extends Path2D implements Serializable {
190 transient float[] floatCoords;
191
192 /**
193 * Constructs a new empty single precision {@code Path2D} object
194 * with a default winding rule of {@link #WIND_NON_ZERO}.
195 *
196 * @since 1.6
197 */
198 public Float() {
199 this(WIND_NON_ZERO, INIT_SIZE);
200 }
201
202 /**
203 * Constructs a new empty single precision {@code Path2D} object
204 * with the specified winding rule to control operations that
205 * require the interior of the path to be defined.
206 *
207 * @param rule the winding rule
208 * @see #WIND_EVEN_ODD
209 * @see #WIND_NON_ZERO
210 * @since 1.6
273 this.pointTypes = new byte[INIT_SIZE];
274 this.floatCoords = new float[INIT_SIZE * 2];
275 append(pi, false);
276 }
277 }
278
279 @Override
280 public final void trimToSize() {
281 // trim arrays:
282 if (numTypes < pointTypes.length) {
283 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
284 }
285 if (numCoords < floatCoords.length) {
286 this.floatCoords = Arrays.copyOf(floatCoords, numCoords);
287 }
288 }
289
290 @Override
291 float[] cloneCoordsFloat(AffineTransform at) {
292 // trim arrays:
293 float[] ret;
294 if (at == null) {
295 ret = Arrays.copyOf(floatCoords, numCoords);
296 } else {
297 ret = new float[numCoords];
298 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
299 }
300 return ret;
301 }
302
303 @Override
304 double[] cloneCoordsDouble(AffineTransform at) {
305 // trim arrays:
306 double[] ret = new double[numCoords];
307 if (at == null) {
308 for (int i = 0; i < numCoords; i++) {
309 ret[i] = floatCoords[i];
310 }
311 } else {
312 at.transform(floatCoords, 0, ret, 0, numCoords / 2);
313 }
314 return ret;
315 }
316
317 void append(float x, float y) {
318 floatCoords[numCoords++] = x;
319 floatCoords[numCoords++] = y;
320 }
321
322 void append(double x, double y) {
323 floatCoords[numCoords++] = (float) x;
324 floatCoords[numCoords++] = (float) y;
325 }
326
538 */
539 public final synchronized void curveTo(float x1, float y1,
540 float x2, float y2,
541 float x3, float y3)
542 {
543 needRoom(true, 6);
544 pointTypes[numTypes++] = SEG_CUBICTO;
545 floatCoords[numCoords++] = x1;
546 floatCoords[numCoords++] = y1;
547 floatCoords[numCoords++] = x2;
548 floatCoords[numCoords++] = y2;
549 floatCoords[numCoords++] = x3;
550 floatCoords[numCoords++] = y3;
551 }
552
553 int pointCrossings(double px, double py) {
554 if (numTypes == 0) {
555 return 0;
556 }
557 double movx, movy, curx, cury, endx, endy;
558 float[] coords = floatCoords;
559 curx = movx = coords[0];
560 cury = movy = coords[1];
561 int crossings = 0;
562 int ci = 2;
563 for (int i = 1; i < numTypes; i++) {
564 switch (pointTypes[i]) {
565 case PathIterator.SEG_MOVETO:
566 if (cury != movy) {
567 crossings +=
568 Curve.pointCrossingsForLine(px, py,
569 curx, cury,
570 movx, movy);
571 }
572 movx = curx = coords[ci++];
573 movy = cury = coords[ci++];
574 break;
575 case PathIterator.SEG_LINETO:
576 crossings +=
577 Curve.pointCrossingsForLine(px, py,
578 curx, cury,
617 curx = movx;
618 cury = movy;
619 break;
620 }
621 }
622 if (cury != movy) {
623 crossings +=
624 Curve.pointCrossingsForLine(px, py,
625 curx, cury,
626 movx, movy);
627 }
628 return crossings;
629 }
630
631 int rectCrossings(double rxmin, double rymin,
632 double rxmax, double rymax)
633 {
634 if (numTypes == 0) {
635 return 0;
636 }
637 float[] coords = floatCoords;
638 double curx, cury, movx, movy, endx, endy;
639 curx = movx = coords[0];
640 cury = movy = coords[1];
641 int crossings = 0;
642 int ci = 2;
643 for (int i = 1;
644 crossings != Curve.RECT_INTERSECTS && i < numTypes;
645 i++)
646 {
647 switch (pointTypes[i]) {
648 case PathIterator.SEG_MOVETO:
649 if (curx != movx || cury != movy) {
650 crossings =
651 Curve.rectCrossingsForLine(crossings,
652 rxmin, rymin,
653 rxmax, rymax,
654 curx, cury,
655 movx, movy);
656 }
657 // Count should always be a multiple of 2 here.
719 if (crossings != Curve.RECT_INTERSECTS &&
720 (curx != movx || cury != movy))
721 {
722 crossings =
723 Curve.rectCrossingsForLine(crossings,
724 rxmin, rymin,
725 rxmax, rymax,
726 curx, cury,
727 movx, movy);
728 }
729 // Count should always be a multiple of 2 here.
730 // assert((crossings & 1) != 0);
731 return crossings;
732 }
733
734 /**
735 * {@inheritDoc}
736 * @since 1.6
737 */
738 public final void append(PathIterator pi, boolean connect) {
739 float[] coords = new float[6];
740 while (!pi.isDone()) {
741 switch (pi.currentSegment(coords)) {
742 case SEG_MOVETO:
743 if (!connect || numTypes < 1 || numCoords < 1) {
744 moveTo(coords[0], coords[1]);
745 break;
746 }
747 if (pointTypes[numTypes - 1] != SEG_CLOSE &&
748 floatCoords[numCoords-2] == coords[0] &&
749 floatCoords[numCoords-1] == coords[1])
750 {
751 // Collapse out initial moveto/lineto
752 break;
753 }
754 lineTo(coords[0], coords[1]);
755 break;
756 case SEG_LINETO:
757 lineTo(coords[0], coords[1]);
758 break;
759 case SEG_QUADTO:
987 /**
988 * Reads the default serializable fields from the
989 * {@code ObjectInputStream} followed by an explicit
990 * serialization of the path segments stored in this
991 * path.
992 * <p>
993 * There are no default serializable fields as of 1.6.
994 * <p>
995 * The serial data for this object is described in the
996 * writeObject method.
997 *
998 * @since 1.6
999 */
1000 private void readObject(java.io.ObjectInputStream s)
1001 throws java.lang.ClassNotFoundException, java.io.IOException
1002 {
1003 super.readObject(s, false);
1004 }
1005
1006 static class CopyIterator extends Path2D.Iterator {
1007 float[] floatCoords;
1008
1009 CopyIterator(Path2D.Float p2df) {
1010 super(p2df);
1011 this.floatCoords = p2df.floatCoords;
1012 }
1013
1014 public int currentSegment(float[] coords) {
1015 int type = path.pointTypes[typeIdx];
1016 int numCoords = curvecoords[type];
1017 if (numCoords > 0) {
1018 System.arraycopy(floatCoords, pointIdx,
1019 coords, 0, numCoords);
1020 }
1021 return type;
1022 }
1023
1024 public int currentSegment(double[] coords) {
1025 int type = path.pointTypes[typeIdx];
1026 int numCoords = curvecoords[type];
1027 if (numCoords > 0) {
1028 for (int i = 0; i < numCoords; i++) {
1029 coords[i] = floatCoords[pointIdx + i];
1030 }
1031 }
1032 return type;
1033 }
1034 }
1035
1036 static class TxIterator extends Path2D.Iterator {
1037 float[] floatCoords;
1038 AffineTransform affine;
1039
1040 TxIterator(Path2D.Float p2df, AffineTransform at) {
1041 super(p2df);
1042 this.floatCoords = p2df.floatCoords;
1043 this.affine = at;
1044 }
1045
1046 public int currentSegment(float[] coords) {
1047 int type = path.pointTypes[typeIdx];
1048 int numCoords = curvecoords[type];
1049 if (numCoords > 0) {
1050 affine.transform(floatCoords, pointIdx,
1051 coords, 0, numCoords / 2);
1052 }
1053 return type;
1054 }
1055
1056 public int currentSegment(double[] coords) {
1057 int type = path.pointTypes[typeIdx];
1058 int numCoords = curvecoords[type];
1059 if (numCoords > 0) {
1060 affine.transform(floatCoords, pointIdx,
1061 coords, 0, numCoords / 2);
1062 }
1063 return type;
1064 }
1065 }
1066
1067 }
1068
1069 /**
1070 * The {@code Double} class defines a geometric path with
1071 * coordinates stored in double precision floating point.
1072 *
1073 * @since 1.6
1074 */
1075 public static class Double extends Path2D implements Serializable {
1076 transient double[] doubleCoords;
1077
1078 /**
1079 * Constructs a new empty double precision {@code Path2D} object
1080 * with a default winding rule of {@link #WIND_NON_ZERO}.
1081 *
1082 * @since 1.6
1083 */
1084 public Double() {
1085 this(WIND_NON_ZERO, INIT_SIZE);
1086 }
1087
1088 /**
1089 * Constructs a new empty double precision {@code Path2D} object
1090 * with the specified winding rule to control operations that
1091 * require the interior of the path to be defined.
1092 *
1093 * @param rule the winding rule
1094 * @see #WIND_EVEN_ODD
1095 * @see #WIND_NON_ZERO
1096 * @since 1.6
1159 this.pointTypes = new byte[INIT_SIZE];
1160 this.doubleCoords = new double[INIT_SIZE * 2];
1161 append(pi, false);
1162 }
1163 }
1164
1165 @Override
1166 public final void trimToSize() {
1167 // trim arrays:
1168 if (numTypes < pointTypes.length) {
1169 this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
1170 }
1171 if (numCoords < doubleCoords.length) {
1172 this.doubleCoords = Arrays.copyOf(doubleCoords, numCoords);
1173 }
1174 }
1175
1176 @Override
1177 float[] cloneCoordsFloat(AffineTransform at) {
1178 // trim arrays:
1179 float[] ret = new float[numCoords];
1180 if (at == null) {
1181 for (int i = 0; i < numCoords; i++) {
1182 ret[i] = (float) doubleCoords[i];
1183 }
1184 } else {
1185 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1186 }
1187 return ret;
1188 }
1189
1190 @Override
1191 double[] cloneCoordsDouble(AffineTransform at) {
1192 // trim arrays:
1193 double[] ret;
1194 if (at == null) {
1195 ret = Arrays.copyOf(doubleCoords, numCoords);
1196 } else {
1197 ret = new double[numCoords];
1198 at.transform(doubleCoords, 0, ret, 0, numCoords / 2);
1199 }
1200 return ret;
1201 }
1202
1203 void append(float x, float y) {
1204 doubleCoords[numCoords++] = x;
1205 doubleCoords[numCoords++] = y;
1206 }
1207
1208 void append(double x, double y) {
1209 doubleCoords[numCoords++] = x;
1210 doubleCoords[numCoords++] = y;
1211 }
1212
1213 Point2D getPoint(int coordindex) {
1313 */
1314 public final synchronized void curveTo(double x1, double y1,
1315 double x2, double y2,
1316 double x3, double y3)
1317 {
1318 needRoom(true, 6);
1319 pointTypes[numTypes++] = SEG_CUBICTO;
1320 doubleCoords[numCoords++] = x1;
1321 doubleCoords[numCoords++] = y1;
1322 doubleCoords[numCoords++] = x2;
1323 doubleCoords[numCoords++] = y2;
1324 doubleCoords[numCoords++] = x3;
1325 doubleCoords[numCoords++] = y3;
1326 }
1327
1328 int pointCrossings(double px, double py) {
1329 if (numTypes == 0) {
1330 return 0;
1331 }
1332 double movx, movy, curx, cury, endx, endy;
1333 double[] coords = doubleCoords;
1334 curx = movx = coords[0];
1335 cury = movy = coords[1];
1336 int crossings = 0;
1337 int ci = 2;
1338 for (int i = 1; i < numTypes; i++) {
1339 switch (pointTypes[i]) {
1340 case PathIterator.SEG_MOVETO:
1341 if (cury != movy) {
1342 crossings +=
1343 Curve.pointCrossingsForLine(px, py,
1344 curx, cury,
1345 movx, movy);
1346 }
1347 movx = curx = coords[ci++];
1348 movy = cury = coords[ci++];
1349 break;
1350 case PathIterator.SEG_LINETO:
1351 crossings +=
1352 Curve.pointCrossingsForLine(px, py,
1353 curx, cury,
1392 curx = movx;
1393 cury = movy;
1394 break;
1395 }
1396 }
1397 if (cury != movy) {
1398 crossings +=
1399 Curve.pointCrossingsForLine(px, py,
1400 curx, cury,
1401 movx, movy);
1402 }
1403 return crossings;
1404 }
1405
1406 int rectCrossings(double rxmin, double rymin,
1407 double rxmax, double rymax)
1408 {
1409 if (numTypes == 0) {
1410 return 0;
1411 }
1412 double[] coords = doubleCoords;
1413 double curx, cury, movx, movy, endx, endy;
1414 curx = movx = coords[0];
1415 cury = movy = coords[1];
1416 int crossings = 0;
1417 int ci = 2;
1418 for (int i = 1;
1419 crossings != Curve.RECT_INTERSECTS && i < numTypes;
1420 i++)
1421 {
1422 switch (pointTypes[i]) {
1423 case PathIterator.SEG_MOVETO:
1424 if (curx != movx || cury != movy) {
1425 crossings =
1426 Curve.rectCrossingsForLine(crossings,
1427 rxmin, rymin,
1428 rxmax, rymax,
1429 curx, cury,
1430 movx, movy);
1431 }
1432 // Count should always be a multiple of 2 here.
1495 if (crossings != Curve.RECT_INTERSECTS &&
1496 (curx != movx || cury != movy))
1497 {
1498 crossings =
1499 Curve.rectCrossingsForLine(crossings,
1500 rxmin, rymin,
1501 rxmax, rymax,
1502 curx, cury,
1503 movx, movy);
1504 }
1505 // Count should always be a multiple of 2 here.
1506 // assert((crossings & 1) != 0);
1507 return crossings;
1508 }
1509
1510 /**
1511 * {@inheritDoc}
1512 * @since 1.6
1513 */
1514 public final void append(PathIterator pi, boolean connect) {
1515 double[] coords = new double[6];
1516 while (!pi.isDone()) {
1517 switch (pi.currentSegment(coords)) {
1518 case SEG_MOVETO:
1519 if (!connect || numTypes < 1 || numCoords < 1) {
1520 moveTo(coords[0], coords[1]);
1521 break;
1522 }
1523 if (pointTypes[numTypes - 1] != SEG_CLOSE &&
1524 doubleCoords[numCoords-2] == coords[0] &&
1525 doubleCoords[numCoords-1] == coords[1])
1526 {
1527 // Collapse out initial moveto/lineto
1528 break;
1529 }
1530 lineTo(coords[0], coords[1]);
1531 break;
1532 case SEG_LINETO:
1533 lineTo(coords[0], coords[1]);
1534 break;
1535 case SEG_QUADTO:
1762 /**
1763 * Reads the default serializable fields from the
1764 * {@code ObjectInputStream} followed by an explicit
1765 * serialization of the path segments stored in this
1766 * path.
1767 * <p>
1768 * There are no default serializable fields as of 1.6.
1769 * <p>
1770 * The serial data for this object is described in the
1771 * writeObject method.
1772 *
1773 * @since 1.6
1774 */
1775 private void readObject(java.io.ObjectInputStream s)
1776 throws java.lang.ClassNotFoundException, java.io.IOException
1777 {
1778 super.readObject(s, true);
1779 }
1780
1781 static class CopyIterator extends Path2D.Iterator {
1782 double[] doubleCoords;
1783
1784 CopyIterator(Path2D.Double p2dd) {
1785 super(p2dd);
1786 this.doubleCoords = p2dd.doubleCoords;
1787 }
1788
1789 public int currentSegment(float[] coords) {
1790 int type = path.pointTypes[typeIdx];
1791 int numCoords = curvecoords[type];
1792 if (numCoords > 0) {
1793 for (int i = 0; i < numCoords; i++) {
1794 coords[i] = (float) doubleCoords[pointIdx + i];
1795 }
1796 }
1797 return type;
1798 }
1799
1800 public int currentSegment(double[] coords) {
1801 int type = path.pointTypes[typeIdx];
1802 int numCoords = curvecoords[type];
1803 if (numCoords > 0) {
1804 System.arraycopy(doubleCoords, pointIdx,
1805 coords, 0, numCoords);
1806 }
1807 return type;
1808 }
1809 }
1810
1811 static class TxIterator extends Path2D.Iterator {
1812 double[] doubleCoords;
1813 AffineTransform affine;
1814
1815 TxIterator(Path2D.Double p2dd, AffineTransform at) {
1816 super(p2dd);
1817 this.doubleCoords = p2dd.doubleCoords;
1818 this.affine = at;
1819 }
1820
1821 public int currentSegment(float[] coords) {
1822 int type = path.pointTypes[typeIdx];
1823 int numCoords = curvecoords[type];
1824 if (numCoords > 0) {
1825 affine.transform(doubleCoords, pointIdx,
1826 coords, 0, numCoords / 2);
1827 }
1828 return type;
1829 }
1830
1831 public int currentSegment(double[] coords) {
1832 int type = path.pointTypes[typeIdx];
2520 private static final byte SERIAL_STORAGE_DBL_ARRAY = 0x31;
2521
2522 private static final byte SERIAL_SEG_FLT_MOVETO = 0x40;
2523 private static final byte SERIAL_SEG_FLT_LINETO = 0x41;
2524 private static final byte SERIAL_SEG_FLT_QUADTO = 0x42;
2525 private static final byte SERIAL_SEG_FLT_CUBICTO = 0x43;
2526
2527 private static final byte SERIAL_SEG_DBL_MOVETO = 0x50;
2528 private static final byte SERIAL_SEG_DBL_LINETO = 0x51;
2529 private static final byte SERIAL_SEG_DBL_QUADTO = 0x52;
2530 private static final byte SERIAL_SEG_DBL_CUBICTO = 0x53;
2531
2532 private static final byte SERIAL_SEG_CLOSE = 0x60;
2533 private static final byte SERIAL_PATH_END = 0x61;
2534
2535 final void writeObject(java.io.ObjectOutputStream s, boolean isdbl)
2536 throws java.io.IOException
2537 {
2538 s.defaultWriteObject();
2539
2540 float[] fCoords;
2541 double[] dCoords;
2542
2543 if (isdbl) {
2544 dCoords = ((Path2D.Double) this).doubleCoords;
2545 fCoords = null;
2546 } else {
2547 fCoords = ((Path2D.Float) this).floatCoords;
2548 dCoords = null;
2549 }
2550
2551 int numTypes = this.numTypes;
2552
2553 s.writeByte(isdbl
2554 ? SERIAL_STORAGE_DBL_ARRAY
2555 : SERIAL_STORAGE_FLT_ARRAY);
2556 s.writeInt(numTypes);
2557 s.writeInt(numCoords);
2558 s.writeByte((byte) windingRule);
2559
2560 int cindex = 0;
2561 for (int i = 0; i < numTypes; i++) {
2709 while (--npoints >= 0) {
2710 append(s.readDouble(), s.readDouble());
2711 }
2712 } else {
2713 while (--npoints >= 0) {
2714 append(s.readFloat(), s.readFloat());
2715 }
2716 }
2717 pointTypes[numTypes++] = segtype;
2718 }
2719 if (nT >= 0 && s.readByte() != SERIAL_PATH_END) {
2720 throw new StreamCorruptedException("missing PATH_END");
2721 }
2722 }
2723
2724 abstract static class Iterator implements PathIterator {
2725 int typeIdx;
2726 int pointIdx;
2727 Path2D path;
2728
2729 static final int[] curvecoords = {2, 2, 4, 6, 0};
2730
2731 Iterator(Path2D path) {
2732 this.path = path;
2733 }
2734
2735 public int getWindingRule() {
2736 return path.getWindingRule();
2737 }
2738
2739 public boolean isDone() {
2740 return (typeIdx >= path.numTypes);
2741 }
2742
2743 public void next() {
2744 int type = path.pointTypes[typeIdx++];
2745 pointIdx += curvecoords[type];
2746 }
2747 }
2748 }
|