From 8b2bf84b5e6107310cf9901e209b81168932da9c Mon Sep 17 00:00:00 2001 From: Dumbo52 Date: Sat, 21 Feb 2015 17:52:22 -0500 Subject: [PATCH] Fix imprecise rotations bug. The bug this fixes is documented here: http://youtrack.sk89q.com/issue/WORLDEDIT-3220 --- .../com/sk89q/worldedit/math/MathUtils.java | 58 +++++++++++++++++++ .../math/transform/AffineTransform.java | 16 +++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MathUtils.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MathUtils.java index 65a72a72c..80f310af5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/MathUtils.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/MathUtils.java @@ -47,4 +47,62 @@ public final class MathUtils { return (int) (a - n * Math.floor(Math.floor(a) / n)); } + /** + * Returns the cosine of an angle given in degrees. This is better than + * just {@code Math.cos(Math.toRadians(degrees))} because it provides a + * more accurate result for angles divisible by 90 degrees. + * + * @param degrees the angle + * @return the cosine of the given angle + */ + public static double dCos(double degrees) { + int dInt = (int) degrees; + if (degrees == dInt && dInt % 90 == 0) { + dInt %= 360; + if (dInt < 0) { + dInt += 360; + } + switch (dInt) { + case 0: + return 1.0; + case 90: + return 0.0; + case 180: + return -1.0; + case 270: + return 0.0; + } + } + return Math.cos(Math.toRadians(degrees)); + } + + /** + * Returns the sine of an angle given in degrees. This is better than just + * {@code Math.cos(Math.toRadians(degrees))} because it provides a more + * accurate result for angles divisible by 90 degrees. + * + * @param degrees the angle + * @return the sine of the given angle + */ + public static double dSin(double degrees) { + int dInt = (int) degrees; + if (degrees == dInt && dInt % 90 == 0) { + dInt %= 360; + if (dInt < 0) { + dInt += 360; + } + switch (dInt) { + case 0: + return 0.0; + case 90: + return 1.0; + case 180: + return 0.0; + case 270: + return -1.0; + } + } + return Math.cos(Math.toRadians(degrees)); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java index aabcbd1ad..41d85904a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/transform/AffineTransform.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.math.transform; import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.math.MathUtils; /** * An affine transform. @@ -244,9 +245,8 @@ public class AffineTransform implements Transform { } public AffineTransform rotateX(double theta) { - theta = Math.toRadians(theta); - double cot = Math.cos(theta); - double sit = Math.sin(theta); + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); return concatenate( new AffineTransform( 1, 0, 0, 0, @@ -255,9 +255,8 @@ public class AffineTransform implements Transform { } public AffineTransform rotateY(double theta) { - theta = Math.toRadians(theta); - double cot = Math.cos(theta); - double sit = Math.sin(theta); + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); return concatenate( new AffineTransform( cot, 0, sit, 0, @@ -266,9 +265,8 @@ public class AffineTransform implements Transform { } public AffineTransform rotateZ(double theta) { - theta = Math.toRadians(theta); - double cot = Math.cos(theta); - double sit = Math.sin(theta); + double cot = MathUtils.dCos(theta); + double sit = MathUtils.dSin(theta); return concatenate( new AffineTransform( cot, -sit, 0, 0,