--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/geom/AffineTransform/GetTypeOptimization.java Thu Oct 30 11:08:27 2014 -0700
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 4418285
+ * @summary Tests that transforms modified with degenerate operations
+ * continue to return their more optimal type from getType().
+ * This test also confirms that isIdentity() returns the
+ * optimal value under all histories of modification.
+ * @run main GetTypeOptimization
+ */
+
+import java.awt.geom.AffineTransform;
+import java.util.Random;
+
+public class GetTypeOptimization {
+ static int TYPE_IDENTITY = AffineTransform.TYPE_IDENTITY;
+ static int TYPE_TRANSLATION = AffineTransform.TYPE_TRANSLATION;
+ static int TYPE_UNIFORM_SCALE = AffineTransform.TYPE_UNIFORM_SCALE;
+ static int TYPE_GENERAL_SCALE = AffineTransform.TYPE_GENERAL_SCALE;
+ static int TYPE_FLIP = AffineTransform.TYPE_FLIP;
+ static int TYPE_QUADRANT_ROTATION = AffineTransform.TYPE_QUADRANT_ROTATION;
+ static int TYPE_GENERAL_ROTATION = AffineTransform.TYPE_GENERAL_ROTATION;
+ static int TYPE_GENERAL_TRANSFORM = AffineTransform.TYPE_GENERAL_TRANSFORM;
+
+ public static Random rand = new Random();
+
+ public static boolean verbose;
+ public static int numerrors;
+
+ public static void main(String argv[]) {
+ verbose = (argv.length != 0);
+
+ checkBug4418285();
+
+ checkAtType(new AffineTransform());
+ checkAtType(AffineTransform.getTranslateInstance(0, 0));
+ checkAtType(AffineTransform.getScaleInstance(1, 1));
+ checkAtType(AffineTransform.getShearInstance(0, 0));
+ checkAtType(AffineTransform.getRotateInstance(0));
+ checkAtType(AffineTransform.getRotateInstance(0, 0, 0));
+ for (int i = 90; i <= 360; i += 90) {
+ double angle = Math.toRadians(i);
+ checkAtType(AffineTransform.getRotateInstance(angle));
+ checkAtType(AffineTransform.getRotateInstance(angle, 0, 0));
+ }
+
+ AffineTransform at = new AffineTransform();
+ checkAtType(at);
+
+ at.setToIdentity(); checkAtType(at);
+ at.setToTranslation(0.0, 0.0); checkAtType(at);
+ at.setToScale(1.0, 1.0); checkAtType(at);
+ at.setToShear(0.0, 0.0); checkAtType(at);
+ at.setToRotation(0); checkAtType(at);
+ at.setToRotation(0, 0, 0); checkAtType(at);
+ for (int i = 90; i <= 360; i += 90) {
+ double angle = Math.toRadians(i);
+ at.setToRotation(angle); checkAtType(at);
+ at.setToRotation(angle, 0, 0); checkAtType(at);
+ }
+
+ at.setToIdentity(); at.scale(1, 1); checkAtType(at);
+ at.setToIdentity(); at.translate(0, 0); checkAtType(at);
+ at.setToIdentity(); at.shear(0, 0); checkAtType(at);
+ at.setToIdentity(); at.rotate(0); checkAtType(at);
+ for (int i = 90; i <= 360; i += 90) {
+ double angle = Math.toRadians(i);
+ at.setToIdentity(); at.rotate(angle); checkAtType(at);
+ at.setToIdentity(); at.rotate(angle, 0, 0); checkAtType(at);
+ }
+
+ at.setToIdentity();
+ for (int i = 0; i < 4; i++) {
+ at.rotate(Math.toRadians(90)); checkAtType(at);
+ }
+
+ at.setToIdentity();
+ at.scale(2, 2); checkAtType(at);
+ at.scale(.5, .5); checkAtType(at);
+
+ for (int n = 1; n <= 3; n++) {
+ for (int i = 0; i < 500; i++) {
+ checkAtType(makeRandomTransform(n));
+ }
+ }
+ if (numerrors != 0) {
+ if (!verbose) {
+ System.err.println("Rerun test with an argument for details");
+ }
+ throw new RuntimeException(numerrors+" tests failed!");
+ }
+ }
+
+ public static void checkBug4418285() {
+ AffineTransform id =
+ new AffineTransform ();
+ AffineTransform translate0 =
+ AffineTransform.getTranslateInstance (0, 0);
+ if (id.isIdentity() != translate0.isIdentity() ||
+ id.getType() != translate0.getType())
+ {
+ numerrors++;
+ if (verbose) {
+ System.err.println("id= " + id +
+ ", isIdentity()=" +
+ id.isIdentity());
+ System.err.println("translate0=" + translate0 +
+ ", isIdentity()=" +
+ translate0.isIdentity());
+ System.err.println("equals=" + id.equals (translate0));
+ System.err.println();
+ }
+ }
+ }
+
+ public static AffineTransform makeRandomTransform(int numops) {
+ AffineTransform at = new AffineTransform();
+ while (--numops >= 0) {
+ switch (rand.nextInt(4)) {
+ case 0:
+ at.scale(rand.nextDouble() * 5 - 2.5,
+ rand.nextDouble() * 5 - 2.5);
+ break;
+ case 1:
+ at.shear(rand.nextDouble() * 5 - 2.5,
+ rand.nextDouble() * 5 - 2.5);
+ break;
+ case 2:
+ at.rotate(rand.nextDouble() * Math.PI * 2);
+ break;
+ case 3:
+ at.translate(rand.nextDouble() * 50 - 25,
+ rand.nextDouble() * 50 - 25);
+ break;
+ default:
+ throw new InternalError("bad case!");
+ }
+ }
+ return at;
+ }
+
+ public static void checkAtType(AffineTransform at) {
+ int reftype = getRefType(at);
+ boolean isident = isIdentity(at);
+ for (int i = 0; i < 5; i++) {
+ boolean atisident = at.isIdentity();
+ int attype = at.getType();
+ if (isident != atisident || reftype != attype) {
+ numerrors++;
+ if (verbose) {
+ System.err.println(at+".isIdentity() == "+atisident);
+ System.err.println(at+".getType() == "+attype);
+ System.err.println("should be "+isident+", "+reftype);
+ new Throwable().printStackTrace();
+ System.err.println();
+ }
+ break;
+ }
+ }
+ }
+
+ public static boolean isIdentity(AffineTransform at) {
+ return (at.getScaleX() == 1 &&
+ at.getScaleY() == 1 &&
+ at.getShearX() == 0 &&
+ at.getShearY() == 0 &&
+ at.getTranslateX() == 0 &&
+ at.getTranslateY() == 0);
+
+ }
+
+ public static int getRefType(AffineTransform at) {
+ double m00 = at.getScaleX();
+ double m11 = at.getScaleY();
+ double m01 = at.getShearX();
+ double m10 = at.getShearY();
+ if (m00 * m01 + m10 * m11 != 0) {
+ // Transformed unit vectors are not perpendicular...
+ return TYPE_GENERAL_TRANSFORM;
+ }
+ int type = ((at.getTranslateX() != 0 || at.getTranslateY() != 0)
+ ? TYPE_TRANSLATION : TYPE_IDENTITY);
+ boolean sgn0, sgn1;
+ if (m01 == 0 && m10 == 0) {
+ sgn0 = (m00 >= 0.0);
+ sgn1 = (m11 >= 0.0);
+ if (sgn0 == sgn1) {
+ if (sgn0) {
+ // Both scaling factors non-negative - simple scale
+ if (m00 != m11) {
+ type |= TYPE_GENERAL_SCALE;
+ } else if (m00 != 1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+ } else {
+ // Both scaling factors negative - 180 degree rotation
+ type |= TYPE_QUADRANT_ROTATION;
+ if (m00 != m11) {
+ type |= TYPE_GENERAL_SCALE;
+ } else if (m00 != -1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+ }
+ } else {
+ // Scaling factor signs different - flip about some axis
+ type |= TYPE_FLIP;
+ if (m00 != -m11) {
+ type |= TYPE_GENERAL_SCALE;
+ } else if (m00 != 1.0 && m00 != -1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+ }
+ } else if (m00 == 0 && m11 == 0) {
+ sgn0 = (m01 >= 0.0);
+ sgn1 = (m10 >= 0.0);
+ if (sgn0 != sgn1) {
+ // Different signs - simple 90 degree rotation
+ if (m01 != -m10) {
+ type |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
+ } else if (m01 != 1.0 && m01 != -1.0) {
+ type |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
+ } else {
+ type |= TYPE_QUADRANT_ROTATION;
+ }
+ } else {
+ // Same signs - 90 degree rotation plus an axis flip too
+ if (m01 == m10) {
+ if (m01 == 0) {
+ // All four m[01][01] elements are 0
+ type |= TYPE_UNIFORM_SCALE;
+ } else {
+ // Note - shouldn't (1,1) be no scale at all?
+ type |= (TYPE_QUADRANT_ROTATION |
+ TYPE_FLIP |
+ TYPE_UNIFORM_SCALE);
+ }
+ } else {
+ type |= (TYPE_QUADRANT_ROTATION |
+ TYPE_FLIP |
+ TYPE_GENERAL_SCALE);
+ }
+ }
+ } else {
+ if (m00 * m11 >= 0.0) {
+ // sgn(m00) == sgn(m11) therefore sgn(m01) == -sgn(m10)
+ // This is the "unflipped" (right-handed) state
+ if (m00 != m11 || m01 != -m10) {
+ type |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE);
+ } else if (m00 == 0) {
+ // then m11 == 0 also
+ if (m01 == -m10) {
+ type |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE);
+ } else {
+ type |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE);
+ }
+ } else if (m00 * m11 - m01 * m10 != 1.0) {
+ type |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE);
+ } else {
+ type |= TYPE_GENERAL_ROTATION;
+ }
+ } else {
+ // sgn(m00) == -sgn(m11) therefore sgn(m01) == sgn(m10)
+ // This is the "flipped" (left-handed) state
+ if (m00 != -m11 || m01 != m10) {
+ type |= (TYPE_GENERAL_ROTATION |
+ TYPE_FLIP |
+ TYPE_GENERAL_SCALE);
+ } else if (m01 == 0) {
+ if (m00 == 1.0 || m00 == -1.0) {
+ type |= TYPE_FLIP;
+ } else {
+ type |= (TYPE_FLIP | TYPE_UNIFORM_SCALE);
+ }
+ } else if (m00 * m11 - m01 * m10 != 1.0) {
+ type |= (TYPE_GENERAL_ROTATION |
+ TYPE_FLIP |
+ TYPE_UNIFORM_SCALE);
+ } else {
+ type |= (TYPE_GENERAL_ROTATION | TYPE_FLIP);
+ }
+ }
+ }
+ return type;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/geom/AffineTransform/TestInvertMethods.java Thu Oct 30 11:08:27 2014 -0700
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 4987374
+ * @summary Unit test for inversion methods:
+ *
+ * AffineTransform.createInverse();
+ * AffineTransform.invert();
+ *
+ * @author flar
+ * @run main TestInvertMethods
+ */
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+
+/*
+ * Instances of the inner class Tester are "nodes" which take an input
+ * AffineTransform (AT), modify it in some way and pass the modified
+ * AT onto another Tester node.
+ *
+ * There is one particular Tester node of note called theVerifier.
+ * This is a leaf node which takes the input AT and tests the various
+ * inversion methods on that matrix.
+ *
+ * Most of the other Tester nodes will perform a single affine operation
+ * on their input, such as a rotate by various angles, or a scale by
+ * various predefined scale values, and then pass the modified AT on
+ * to the next node in the chain which may be a verifier or another
+ * modifier.
+ *
+ * The Tester instances can also be chained together using the chain
+ * method so that we can test not only matrices modified by some single
+ * affine operation (scale, rotate, etc.) but also composite matrices
+ * that represent multiple operations concatenated together.
+ */
+public class TestInvertMethods {
+ public static boolean verbose;
+
+ public static final double MAX_ULPS = 2.0;
+ public static double MAX_TX_ULPS = MAX_ULPS;
+ public static double maxulps = 0.0;
+ public static double maxtxulps = 0.0;
+ public static int numtests = 0;
+
+ public static void main(String argv[]) {
+ Tester rotate = new Tester.Rotate();
+ Tester scale = new Tester.Scale();
+ Tester shear = new Tester.Shear();
+ Tester translate = new Tester.Translate();
+
+ if (argv.length > 1) {
+ // This next line verifies that chaining works correctly...
+ scale.chain(translate.chain(new Tester.Debug())).test(false);
+ return;
+ }
+
+ verbose = (argv.length > 0);
+
+ new Tester.Identity().test(true);
+ translate.test(true);
+ scale.test(true);
+ rotate.test(true);
+ shear.test(true);
+ scale.chain(translate).test(true);
+ rotate.chain(translate).test(true);
+ shear.chain(translate).test(true);
+ translate.chain(scale).test(true);
+ translate.chain(rotate).test(true);
+ translate.chain(shear).test(true);
+ translate.chain(scale.chain(rotate.chain(shear))).test(false);
+ shear.chain(rotate.chain(scale.chain(translate))).test(false);
+
+ System.out.println(numtests+" tests performed");
+ System.out.println("Max scale and shear difference: "+maxulps+" ulps");
+ System.out.println("Max translate difference: "+maxtxulps+" ulps");
+ }
+
+ public abstract static class Tester {
+ public static AffineTransform IdentityTx = new AffineTransform();
+
+ /*
+ * This is the leaf node that performs inversion testing
+ * on the incoming AffineTransform.
+ */
+ public static final Tester theVerifier = new Tester() {
+ public void test(AffineTransform at, boolean full) {
+ numtests++;
+ AffineTransform inv1, inv2;
+ boolean isinvertible =
+ (Math.abs(at.getDeterminant()) >= Double.MIN_VALUE);
+ try {
+ inv1 = at.createInverse();
+ if (!isinvertible) missingNTE("createInverse", at);
+ } catch (NoninvertibleTransformException e) {
+ inv1 = null;
+ if (isinvertible) extraNTE("createInverse", at);
+ }
+ inv2 = new AffineTransform(at);
+ try {
+ inv2.invert();
+ if (!isinvertible) missingNTE("invert", at);
+ } catch (NoninvertibleTransformException e) {
+ if (isinvertible) extraNTE("invert", at);
+ }
+ if (verbose) System.out.println("at = "+at);
+ if (isinvertible) {
+ if (verbose) System.out.println(" inv1 = "+inv1);
+ if (verbose) System.out.println(" inv2 = "+inv2);
+ if (!inv1.equals(inv2)) {
+ report(at, inv1, inv2,
+ "invert methods do not agree");
+ }
+ inv1.concatenate(at);
+ inv2.concatenate(at);
+ // "Fix" some values that don't always behave
+ // well with all the math that we've done up
+ // to this point.
+ // See the note on the concatfix method below.
+ concatfix(inv1);
+ concatfix(inv2);
+ if (verbose) System.out.println(" at*inv1 = "+inv1);
+ if (verbose) System.out.println(" at*inv2 = "+inv2);
+ if (!compare(inv1, IdentityTx)) {
+ report(at, inv1, IdentityTx,
+ "createInverse() check failed");
+ }
+ if (!compare(inv2, IdentityTx)) {
+ report(at, inv2, IdentityTx,
+ "invert() check failed");
+ }
+ } else {
+ if (verbose) System.out.println(" is not invertible");
+ }
+ if (verbose) System.out.println();
+ }
+
+ void missingNTE(String methodname, AffineTransform at) {
+ throw new RuntimeException("Noninvertible was not "+
+ "thrown from "+methodname+
+ " for: "+at);
+ }
+
+ void extraNTE(String methodname, AffineTransform at) {
+ throw new RuntimeException("Unexpected Noninvertible "+
+ "thrown from "+methodname+
+ " for: "+at);
+ }
+ };
+
+ /*
+ * The inversion math may work out fairly exactly, but when
+ * we concatenate the inversions back with the original matrix
+ * in an attempt to restore them to the identity matrix,
+ * then we can end up compounding errors to a fairly high
+ * level, particularly if the component values had mantissas
+ * that were repeating fractions. This function therefore
+ * "fixes" the results of concatenating the inversions back
+ * with their original matrices to get rid of small variations
+ * in the values that should have ended up being 0.0.
+ */
+ public void concatfix(AffineTransform at) {
+ double m00 = at.getScaleX();
+ double m10 = at.getShearY();
+ double m01 = at.getShearX();
+ double m11 = at.getScaleY();
+ double m02 = at.getTranslateX();
+ double m12 = at.getTranslateY();
+ if (Math.abs(m02) < 1E-10) m02 = 0.0;
+ if (Math.abs(m12) < 1E-10) m12 = 0.0;
+ if (Math.abs(m01) < 1E-15) m01 = 0.0;
+ if (Math.abs(m10) < 1E-15) m10 = 0.0;
+ at.setTransform(m00, m10,
+ m01, m11,
+ m02, m12);
+ }
+
+ public void test(boolean full) {
+ test(IdentityTx, full);
+ }
+
+ public void test(AffineTransform init, boolean full) {
+ test(init, theVerifier, full);
+ }
+
+ public void test(AffineTransform init, Tester next, boolean full) {
+ next.test(init, full);
+ }
+
+ public Tester chain(Tester next) {
+ return new Chain(this, next);
+ }
+
+ /*
+ * Utility node used to chain together two other nodes for
+ * implementing the "chain" method.
+ */
+ public static class Chain extends Tester {
+ Tester prev;
+ Tester next;
+
+ public Chain(Tester prev, Tester next) {
+ this.prev = prev;
+ this.next = next;
+ }
+
+ public void test(AffineTransform init, boolean full) {
+ prev.test(init, next, full);
+ }
+
+ public Tester chain(Tester next) {
+ this.next = this.next.chain(next);
+ return this;
+ }
+ }
+
+ /*
+ * Utility node for testing.
+ */
+ public static class Fail extends Tester {
+ public void test(AffineTransform init, Tester next, boolean full) {
+ throw new RuntimeException("Debug: Forcing failure");
+ }
+ }
+
+ /*
+ * Utility node for testing that chaining works.
+ */
+ public static class Debug extends Tester {
+ public void test(AffineTransform init, Tester next, boolean full) {
+ new Throwable().printStackTrace();
+ next.test(init, full);
+ }
+ }
+
+ /*
+ * NOP node.
+ */
+ public static class Identity extends Tester {
+ public void test(AffineTransform init, Tester next, boolean full) {
+ if (verbose) System.out.println("*Identity = "+init);
+ next.test(init, full);
+ }
+ }
+
+ /*
+ * Affine rotation node.
+ */
+ public static class Rotate extends Tester {
+ public void test(AffineTransform init, Tester next, boolean full) {
+ int inc = full ? 10 : 45;
+ for (int i = -720; i <= 720; i += inc) {
+ AffineTransform at2 = new AffineTransform(init);
+ at2.rotate(Math.toRadians(i));
+ if (verbose) System.out.println("*Rotate("+i+") = "+at2);
+ next.test(at2, full);
+ }
+ }
+ }
+
+ public static final double SMALL_VALUE = .0001;
+ public static final double LARGE_VALUE = 10000;
+
+ /*
+ * Affine scale node.
+ */
+ public static class Scale extends Tester {
+ public double fullvals[] = {
+ // Noninvertibles
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+
+ // Invertibles
+ SMALL_VALUE, SMALL_VALUE,
+ SMALL_VALUE, 1.0,
+ 1.0, SMALL_VALUE,
+
+ SMALL_VALUE, LARGE_VALUE,
+ LARGE_VALUE, SMALL_VALUE,
+
+ LARGE_VALUE, LARGE_VALUE,
+ LARGE_VALUE, 1.0,
+ 1.0, LARGE_VALUE,
+
+ 0.5, 0.5,
+ 1.0, 1.0,
+ 2.0, 2.0,
+ Math.PI, Math.E,
+ };
+ public double abbrevvals[] = {
+ 0.0, 0.0,
+ 1.0, 1.0,
+ 2.0, 3.0,
+ };
+
+ public void test(AffineTransform init, Tester next, boolean full) {
+ double scales[] = (full ? fullvals : abbrevvals);
+ for (int i = 0; i < scales.length; i += 2) {
+ AffineTransform at2 = new AffineTransform(init);
+ at2.scale(scales[i], scales[i+1]);
+ if (verbose) System.out.println("*Scale("+scales[i]+", "+
+ scales[i+1]+") = "+at2);
+ next.test(at2, full);
+ }
+ }
+ }
+
+ /*
+ * Affine shear node.
+ */
+ public static class Shear extends Tester {
+ public double fullvals[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+
+ // Noninvertible
+ 1.0, 1.0,
+
+ SMALL_VALUE, SMALL_VALUE,
+ SMALL_VALUE, LARGE_VALUE,
+ LARGE_VALUE, SMALL_VALUE,
+ LARGE_VALUE, LARGE_VALUE,
+
+ Math.PI, Math.E,
+ };
+ public double abbrevvals[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+
+ // Noninvertible
+ 1.0, 1.0,
+ };
+
+ public void test(AffineTransform init, Tester next, boolean full) {
+ double shears[] = (full ? fullvals : abbrevvals);
+ for (int i = 0; i < shears.length; i += 2) {
+ AffineTransform at2 = new AffineTransform(init);
+ at2.shear(shears[i], shears[i+1]);
+ if (verbose) System.out.println("*Shear("+shears[i]+", "+
+ shears[i+1]+") = "+at2);
+ next.test(at2, full);
+ }
+ }
+ }
+
+ /*
+ * Affine translate node.
+ */
+ public static class Translate extends Tester {
+ public double fullvals[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+
+ SMALL_VALUE, SMALL_VALUE,
+ SMALL_VALUE, LARGE_VALUE,
+ LARGE_VALUE, SMALL_VALUE,
+ LARGE_VALUE, LARGE_VALUE,
+
+ Math.PI, Math.E,
+ };
+ public double abbrevvals[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ Math.PI, Math.E,
+ };
+
+ public void test(AffineTransform init, Tester next, boolean full) {
+ double translates[] = (full ? fullvals : abbrevvals);
+ for (int i = 0; i < translates.length; i += 2) {
+ AffineTransform at2 = new AffineTransform(init);
+ at2.translate(translates[i], translates[i+1]);
+ if (verbose) System.out.println("*Translate("+
+ translates[i]+", "+
+ translates[i+1]+") = "+at2);
+ next.test(at2, full);
+ }
+ }
+ }
+ }
+
+ public static void report(AffineTransform orig,
+ AffineTransform at1, AffineTransform at2,
+ String message)
+ {
+ System.out.println(orig+", type = "+orig.getType());
+ System.out.println(at1+", type = "+at1.getType());
+ System.out.println(at2+", type = "+at2.getType());
+ System.out.println("ScaleX values differ by "+
+ ulps(at1.getScaleX(),
+ at2.getScaleX())+" ulps");
+ System.out.println("ScaleY values differ by "+
+ ulps(at1.getScaleY(),
+ at2.getScaleY())+" ulps");
+ System.out.println("ShearX values differ by "+
+ ulps(at1.getShearX(),
+ at2.getShearX())+" ulps");
+ System.out.println("ShearY values differ by "+
+ ulps(at1.getShearY(),
+ at2.getShearY())+" ulps");
+ System.out.println("TranslateX values differ by "+
+ ulps(at1.getTranslateX(),
+ at2.getTranslateX())+" ulps");
+ System.out.println("TranslateY values differ by "+
+ ulps(at1.getTranslateY(),
+ at2.getTranslateY())+" ulps");
+ throw new RuntimeException(message);
+ }
+
+ public static boolean compare(AffineTransform at1, AffineTransform at2) {
+ maxulps = Math.max(maxulps, ulps(at1.getScaleX(), at2.getScaleX()));
+ maxulps = Math.max(maxulps, ulps(at1.getScaleY(), at2.getScaleY()));
+ maxulps = Math.max(maxulps, ulps(at1.getShearX(), at2.getShearX()));
+ maxulps = Math.max(maxulps, ulps(at1.getShearY(), at2.getShearY()));
+ maxtxulps = Math.max(maxtxulps,
+ ulps(at1.getTranslateX(), at2.getTranslateX()));
+ maxtxulps = Math.max(maxtxulps,
+ ulps(at1.getTranslateY(), at2.getTranslateY()));
+ return (getModifiedType(at1) == getModifiedType(at2) &&
+ (compare(at1.getScaleX(), at2.getScaleX(), MAX_ULPS)) &&
+ (compare(at1.getScaleY(), at2.getScaleY(), MAX_ULPS)) &&
+ (compare(at1.getShearX(), at2.getShearX(), MAX_ULPS)) &&
+ (compare(at1.getShearY(), at2.getShearY(), MAX_ULPS)) &&
+ (compare(at1.getTranslateX(),
+ at2.getTranslateX(), MAX_TX_ULPS)) &&
+ (compare(at1.getTranslateY(),
+ at2.getTranslateY(), MAX_TX_ULPS)));
+ }
+
+ public static final int ANY_SCALE_MASK =
+ (AffineTransform.TYPE_UNIFORM_SCALE |
+ AffineTransform.TYPE_GENERAL_SCALE);
+ public static int getModifiedType(AffineTransform at) {
+ int type = at.getType();
+ // Some of the vector methods can introduce a tiny uniform scale
+ // at some angles...
+ if ((type & ANY_SCALE_MASK) != 0) {
+ maxulps = Math.max(maxulps, ulps(at.getDeterminant(), 1.0));
+ if (ulps(at.getDeterminant(), 1.0) <= MAX_ULPS) {
+ // Really tiny - we will ignore it
+ type &= ~ ANY_SCALE_MASK;
+ }
+ }
+ return type;
+ }
+
+ public static boolean compare(double val1, double val2, double maxulps) {
+ if (Math.abs(val1 - val2) < 1E-15) return true;
+ return (ulps(val1, val2) <= maxulps);
+ }
+
+ public static double ulps(double val1, double val2) {
+ double diff = Math.abs(val1 - val2);
+ double ulpmax = Math.min(Math.ulp(val1), Math.ulp(val2));
+ return (diff / ulpmax);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/geom/AffineTransform/TestRotateMethods.java Thu Oct 30 11:08:27 2014 -0700
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 4980035
+ * @summary Unit test for new methods:
+ *
+ * AffineTransform.getRotateInstance(double x, double y);
+ * AffineTransform.setToRotation(double x, double y);
+ * AffineTransform.rotate(double x, double y);
+ *
+ * AffineTransform.getQuadrantRotateInstance(int numquads);
+ * AffineTransform.setToQuadrantRotation(int numquads);
+ * AffineTransform.quadrantRotate(int numquads);
+ *
+ * @author flar
+ * @run main TestRotateMethods
+ */
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+
+public class TestRotateMethods {
+ /* The maximum errors allowed, measured in double precision "ulps"
+ * Note that for most fields, the tests are extremely accurate - to
+ * within 3 ulps of the smaller value in the comparison
+ * For the translation components, the tests are still very accurate,
+ * but the absolute number of ulps can be noticeably higher when we
+ * use one of the rotate methods that takes an anchor point.
+ * Since a double precision value has 56 bits of precision, even
+ * 1024 ulps is extremely small as a ratio of the value.
+ */
+ public static final double MAX_ULPS = 3.0;
+ public static final double MAX_ANCHOR_TX_ULPS = 1024.0;
+ public static double MAX_TX_ULPS = MAX_ULPS;
+
+ // Vectors for quadrant rotations
+ public static final double quadxvec[] = { 1.0, 0.0, -1.0, 0.0 };
+ public static final double quadyvec[] = { 0.0, 1.0, 0.0, -1.0 };
+
+ // Run tests once for each type of method:
+ // tx = AffineTransform.get<Rotate>Instance()
+ // tx.set<Rotate>()
+ // tx.<rotate>()
+ public static enum Mode { GET, SET, MOD };
+
+ // Used to accumulate and report largest differences encountered by tests
+ public static double maxulps = 0.0;
+ public static double maxtxulps = 0.0;
+
+ // Sample anchor points for testing.
+ public static Point2D zeropt = new Point2D.Double(0, 0);
+ public static Point2D testtxpts[] = {
+ new Point2D.Double( 5, 5),
+ new Point2D.Double( 20, -10),
+ new Point2D.Double(-Math.PI, Math.E),
+ };
+
+ public static void main(String argv[]) {
+ test(Mode.GET);
+ test(Mode.SET);
+ test(Mode.MOD);
+
+ System.out.println("Max scale and shear difference: "+maxulps+" ulps");
+ System.out.println("Max translate difference: "+maxtxulps+" ulps");
+ }
+
+ public static void test(Mode mode) {
+ MAX_TX_ULPS = MAX_ULPS; // Stricter tx testing with no anchor point
+ test(mode, 0.5, null);
+ test(mode, 1.0, null);
+ test(mode, 3.0, null);
+
+ // Anchor points make the tx values less reliable
+ MAX_TX_ULPS = MAX_ANCHOR_TX_ULPS;
+ for (int i = 0; i < testtxpts.length; i++) {
+ test(mode, 1.0, testtxpts[i]);
+ }
+ MAX_TX_ULPS = MAX_ULPS; // Restore to default
+ }
+
+ public static void verify(AffineTransform at1, AffineTransform at2,
+ Mode mode, double vectorscale, Point2D txpt,
+ String message, double num, String units)
+ {
+ if (!compare(at1, at2)) {
+ System.out.println("mode == "+mode);
+ System.out.println("vectorscale == "+vectorscale);
+ System.out.println("txpt == "+txpt);
+ System.out.println(at1+", type = "+at1.getType());
+ System.out.println(at2+", type = "+at2.getType());
+ System.out.println("ScaleX values differ by "+
+ ulps(at1.getScaleX(), at2.getScaleX())+" ulps");
+ System.out.println("ScaleY values differ by "+
+ ulps(at1.getScaleY(), at2.getScaleY())+" ulps");
+ System.out.println("ShearX values differ by "+
+ ulps(at1.getShearX(), at2.getShearX())+" ulps");
+ System.out.println("ShearY values differ by "+
+ ulps(at1.getShearY(), at2.getShearY())+" ulps");
+ System.out.println("TranslateX values differ by "+
+ ulps(at1.getTranslateX(),
+ at2.getTranslateX())+" ulps");
+ System.out.println("TranslateY values differ by "+
+ ulps(at1.getTranslateY(),
+ at2.getTranslateY())+" ulps");
+ throw new RuntimeException(message + num + units);
+ }
+ }
+
+ public static void test(Mode mode, double vectorscale, Point2D txpt) {
+ AffineTransform at1, at2, at3;
+
+ for (int deg = -720; deg <= 720; deg++) {
+ if ((deg % 90) == 0) continue;
+ double radians = Math.toRadians(deg);
+ double vecy = Math.sin(radians) * vectorscale;
+ double vecx = Math.cos(radians) * vectorscale;
+
+ at1 = makeAT(mode, txpt, radians);
+ at2 = makeAT(mode, txpt, vecx, vecy);
+ verify(at1, at2, mode, vectorscale, txpt,
+ "vector and radians do not match for ", deg, " degrees");
+
+ if (txpt == null) {
+ // Make sure output was same as a with a 0,0 anchor point
+ if (vectorscale == 1.0) {
+ // Only need to test radians method for one scale factor
+ at3 = makeAT(mode, zeropt, radians);
+ verify(at1, at3, mode, vectorscale, zeropt,
+ "radians not invariant with 0,0 translate at ",
+ deg, " degrees");
+ }
+ // But test vector methods with all scale factors
+ at3 = makeAT(mode, zeropt, vecx, vecy);
+ verify(at2, at3, mode, vectorscale, zeropt,
+ "vector not invariant with 0,0 translate at ",
+ deg, " degrees");
+ }
+ }
+
+ for (int quad = -8; quad <= 8; quad++) {
+ double degrees = quad * 90.0;
+ double radians = Math.toRadians(degrees);
+ double vecx = quadxvec[quad & 3] * vectorscale;
+ double vecy = quadyvec[quad & 3] * vectorscale;
+
+ at1 = makeAT(mode, txpt, radians);
+ at2 = makeAT(mode, txpt, vecx, vecy);
+ verify(at1, at2, mode, vectorscale, txpt,
+ "quadrant vector and radians do not match for ",
+ degrees, " degrees");
+ at2 = makeQuadAT(mode, txpt, quad);
+ verify(at1, at2, mode, vectorscale, txpt,
+ "quadrant and radians do not match for ",
+ quad, " quadrants");
+ if (txpt == null) {
+ at3 = makeQuadAT(mode, zeropt, quad);
+ verify(at2, at3, mode, vectorscale, zeropt,
+ "quadrant not invariant with 0,0 translate at ",
+ quad, " quadrants");
+ }
+ }
+ }
+
+ public static AffineTransform makeRandomAT() {
+ AffineTransform at = new AffineTransform();
+ at.scale(Math.random() * -10.0, Math.random() * 100.0);
+ at.rotate(Math.random() * Math.PI);
+ at.shear(Math.random(), Math.random());
+ at.translate(Math.random() * 300.0, Math.random() * -20.0);
+ return at;
+ }
+
+ public static AffineTransform makeAT(Mode mode, Point2D txpt,
+ double radians)
+ {
+ AffineTransform at;
+ double tx = (txpt == null) ? 0.0 : txpt.getX();
+ double ty = (txpt == null) ? 0.0 : txpt.getY();
+ switch (mode) {
+ case GET:
+ if (txpt != null) {
+ at = AffineTransform.getRotateInstance(radians, tx, ty);
+ } else {
+ at = AffineTransform.getRotateInstance(radians);
+ }
+ break;
+ case SET:
+ at = makeRandomAT();
+ if (txpt != null) {
+ at.setToRotation(radians, tx, ty);
+ } else {
+ at.setToRotation(radians);
+ }
+ break;
+ case MOD:
+ at = makeRandomAT();
+ at.setToIdentity();
+ if (txpt != null) {
+ at.rotate(radians, tx, ty);
+ } else {
+ at.rotate(radians);
+ }
+ break;
+ default:
+ throw new InternalError("unrecognized mode: "+mode);
+ }
+
+ return at;
+ }
+
+ public static AffineTransform makeAT(Mode mode, Point2D txpt,
+ double vx, double vy)
+ {
+ AffineTransform at;
+ double tx = (txpt == null) ? 0.0 : txpt.getX();
+ double ty = (txpt == null) ? 0.0 : txpt.getY();
+ switch (mode) {
+ case GET:
+ if (txpt != null) {
+ at = AffineTransform.getRotateInstance(vx, vy, tx, ty);
+ } else {
+ at = AffineTransform.getRotateInstance(vx, vy);
+ }
+ break;
+ case SET:
+ at = makeRandomAT();
+ if (txpt != null) {
+ at.setToRotation(vx, vy, tx, ty);
+ } else {
+ at.setToRotation(vx, vy);
+ }
+ break;
+ case MOD:
+ at = makeRandomAT();
+ at.setToIdentity();
+ if (txpt != null) {
+ at.rotate(vx, vy, tx, ty);
+ } else {
+ at.rotate(vx, vy);
+ }
+ break;
+ default:
+ throw new InternalError("unrecognized mode: "+mode);
+ }
+
+ return at;
+ }
+
+ public static AffineTransform makeQuadAT(Mode mode, Point2D txpt,
+ int quads)
+ {
+ AffineTransform at;
+ double tx = (txpt == null) ? 0.0 : txpt.getX();
+ double ty = (txpt == null) ? 0.0 : txpt.getY();
+ switch (mode) {
+ case GET:
+ if (txpt != null) {
+ at = AffineTransform.getQuadrantRotateInstance(quads, tx, ty);
+ } else {
+ at = AffineTransform.getQuadrantRotateInstance(quads);
+ }
+ break;
+ case SET:
+ at = makeRandomAT();
+ if (txpt != null) {
+ at.setToQuadrantRotation(quads, tx, ty);
+ } else {
+ at.setToQuadrantRotation(quads);
+ }
+ break;
+ case MOD:
+ at = makeRandomAT();
+ at.setToIdentity();
+ if (txpt != null) {
+ at.quadrantRotate(quads, tx, ty);
+ } else {
+ at.quadrantRotate(quads);
+ }
+ break;
+ default:
+ throw new InternalError("unrecognized mode: "+mode);
+ }
+
+ return at;
+ }
+
+ public static boolean compare(AffineTransform at1, AffineTransform at2) {
+ maxulps = Math.max(maxulps, ulps(at1.getScaleX(), at2.getScaleX()));
+ maxulps = Math.max(maxulps, ulps(at1.getScaleY(), at2.getScaleY()));
+ maxulps = Math.max(maxulps, ulps(at1.getShearX(), at2.getShearX()));
+ maxulps = Math.max(maxulps, ulps(at1.getShearY(), at2.getShearY()));
+ maxtxulps = Math.max(maxtxulps,
+ ulps(at1.getTranslateX(), at2.getTranslateX()));
+ maxtxulps = Math.max(maxtxulps,
+ ulps(at1.getTranslateY(), at2.getTranslateY()));
+ return (getModifiedType(at1) == getModifiedType(at2) &&
+ (compare(at1.getScaleX(), at2.getScaleX(), MAX_ULPS)) &&
+ (compare(at1.getScaleY(), at2.getScaleY(), MAX_ULPS)) &&
+ (compare(at1.getShearX(), at2.getShearX(), MAX_ULPS)) &&
+ (compare(at1.getShearY(), at2.getShearY(), MAX_ULPS)) &&
+ (compare(at1.getTranslateX(),
+ at2.getTranslateX(), MAX_TX_ULPS)) &&
+ (compare(at1.getTranslateY(),
+ at2.getTranslateY(), MAX_TX_ULPS)));
+ }
+
+ public static int getModifiedType(AffineTransform at) {
+ int type = at.getType();
+ // Some of the vector methods can introduce a tiny uniform scale
+ // at some angles...
+ if ((type & AffineTransform.TYPE_UNIFORM_SCALE) != 0) {
+ maxulps = Math.max(maxulps, ulps(at.getDeterminant(), 1.0));
+ if (ulps(at.getDeterminant(), 1.0) <= MAX_ULPS) {
+ // Really tiny - we will ignore it
+ type &= (~AffineTransform.TYPE_UNIFORM_SCALE);
+ }
+ }
+ return type;
+ }
+
+ public static boolean compare(double val1, double val2, double maxulps) {
+ return (ulps(val1, val2) <= maxulps);
+ }
+
+ public static double ulps(double val1, double val2) {
+ double diff = Math.abs(val1 - val2);
+ double ulpmax = Math.min(Math.ulp(val1), Math.ulp(val2));
+ return (diff / ulpmax);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/geom/AffineTransform/TestSerialization.java Thu Oct 30 11:08:27 2014 -0700
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 6213608
+ * @summary Test that AffineTransform can deserialize appropriate versions.
+ * @author flar
+ * @run main TestSerialization
+ */
+
+import java.io.FileInputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.awt.geom.AffineTransform;
+
+public class TestSerialization {
+ public static void main(String argv[]) {
+ if (argv.length > 0) {
+ System.out.println("Saving from: "+
+ System.getProperty("java.version"));
+ writeSer(argv[0]);
+ return;
+ }
+ System.out.println("Testing on: "+System.getProperty("java.version"));
+ testReadWrite();
+ readSer("serial.1.2", true);
+ }
+
+ public static AffineTransform testATs[] = {
+ new AffineTransform(),
+ AffineTransform.getScaleInstance(2.5, -3.0),
+ AffineTransform.getRotateInstance(Math.PI / 4.0),
+ AffineTransform.getShearInstance(1.0, -3.0),
+ AffineTransform.getTranslateInstance(25.0, 12.5),
+ makeComplexAT(),
+ };
+
+ public static AffineTransform makeComplexAT() {
+ AffineTransform at = new AffineTransform();
+ at.scale(2.5, -3.0);
+ at.rotate(Math.PI / 4.0);
+ at.shear(1.0, -3.0);
+ at.translate(25.0, 12.5);
+ return at;
+ };
+
+ public static void testReadWrite() {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ testWrite(oos);
+ oos.flush();
+ oos.close();
+ byte buf[] = baos.toByteArray();
+ ByteArrayInputStream bais = new ByteArrayInputStream(buf);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ testRead(ois, true);
+ } catch (InvalidClassException ice) {
+ throw new RuntimeException("Object read failed from loopback");
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("IOException testing loopback");
+ }
+ }
+
+ public static String resolve(String relfilename) {
+ String dir = System.getProperty("test.src");
+ if (dir == null) {
+ return relfilename;
+ } else {
+ return dir+"/"+relfilename;
+ }
+ }
+
+ public static void readSer(String filename, boolean shouldsucceed) {
+ try {
+ FileInputStream fis = new FileInputStream(resolve(filename));
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ testRead(ois, shouldsucceed);
+ } catch (InvalidClassException ice) {
+ throw new RuntimeException("Object read failed from: "+filename);
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("IOException reading: "+filename);
+ }
+ }
+
+ public static void testRead(ObjectInputStream ois, boolean shouldsucceed)
+ throws IOException
+ {
+ for (int i = 0; i < testATs.length; i++) {
+ AffineTransform at;
+ try {
+ at = (AffineTransform) ois.readObject();
+ if (!shouldsucceed) {
+ throw new RuntimeException("readObj did not fail");
+ }
+ } catch (ClassNotFoundException e) {
+ // Should never happen, but must catch declared exceptions...
+ throw new RuntimeException("AffineTransform not found!");
+ } catch (InvalidClassException e) {
+ if (shouldsucceed) {
+ throw e;
+ }
+ continue;
+ }
+ if (!testATs[i].equals(at)) {
+ throw new RuntimeException("wrong AT read from stream");
+ }
+ }
+ }
+
+ public static void writeSer(String filename) {
+ try {
+ FileOutputStream fos = new FileOutputStream(filename);
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ testWrite(oos);
+ oos.flush();
+ oos.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("IOException writing: "+filename);
+ }
+ }
+
+ public static void testWrite(ObjectOutputStream oos)
+ throws IOException
+ {
+ for (int i = 0; i < testATs.length; i++) {
+ oos.writeObject(testATs[i]);
+ }
+ }
+}
Binary file jdk/test/java/awt/geom/AffineTransform/serial.1.2 has changed