1 /*
   2  * Copyright (c) 2015, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 import java.awt.Rectangle;
  26 import java.awt.geom.AffineTransform;
  27 import java.awt.geom.GeneralPath;
  28 import java.awt.geom.IllegalPathStateException;
  29 import java.awt.geom.Path2D;
  30 import java.awt.geom.PathIterator;
  31 import java.awt.geom.Point2D;
  32 import java.awt.geom.Rectangle2D;
  33 import java.util.Arrays;
  34 
  35 /**
  36  * @test
  37  * @bug 8076419, 8078192
  38  * @summary Check Path2D copy constructor (trims arrays)
  39  *          and constructor with zero capacity
  40  *          and Path2D.trimToSize()
  41  * @run main Path2DCopyConstructor
  42  */
  43 public class Path2DCopyConstructor {
  44 
  45     private final static float EPSILON = 5e-6f;
  46     private final static float FLATNESS = 1e-2f;
  47 
  48     private final static AffineTransform at
  49         = AffineTransform.getScaleInstance(1.3, 2.4);
  50 
  51     private final static Rectangle2D.Double rect2d
  52         = new Rectangle2D.Double(3.2, 4.1, 5.0, 10.0);
  53 
  54     private final static Point2D.Double pt2d
  55         = new Point2D.Double(2.0, 2.5);
  56 
  57     public static boolean verbose;
  58 
  59     static void log(String msg) {
  60         if (verbose) {
  61             System.out.println(msg);
  62         }
  63     }
  64 
  65     public static void main(String argv[]) {
  66         verbose = (argv.length != 0);
  67 
  68         testEmptyDoublePaths();
  69         testDoublePaths();
  70 
  71         testEmptyFloatPaths();
  72         testFloatPaths();
  73 
  74         testEmptyGeneralPath();
  75         testGeneralPath();
  76     }
  77 
  78     static void testEmptyDoublePaths() {
  79         log("\n - Test(Path2D.Double[0]) ---");
  80         test(() -> new Path2D.Double(Path2D.WIND_NON_ZERO, 0));
  81     }
  82 
  83     static void testDoublePaths() {
  84         log("\n - Test(Path2D.Double) ---");
  85         test(() -> new Path2D.Double());
  86     }
  87 
  88     static void testEmptyFloatPaths() {
  89         log("\n - Test(Path2D.Float[0]) ---");
  90         test(() -> new Path2D.Float(Path2D.WIND_NON_ZERO, 0));
  91     }
  92 
  93     static void testFloatPaths() {
  94         log("\n - Test(Path2D.Float) ---");
  95         test(() -> new Path2D.Float());
  96     }
  97 
  98     static void testEmptyGeneralPath() {
  99         log("\n - Test(GeneralPath[0]) ---");
 100         test(() -> new GeneralPath(Path2D.WIND_NON_ZERO, 0));
 101     }
 102 
 103     static void testGeneralPath() {
 104         log("\n - Test(GeneralPath) ---");
 105         test(() -> new GeneralPath());
 106     }
 107 
 108     interface PathFactory {
 109         Path2D makePath();
 110     }
 111 
 112     static void test(PathFactory pf) {
 113         log("\n --- test: path(empty) ---");
 114         test(pf.makePath(), true);
 115         log("\n\n --- test: path(addMove) ---");
 116         test(addMove(pf.makePath()), false);
 117         log("\n\n --- test: path(addMoveAndLines) ---");
 118         test(addMoveAndLines(pf.makePath()), false);
 119         log("\n\n --- test: path(addMoveAndQuads) ---");
 120         test(addMoveAndQuads(pf.makePath()), false);
 121         log("\n\n --- test: path(addMoveAndCubics) ---");
 122         test(addMoveAndCubics(pf.makePath()), false);
 123         log("\n\n --- test: path(addMoveAndClose) ---");
 124         test(addMoveAndClose(pf.makePath()), false);
 125     }
 126 
 127     static Path2D addMove(Path2D p2d) {
 128         p2d.moveTo(1.0, 0.5);
 129         return p2d;
 130     }
 131 
 132     static Path2D addMoveAndLines(Path2D p2d) {
 133         addMove(p2d);
 134         addLines(p2d);
 135         return p2d;
 136     }
 137 
 138     static Path2D addLines(Path2D p2d) {
 139         for (int i = 0; i < 10; i++) {
 140             p2d.lineTo(1.1 * i, 2.3 * i);
 141         }
 142         return p2d;
 143     }
 144 
 145     static Path2D addMoveAndCubics(Path2D p2d) {
 146         addMove(p2d);
 147         addCubics(p2d);
 148         return p2d;
 149     }
 150 
 151     static Path2D addCubics(Path2D p2d) {
 152         for (int i = 0; i < 10; i++) {
 153             p2d.curveTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i, 1.5 * i, 1.6 * i);
 154         }
 155         return p2d;
 156     }
 157 
 158     static Path2D addMoveAndQuads(Path2D p2d) {
 159         addMove(p2d);
 160         addQuads(p2d);
 161         return p2d;
 162     }
 163 
 164     static Path2D addQuads(Path2D p2d) {
 165         for (int i = 0; i < 10; i++) {
 166             p2d.quadTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i);
 167         }
 168         return p2d;
 169     }
 170 
 171     static Path2D addMoveAndClose(Path2D p2d) {
 172         addMove(p2d);
 173         addClose(p2d);
 174         return p2d;
 175     }
 176 
 177     static Path2D addClose(Path2D p2d) {
 178         p2d.closePath();
 179         return p2d;
 180     }
 181 
 182     static void test(Path2D p2d, boolean isEmpty) {
 183         Path2D c;
 184         Path2D.Float pf;
 185         Path2D.Double pd;
 186         GeneralPath gp;
 187 
 188         pf = new Path2D.Float(p2d);
 189         testEqual(pf, p2d);
 190         testEqual(pf.trimToSize(), p2d);
 191         pd = new Path2D.Double(p2d);
 192         testEqual(pd, p2d);
 193         testEqual(pf.trimToSize(), p2d);
 194         c = (Path2D)p2d.clone();
 195         testEqual(c, p2d);
 196         testEqual(c.trimToSize(), p2d);
 197         gp = new GeneralPath(p2d);
 198         testEqual(gp, p2d);
 199         testEqual(gp.trimToSize(), p2d);
 200 
 201         pf = new Path2D.Float(p2d);
 202         testIterator(pf, p2d);
 203         testIterator(pf.trimToSize(), p2d);
 204         pd = new Path2D.Double(p2d);
 205         testIterator(pd, p2d);
 206         testIterator(pf.trimToSize(), p2d);
 207         c = (Path2D)p2d.clone();
 208         testIterator(c, p2d);
 209         testIterator(c.trimToSize(), p2d);
 210         gp = new GeneralPath(p2d);
 211         testIterator(gp, p2d);
 212         testIterator(gp.trimToSize(), p2d);
 213 
 214         pf = new Path2D.Float(p2d);
 215         testFlattening(pf, p2d);
 216         testFlattening(pf.trimToSize(), p2d);
 217         pd = new Path2D.Double(p2d);
 218         testFlattening(pd, p2d);
 219         testFlattening(pf.trimToSize(), p2d);
 220         c = (Path2D)p2d.clone();
 221         testFlattening(c, p2d);
 222         testFlattening(c.trimToSize(), p2d);
 223         gp = new GeneralPath(p2d);
 224         testFlattening(gp, p2d);
 225         testFlattening(gp.trimToSize(), p2d);
 226 
 227         pf = new Path2D.Float(p2d);
 228         testAddMove(pf);
 229         testAddMove(pf.trimToSize());
 230         pd = new Path2D.Double(p2d);
 231         testAddMove(pd);
 232         testAddMove(pf.trimToSize());
 233         c = (Path2D)p2d.clone();
 234         testAddMove(c);
 235         testAddMove(c.trimToSize());
 236         gp = new GeneralPath(p2d);
 237         testAddMove(gp);
 238         testAddMove(gp.trimToSize());
 239 
 240         // These should expect exception if empty
 241         pf = new Path2D.Float(p2d);
 242         testAddLine(pf, isEmpty);
 243         testAddLine(pf.trimToSize(), isEmpty);
 244         pd = new Path2D.Double(p2d);
 245         testAddLine(pd, isEmpty);
 246         testAddLine(pf.trimToSize(), isEmpty);
 247         c = (Path2D)p2d.clone();
 248         testAddLine(c, isEmpty);
 249         testAddLine(c.trimToSize(), isEmpty);
 250         gp = new GeneralPath(p2d);
 251         testAddLine(gp, isEmpty);
 252         testAddLine(gp.trimToSize(), isEmpty);
 253 
 254         pf = new Path2D.Float(p2d);
 255         testAddQuad(pf, isEmpty);
 256         testAddQuad(pf.trimToSize(), isEmpty);
 257         pd = new Path2D.Double(p2d);
 258         testAddQuad(pd, isEmpty);
 259         testAddQuad(pf.trimToSize(), isEmpty);
 260         c = (Path2D)p2d.clone();
 261         testAddQuad(c, isEmpty);
 262         testAddQuad(c.trimToSize(), isEmpty);
 263         gp = new GeneralPath(p2d);
 264         testAddQuad(gp, isEmpty);
 265         testAddQuad(gp.trimToSize(), isEmpty);
 266 
 267         pf = new Path2D.Float(p2d);
 268         testAddCubic(pf, isEmpty);
 269         testAddCubic(pf.trimToSize(), isEmpty);
 270         pd = new Path2D.Double(p2d);
 271         testAddCubic(pd, isEmpty);
 272         testAddCubic(pf.trimToSize(), isEmpty);
 273         c = (Path2D)p2d.clone();
 274         testAddCubic(c, isEmpty);
 275         testAddCubic(c.trimToSize(), isEmpty);
 276         gp = new GeneralPath(p2d);
 277         testAddCubic(gp, isEmpty);
 278         testAddCubic(gp.trimToSize(), isEmpty);
 279 
 280         pf = new Path2D.Float(p2d);
 281         testAddClose(pf, isEmpty);
 282         testAddClose(pf.trimToSize(), isEmpty);
 283         pd = new Path2D.Double(p2d);
 284         testAddClose(pd, isEmpty);
 285         testAddClose(pf.trimToSize(), isEmpty);
 286         c = (Path2D)p2d.clone();
 287         testAddClose(c, isEmpty);
 288         testAddClose(c.trimToSize(), isEmpty);
 289         gp = new GeneralPath(p2d);
 290         testAddClose(gp, isEmpty);
 291         testAddClose(gp.trimToSize(), isEmpty);
 292 
 293         pf = new Path2D.Float(p2d);
 294         testGetBounds(pf, p2d);
 295         testGetBounds(pf.trimToSize(), p2d);
 296         pd = new Path2D.Double(p2d);
 297         testGetBounds(pd, p2d);
 298         testGetBounds(pf.trimToSize(), p2d);
 299         c = (Path2D)p2d.clone();
 300         testGetBounds(c, p2d);
 301         testGetBounds(c.trimToSize(), p2d);
 302         gp = new GeneralPath(p2d);
 303         testGetBounds(gp, p2d);
 304         testGetBounds(gp.trimToSize(), p2d);
 305 
 306         pf = new Path2D.Float(p2d);
 307         testTransform(pf);
 308         testTransform(pf.trimToSize());
 309         pd = new Path2D.Double(p2d);
 310         testTransform(pd);
 311         testTransform(pf.trimToSize());
 312         c = (Path2D)p2d.clone();
 313         testTransform(c);
 314         testTransform(c.trimToSize());
 315         gp = new GeneralPath(p2d);
 316         testTransform(gp);
 317         testTransform(gp.trimToSize());
 318 
 319         pf = new Path2D.Float(p2d);
 320         testIntersect(pf, p2d);
 321         testIntersect(pf.trimToSize(), p2d);
 322         pd = new Path2D.Double(p2d);
 323         testIntersect(pd, p2d);
 324         testIntersect(pf.trimToSize(), p2d);
 325         c = (Path2D)p2d.clone();
 326         testIntersect(c, p2d);
 327         testIntersect(c.trimToSize(), p2d);
 328         gp = new GeneralPath(p2d);
 329         testIntersect(gp, p2d);
 330         testIntersect(gp.trimToSize(), p2d);
 331 
 332         pf = new Path2D.Float(p2d);
 333         testContains(pf, p2d);
 334         testContains(pf.trimToSize(), p2d);
 335         pd = new Path2D.Double(p2d);
 336         testContains(pd, p2d);
 337         testContains(pf.trimToSize(), p2d);
 338         c = (Path2D)p2d.clone();
 339         testContains(c, p2d);
 340         testContains(c.trimToSize(), p2d);
 341         gp = new GeneralPath(p2d);
 342         testContains(gp, p2d);
 343         testContains(gp.trimToSize(), p2d);
 344 
 345         pf = new Path2D.Float(p2d);
 346         testGetCurrentPoint(pf, p2d);
 347         testGetCurrentPoint(pf.trimToSize(), p2d);
 348         pd = new Path2D.Double(p2d);
 349         testGetCurrentPoint(pd, p2d);
 350         testGetCurrentPoint(pf.trimToSize(), p2d);
 351         c = (Path2D)p2d.clone();
 352         testGetCurrentPoint(c, p2d);
 353         testGetCurrentPoint(c.trimToSize(), p2d);
 354         gp = new GeneralPath(p2d);
 355         testGetCurrentPoint(gp, p2d);
 356         testGetCurrentPoint(gp.trimToSize(), p2d);
 357     }
 358 
 359     static void testEqual(Path2D pathA, Path2D pathB) {
 360         final PathIterator itA = pathA.getPathIterator(null);
 361         final PathIterator itB = pathB.getPathIterator(null);
 362 
 363         float[] coordsA = new float[6];
 364         float[] coordsB = new float[6];
 365 
 366         int n = 0;
 367         for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
 368             int typeA = itA.currentSegment(coordsA);
 369             int typeB = itB.currentSegment(coordsB);
 370 
 371             if (typeA != typeB) {
 372                 throw new IllegalStateException("Path-segment[" + n + "] "
 373                     + " type are not equals [" + typeA + "|" + typeB + "] !");
 374             }
 375             if (!equalsArray(coordsA, coordsB, getLength(typeA))) {
 376                 throw new IllegalStateException("Path-segment[" + n + "] coords"
 377                     + " are not equals [" + Arrays.toString(coordsA) + "|"
 378                     + Arrays.toString(coordsB) + "] !");
 379             }
 380         }
 381         if (!itA.isDone() || !itB.isDone()) {
 382             throw new IllegalStateException("Paths do not have same lengths !");
 383         }
 384         log("testEqual: " + n + " segments.");
 385     }
 386 
 387     static void testIterator(Path2D pathA, Path2D pathB) {
 388         final PathIterator itA = pathA.getPathIterator(at);
 389         final PathIterator itB = pathB.getPathIterator(at);
 390 
 391         float[] coordsA = new float[6];
 392         float[] coordsB = new float[6];
 393 
 394         int n = 0;
 395         for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
 396             int typeA = itA.currentSegment(coordsA);
 397             int typeB = itB.currentSegment(coordsB);
 398 
 399             if (typeA != typeB) {
 400                 throw new IllegalStateException("Path-segment[" + n + "] "
 401                     + "type are not equals [" + typeA + "|" + typeB + "] !");
 402             }
 403             // Take care of floating-point precision:
 404             if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) {
 405                 throw new IllegalStateException("Path-segment[" + n + "] coords"
 406                     + " are not equals [" + Arrays.toString(coordsA) + "|"
 407                     + Arrays.toString(coordsB) + "] !");
 408             }
 409         }
 410         if (!itA.isDone() || !itB.isDone()) {
 411             throw new IllegalStateException("Paths do not have same lengths !");
 412         }
 413         log("testIterator: " + n + " segments.");
 414     }
 415 
 416     static void testFlattening(Path2D pathA, Path2D pathB) {
 417         final PathIterator itA = pathA.getPathIterator(at, FLATNESS);
 418         final PathIterator itB = pathB.getPathIterator(at, FLATNESS);
 419 
 420         float[] coordsA = new float[6];
 421         float[] coordsB = new float[6];
 422 
 423         int n = 0;
 424         for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) {
 425             int typeA = itA.currentSegment(coordsA);
 426             int typeB = itB.currentSegment(coordsB);
 427 
 428             if (typeA != typeB) {
 429                 throw new IllegalStateException("Path-segment[" + n + "] "
 430                     + "type are not equals [" + typeA + "|" + typeB + "] !");
 431             }
 432             // Take care of floating-point precision:
 433             if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) {
 434                 throw new IllegalStateException("Path-segment[" + n + "] coords"
 435                     + " are not equals [" + Arrays.toString(coordsA) + "|"
 436                     + Arrays.toString(coordsB) + "] !");
 437             }
 438         }
 439         if (!itA.isDone() || !itB.isDone()) {
 440             throw new IllegalStateException("Paths do not have same lengths !");
 441         }
 442         log("testFlattening: " + n + " segments.");
 443     }
 444 
 445     static void testAddMove(Path2D pathA) {
 446         addMove(pathA);
 447         log("testAddMove: passed.");
 448     }
 449 
 450     static void testAddLine(Path2D pathA, boolean isEmpty) {
 451         try {
 452             addLines(pathA);
 453         }
 454         catch (IllegalPathStateException ipse) {
 455             if (isEmpty) {
 456                 log("testAddLine: passed "
 457                     + "(expected IllegalPathStateException catched).");
 458                 return;
 459             } else {
 460                 throw ipse;
 461             }
 462         }
 463         if (isEmpty) {
 464             throw new IllegalStateException("IllegalPathStateException not thrown !");
 465         }
 466         log("testAddLine: passed.");
 467     }
 468 
 469     static void testAddQuad(Path2D pathA, boolean isEmpty) {
 470         try {
 471             addQuads(pathA);
 472         }
 473         catch (IllegalPathStateException ipse) {
 474             if (isEmpty) {
 475                 log("testAddQuad: passed "
 476                     + "(expected IllegalPathStateException catched).");
 477                 return;
 478             } else {
 479                 throw ipse;
 480             }
 481         }
 482         if (isEmpty) {
 483             throw new IllegalStateException("IllegalPathStateException not thrown !");
 484         }
 485         log("testAddQuad: passed.");
 486     }
 487 
 488     static void testAddCubic(Path2D pathA, boolean isEmpty) {
 489         try {
 490             addCubics(pathA);
 491         }
 492         catch (IllegalPathStateException ipse) {
 493             if (isEmpty) {
 494                 log("testAddCubic: passed "
 495                     + "(expected IllegalPathStateException catched).");
 496                 return;
 497             } else {
 498                 throw ipse;
 499             }
 500         }
 501         if (isEmpty) {
 502             throw new IllegalStateException("IllegalPathStateException not thrown !");
 503         }
 504         log("testAddCubic: passed.");
 505     }
 506 
 507     static void testAddClose(Path2D pathA, boolean isEmpty) {
 508         try {
 509             addClose(pathA);
 510         }
 511         catch (IllegalPathStateException ipse) {
 512             if (isEmpty) {
 513                 log("testAddClose: passed "
 514                     + "(expected IllegalPathStateException catched).");
 515                 return;
 516             } else {
 517                 throw ipse;
 518             }
 519         }
 520         if (isEmpty) {
 521             throw new IllegalStateException("IllegalPathStateException not thrown !");
 522         }
 523         log("testAddClose: passed.");
 524     }
 525 
 526     static void testGetBounds(Path2D pathA, Path2D pathB) {
 527         final Rectangle rA = pathA.getBounds();
 528         final Rectangle rB = pathB.getBounds();
 529 
 530         if (!rA.equals(rB)) {
 531             throw new IllegalStateException("Bounds are not equals [" + rA
 532                 + "|" + rB + "] !");
 533         }
 534         final Rectangle2D r2dA = pathA.getBounds2D();
 535         final Rectangle2D r2dB = pathB.getBounds2D();
 536 
 537         if (!equalsRectangle2D(r2dA, r2dB)) {
 538             throw new IllegalStateException("Bounds2D are not equals ["
 539                 + r2dA + "|" + r2dB + "] !");
 540         }
 541         log("testGetBounds: passed.");
 542     }
 543 
 544     static void testTransform(Path2D pathA) {
 545         pathA.transform(at);
 546         log("testTransform: passed.");
 547     }
 548 
 549     static void testIntersect(Path2D pathA, Path2D pathB) {
 550         boolean resA = pathA.intersects(rect2d);
 551         boolean resB = pathB.intersects(rect2d);
 552         if (resA != resB) {
 553             throw new IllegalStateException("Intersects(rect2d) are not equals ["
 554                 + resA + "|" + resB + "] !");
 555         }
 556         resA = pathA.intersects(1.0, 2.0, 13.0, 17.0);
 557         resB = pathB.intersects(1.0, 2.0, 13.0, 17.0);
 558         if (resA != resB) {
 559             throw new IllegalStateException("Intersects(doubles) are not equals ["
 560                 + resA + "|" + resB + "] !");
 561         }
 562         log("testIntersect: passed.");
 563     }
 564 
 565     static void testContains(Path2D pathA, Path2D pathB) {
 566         boolean resA = pathA.contains(pt2d);
 567         boolean resB = pathB.contains(pt2d);
 568         if (resA != resB) {
 569             throw new IllegalStateException("Contains(pt) are not equals ["
 570                 + resA + "|" + resB + "] !");
 571         }
 572         resA = pathA.contains(pt2d.getX(), pt2d.getY());
 573         resB = pathB.contains(pt2d.getX(), pt2d.getY());
 574         if (resA != resB) {
 575             throw new IllegalStateException("Contains(x,y) are not equals ["
 576                 + resA + "|" + resB + "] !");
 577         }
 578         resA = pathA.contains(rect2d);
 579         resB = pathB.contains(rect2d);
 580         if (resA != resB) {
 581             throw new IllegalStateException("Contains(rect2d) are not equals ["
 582                 + resA + "|" + resB + "] !");
 583         }
 584         resA = pathA.contains(1.0, 2.0, 13.0, 17.0);
 585         resB = pathB.contains(1.0, 2.0, 13.0, 17.0);
 586         if (resA != resB) {
 587             throw new IllegalStateException("Contains(doubles) are not equals ["
 588                 + resA + "|" + resB + "] !");
 589         }
 590         log("testContains: passed.");
 591     }
 592 
 593     static void testGetCurrentPoint(Path2D pathA, Path2D pathB) {
 594         final Point2D ptA = pathA.getCurrentPoint();
 595         final Point2D ptB = pathA.getCurrentPoint();
 596         if (((ptA == null) && (ptB != null))
 597             || ((ptA != null) && !ptA.equals(ptB)))
 598         {
 599             throw new IllegalStateException("getCurrentPoint() are not equals ["
 600                 + ptA + "|" + ptB + "] !");
 601         }
 602         log("testGetCurrentPoint: passed.");
 603     }
 604 
 605     static int getLength(int type) {
 606         switch(type) {
 607             case PathIterator.SEG_CUBICTO:
 608                 return 6;
 609             case PathIterator.SEG_QUADTO:
 610                 return 4;
 611             case PathIterator.SEG_LINETO:
 612             case PathIterator.SEG_MOVETO:
 613                 return 2;
 614             case PathIterator.SEG_CLOSE:
 615                 return 0;
 616             default:
 617                 throw new IllegalStateException("Invalid type: " + type);
 618         }
 619     }
 620 
 621 
 622     // Custom equals methods ---
 623 
 624     public static boolean equalsArray(float[] a, float[] a2, final int len) {
 625         for (int i = 0; i < len; i++) {
 626             if (Float.floatToIntBits(a[i]) != Float.floatToIntBits(a2[i])) {
 627                 return false;
 628             }
 629         }
 630         return true;
 631     }
 632 
 633     static boolean equalsArrayEps(float[] a, float[] a2, final int len) {
 634         for (int i = 0; i < len; i++) {
 635             if (!equalsEps(a[i], a2[i])) {
 636                 return false;
 637             }
 638         }
 639 
 640         return true;
 641     }
 642 
 643     static boolean equalsRectangle2D(Rectangle2D a, Rectangle2D b) {
 644         if (a == b) {
 645             return true;
 646         }
 647         return equalsEps(a.getX(), b.getX())
 648             && equalsEps(a.getY(), b.getY())
 649             && equalsEps(a.getWidth(), b.getWidth())
 650             && equalsEps(a.getHeight(), b.getHeight());
 651     }
 652 
 653     static boolean equalsEps(float a, float b) {
 654         return (Math.abs(a - b) <= EPSILON);
 655     }
 656 
 657     static boolean equalsEps(double a, double b) {
 658         return (Math.abs(a - b) <= EPSILON);
 659     }
 660 }