blob: c26c14671ac1b46de401b678e994bd93508882c3 [file] [log] [blame]
/*
* 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;
}
}