diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java index fe896d102..2d3c18af5 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/transform/BlockTransformExtent.java @@ -198,16 +198,16 @@ public class BlockTransformExtent extends ResettableExtent { result.add(combine(NORTH, EAST, SOUTH, WEST)); continue; case "inner_left": - result.add(notIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("outer_right"), property.getIndexFor("outer_left"))); + result.add(orIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("outer_right"), property.getIndexFor("outer_left"))); continue; case "inner_right": - result.add(notIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("outer_right"), property.getIndexFor("outer_left"))); + result.add(orIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("outer_right"), property.getIndexFor("outer_left"))); continue; case "outer_left": - result.add(notIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("inner_left"), property.getIndexFor("inner_right"))); + result.add(orIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("inner_left"), property.getIndexFor("inner_right"))); continue; case "outer_right": - result.add(notIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("inner_left"), property.getIndexFor("inner_right"))); + result.add(orIndex(combine(NORTHEAST, NORTHWEST, SOUTHWEST, SOUTHEAST), property.getIndexFor("inner_left"), property.getIndexFor("inner_right"))); continue; default: LOGGER.warn("Unknown direction {}", value); @@ -265,7 +265,7 @@ public class BlockTransformExtent extends ResettableExtent { return (mask & (1L << dir.ordinal())) != 0; } - private static long notIndex(long mask, int... indexes) { + private static long orIndex(long mask, int... indexes) { for (int index : indexes) { mask = mask | (1L << (index + values().length)); } @@ -296,7 +296,8 @@ public class BlockTransformExtent extends ResettableExtent { flip = ((AffineTransform) transform).isScaled(oldVector); } - if (oldVector.equals(newVector)) { + // If we're flipping, it is possible for the old and new vectors to be equal + if (!flip && oldVector.equalsFuzzy(newVector)) { continue; } @@ -304,6 +305,7 @@ public class BlockTransformExtent extends ResettableExtent { for (int i = 0; i < directions.length; i++) { int j = (oldIndex + i) % directions.length; long newDirMask = directions[j]; + // Check if the old mask excludes it if (!hasIndex(oldDirMask, j)) { continue; } @@ -312,7 +314,6 @@ public class BlockTransformExtent extends ResettableExtent { if (!hasDirection(newDirMask, v)) { continue; } - // Check if the old mask excludes it double dot = v.toVector().normalize().dot(newVector); if (dot > closest || (flip && dot >= closest)) { // closest = dot; @@ -387,12 +388,13 @@ public class BlockTransformExtent extends ResettableExtent { newMaskedId = tmp.getInternalId(); } - + // True if relying on two different "directions" for the result, e.g. stairs with both facing and shape for (AbstractProperty property : (List>) type.getProperties()) { if (isDirectional(property)) { long[] directions = getDirections(property); if (directions != null) { - Integer newIndex = getNewStateIndex(transform, directions, property.getIndex(state.getInternalId())); + int oldIndex = property.getIndex(newMaskedId); + Integer newIndex = getNewStateIndex(transform, directions, oldIndex); if (newIndex != null) { newMaskedId = property.modifyIndex(newMaskedId, newIndex); } @@ -467,7 +469,7 @@ public class BlockTransformExtent extends ResettableExtent { @Override public > boolean setBlock(BlockVector3 location, B block) throws WorldEditException { - return super.setBlock(location, transformBlock(block, true)); + return super.setBlock(location, transformInverse(block)); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java index 2dd7a9598..1be75c018 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/math/Vector3.java @@ -650,6 +650,30 @@ public abstract class Vector3 { return other.getX() == this.getX() && other.getY() == this.getY() && other.getZ() == this.getZ(); } + /** + * Tests if vectors are equal, accounting for floating point errors + * + * @param other Another Vector3 + * @return if the vectors are effectively equal + */ + public boolean equalsFuzzy(Vector3 other) { + if (this.equals(other)) { + return true; + } + + // Minecraft deals in whole blocks, thus any difference smaller than this is unnecessary + if (Math.abs(getX() - other.getX()) > 0.000001d) { + return false; + } + if (Math.abs(getY() - other.getY()) > 0.000001d) { + return false; + } + if (Math.abs(getZ() - other.getZ()) > 0.000001d) { + return false; + } + return true; + } + @Override public int hashCode() { return (int) getX() ^ (int) getZ() << 12 ^ (int) getY() << 24; 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 22d3f723e..3129e9c66 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 @@ -37,26 +37,26 @@ public class AffineTransform implements Transform, Serializable { /** * coefficients for x coordinate. */ - private final double m00; - private final double m01; - private final double m02; - private final double m03; + private final double m00; // x-only + private final double m01; // x-y + private final double m02; // x-z + private final double m03; // translation /** * coefficients for y coordinate. */ - private final double m10; - private final double m11; - private final double m12; - private final double m13; + private final double m10; // x-y + private final double m11; // y-only + private final double m12; // y-z + private final double m13; // translation /** * coefficients for z coordinate. */ - private final double m20; - private final double m21; - private final double m22; - private final double m23; + private final double m20; // x-z + private final double m21; // y-z + private final double m22; // z-only + private final double m23; // translation // =================================================================== // constructors @@ -295,10 +295,7 @@ public class AffineTransform implements Transform, Serializable { } public boolean isScaled(Vector3 vector) { - boolean flip = false; - if (vector.getX() != 0 && m00 < 0) { - flip = true; - } + boolean flip = vector.getX() != 0 && m00 < 0; if (vector.getY() != 0 && m11 < 0) { flip = !flip; } @@ -308,13 +305,14 @@ public class AffineTransform implements Transform, Serializable { if (flip) { return true; } - if (vector.getX() != 0 && m01 != 0 && m01 == m10) { + // Check for flip-and-rotate + if (vector.getX() != 0 && vector.getY() != 0 && m01 != 0 && m10 != 0) { flip = true; } - if (vector.getY() != 0 && m02 != 0 && m02 == m20) { + if (vector.getX() != 0 && vector.getZ() != 0 && m02 != 0 && m20 != 0) { flip = !flip; } - if (vector.getZ() != 0 && m21 != 0 && m21 == m12) { + if (vector.getY() != 0 && vector.getZ() != 0 && m12 != 0 && m21 != 0) { flip = !flip; } return flip;