Off axis rotation

This commit is contained in:
Jesse Boyd 2017-08-24 14:23:44 +10:00
parent 920095a2de
commit 3c4a709efc
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
4 changed files with 133 additions and 24 deletions

View File

@ -469,12 +469,6 @@ public class ClipboardCommands extends MethodCommands {
)
@CommandPermissions("worldedit.clipboard.rotate")
public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException {
if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) ||
xRotate != null && Math.abs(xRotate % 90) > 0.001 ||
zRotate != null && Math.abs(zRotate % 90) > 0.001) {
player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
}
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
transform = transform.rotateY(-(yRotate != null ? yRotate : 0));

View File

@ -0,0 +1,82 @@
package com.sk89q.worldedit.function.operation;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import java.util.List;
public class BackwardsExtentBlockCopy implements Operation {
private final Region region;
private final Transform transform;
private final Extent destination;
private final Extent source;
private final RegionFunction function;
private final Vector origin;
private Vector mutable = new MutableBlockVector();
public BackwardsExtentBlockCopy(Extent source, Region region, Extent destination, Vector origin, Transform transform, RegionFunction function) {
this.source = source;
this.region = region;
this.destination = destination;
this.transform = transform;
this.function = function;
this.origin = origin;
}
@Override
public Operation resume(RunContext run) throws WorldEditException {
CuboidRegion destRegion = transform(this.transform, this.region);
Transform inverse = this.transform.inverse();
for (Vector pt : destRegion) {
Vector copyFrom = transform(inverse, pt);
if (region.contains(copyFrom)) {
function.apply(pt);
}
}
return null;
}
private CuboidRegion transform(Transform transform, Region region) {
Vector min = new MutableBlockVector(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
Vector max = new MutableBlockVector(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
Vector pos1 = region.getMinimumPoint();
Vector pos2 = region.getMaximumPoint();
for (int x : new int[] { pos1.getBlockX(), pos2.getBlockX() }) {
for (int y : new int[] { pos1.getBlockY(), pos2.getBlockY() }) {
for (int z : new int[] { pos1.getBlockZ(), pos2.getBlockZ() }) {
Vector pt = transform(transform, new Vector(x, y, z)).toBlockVector();
min = Vector.getMinimum(min, pt);
max = Vector.getMaximum(max, pt);
}
}
}
return new CuboidRegion(min, max);
}
private Vector transform(Transform transform, Vector pt) {
mutable.mutX(((pt.getBlockX() - origin.getBlockX())));
mutable.mutY(((pt.getBlockY() - origin.getBlockY())));
mutable.mutZ(((pt.getBlockZ() - origin.getBlockZ())));
Vector tmp = transform.apply(mutable);
tmp.mutX((tmp.getBlockX() + origin.getBlockX()));
tmp.mutY((tmp.getBlockY() + origin.getBlockY()));
tmp.mutZ((tmp.getBlockZ() + origin.getBlockZ()));
return tmp;
}
@Override
public void cancel() {
}
@Override
public void addStatusMessages(List<String> messages) {
}
}

View File

@ -39,6 +39,7 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Identity;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
@ -253,30 +254,50 @@ public class ForwardExtentCopy implements Operation {
if (!translation.equals(Vector.ZERO)) {
finalDest = new BlockTranslateExtent(finalDest, translation.getBlockX(), translation.getBlockY(), translation.getBlockZ());
}
PositionTransformExtent transExt;
Operation blockCopy = null;
PositionTransformExtent transExt = null;
if (!currentTransform.isIdentity()) {
transExt = new PositionTransformExtent(finalDest, currentTransform);
transExt.setOrigin(from);
finalDest = transExt;
} else {
transExt = null;
if (!(currentTransform instanceof AffineTransform) || ((AffineTransform) currentTransform).isOffAxis()) {
transExt = new PositionTransformExtent(source, currentTransform.inverse());
transExt.setOrigin(from);
RegionFunction copy = new SimpleBlockCopy(transExt, finalDest);
if (sourceMask != Masks.alwaysTrue()) {
copy = new RegionMaskingFilter(sourceMask, copy);
}
if (sourceFunction != null) {
copy = new CombinedRegionFunction(copy, sourceFunction);
}
if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) {
copy = new CombinedRegionFunction(copy, new BiomeCopy(source, finalDest));
}
blockCopy = new BackwardsExtentBlockCopy(transExt, region, finalDest, from, transform, copy);
} else {
transExt = new PositionTransformExtent(finalDest, currentTransform);
transExt.setOrigin(from);
finalDest = transExt;
}
}
RegionFunction copy = new SimpleBlockCopy(source, finalDest);
if (sourceMask != Masks.alwaysTrue()) {
copy = new RegionMaskingFilter(sourceMask, copy);
if (blockCopy == null) {
RegionFunction copy = new SimpleBlockCopy(source, finalDest);
if (sourceMask != Masks.alwaysTrue()) {
copy = new RegionMaskingFilter(sourceMask, copy);
}
if (sourceFunction != null) {
copy = new CombinedRegionFunction(copy, sourceFunction);
}
if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) {
copy = new CombinedRegionFunction(copy, new BiomeCopy(source, finalDest));
}
blockCopy = new RegionVisitor(region, copy, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
}
if (sourceFunction != null) {
copy = new CombinedRegionFunction(copy, sourceFunction);
}
if (copyBiomes && (!(source instanceof BlockArrayClipboard) || ((BlockArrayClipboard) source).IMP.hasBiomes())) {
copy = new CombinedRegionFunction(copy, new BiomeCopy(source, finalDest));
}
RegionVisitor blockVisitor = new RegionVisitor(region, copy, queue instanceof MappedFaweQueue ? (MappedFaweQueue) queue : null);
List<? extends Entity> entities = isCopyEntities() ? source.getEntities(region) : new ArrayList<>();
for (int i = 0; i < repetitions; i++) {
Operations.completeBlindly(blockVisitor);
Operations.completeBlindly(blockCopy);
if (!entities.isEmpty()) {
ExtentEntityCopy entityCopy = new ExtentEntityCopy(from, destination, to, currentTransform);
@ -291,7 +312,7 @@ public class ForwardExtentCopy implements Operation {
}
}
affected = blockVisitor.getAffected();
affected = region.getArea();
return null;
}

View File

@ -133,6 +133,18 @@ public class AffineTransform implements Transform, Serializable {
return new double[]{m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23};
}
public boolean isOffAxis() {
double[] c = coefficients();
for (int i = 0; i < c.length; i++) {
if ((i + 1) % 4 != 0) {
if (Math.abs(c[i]) != 1 && c[i] != 0) {
return true;
}
}
}
return false;
}
/**
* Computes the determinant of this transform. Can be zero.
*