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