Switch to Gradle. Use git log --follow for history.

This converts the project into a multi-module Gradle build.

By default, Git does not show history past a rename, so use git log
--follow to see further history.
This commit is contained in:
sk89q
2014-11-14 11:27:39 -08:00
parent 44559cde68
commit 7192780251
714 changed files with 333 additions and 834 deletions

View File

@@ -0,0 +1,212 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.iterator.RegionIterator;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.util.*;
public abstract class AbstractRegion implements Region {
protected World world;
public AbstractRegion(World world) {
this.world = world;
}
@Override
public Vector getCenter() {
return getMinimumPoint().add(getMaximumPoint()).divide(2);
}
/**
* Get the iterator.
*
* @return iterator of points inside the region
*/
@Override
public Iterator<BlockVector> iterator() {
return new RegionIterator(this);
}
@Override
public World getWorld() {
return world;
}
@Override
public void setWorld(LocalWorld world) {
setWorld((World) world);
}
@Override
public void setWorld(World world) {
this.world = world;
}
@Override
public void shift(Vector change) throws RegionOperationException {
expand(change);
contract(change);
}
@Override
public AbstractRegion clone() {
try {
return (AbstractRegion) super.clone();
} catch (CloneNotSupportedException exc) {
return null;
}
}
@Override
public List<BlockVector2D> polygonize(int maxPoints) {
if (maxPoints >= 0 && maxPoints < 4) {
throw new IllegalArgumentException("Cannot polygonize an AbstractRegion with no overridden polygonize method into less than 4 points.");
}
final BlockVector min = getMinimumPoint().toBlockVector();
final BlockVector max = getMaximumPoint().toBlockVector();
final List<BlockVector2D> points = new ArrayList<BlockVector2D>(4);
points.add(new BlockVector2D(min.getX(), min.getZ()));
points.add(new BlockVector2D(min.getX(), max.getZ()));
points.add(new BlockVector2D(max.getX(), max.getZ()));
points.add(new BlockVector2D(max.getX(), min.getZ()));
return points;
}
/**
* Get the number of blocks in the region.
*
* @return number of blocks
*/
@Override
public int getArea() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return (int)((max.getX() - min.getX() + 1) *
(max.getY() - min.getY() + 1) *
(max.getZ() - min.getZ() + 1));
}
/**
* Get X-size.
*
* @return width
*/
@Override
public int getWidth() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return (int) (max.getX() - min.getX() + 1);
}
/**
* Get Y-size.
*
* @return height
*/
@Override
public int getHeight() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return (int) (max.getY() - min.getY() + 1);
}
/**
* Get Z-size.
*
* @return length
*/
@Override
public int getLength() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return (int) (max.getZ() - min.getZ() + 1);
}
/**
* Get a list of chunks.
*
* @return a set of chunks
*/
@Override
public Set<Vector2D> getChunks() {
final Set<Vector2D> chunks = new HashSet<Vector2D>();
final Vector min = getMinimumPoint();
final Vector max = getMaximumPoint();
final int minY = min.getBlockY();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
if (!contains(new Vector(x, minY, z))) {
continue;
}
chunks.add(new BlockVector2D(
x >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS
));
}
}
return chunks;
}
@Override
public Set<Vector> getChunkCubes() {
final Set<Vector> chunks = new HashSet<Vector>();
final Vector min = getMinimumPoint();
final Vector max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
if (!contains(new Vector(x, y, z))) {
continue;
}
chunks.add(new BlockVector(
x >> ChunkStore.CHUNK_SHIFTS,
y >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS
));
}
}
}
return chunks;
}
}

View File

@@ -0,0 +1,340 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.polyhedron.Edge;
import com.sk89q.worldedit.regions.polyhedron.Triangle;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
public class ConvexPolyhedralRegion extends AbstractRegion {
/**
* Vertices that are contained in the convex hull.
*/
private final Set<Vector> vertices = new LinkedHashSet<Vector>();
/**
* Triangles that form the convex hull.
*/
private final List<Triangle> triangles = new ArrayList<Triangle>();
/**
* Vertices that are coplanar to the first 3 vertices.
*/
private final Set<Vector> vertexBacklog = new LinkedHashSet<Vector>();
/**
* Minimum point of the axis-aligned bounding box.
*/
private Vector minimumPoint;
/**
* Maximum point of the axis-aligned bounding box.
*/
private Vector maximumPoint;
/**
* Accumulator for the barycenter of the polyhedron. Divide by vertices.size() to get the actual center.
*/
private Vector centerAccum = Vector.ZERO;
/**
* The last triangle that caused a {@link #contains(Vector)} to classify a point as "outside". Used for optimization.
*/
private Triangle lastTriangle;
/**
* Constructs an empty mesh, containing no vertices or triangles.
*
* @param world the world
*/
public ConvexPolyhedralRegion(@Nullable World world) {
super(world);
}
/**
* @deprecated cast {@code world} to {@link World}
*/
@Deprecated
public ConvexPolyhedralRegion(LocalWorld world) {
super(world);
}
/**
* Constructs an independent copy of the given region.
*
* @param region the region to copy
*/
public ConvexPolyhedralRegion(ConvexPolyhedralRegion region) {
this(region.world);
vertices.addAll(region.vertices);
triangles.addAll(region.triangles);
vertexBacklog.addAll(region.vertexBacklog);
minimumPoint = region.minimumPoint;
maximumPoint = region.maximumPoint;
centerAccum = region.centerAccum;
lastTriangle = region.lastTriangle;
}
/**
* Clears the region, removing all vertices and triangles.
*/
public void clear() {
vertices.clear();
triangles.clear();
vertexBacklog.clear();
minimumPoint = null;
maximumPoint = null;
centerAccum = Vector.ZERO;
lastTriangle = null;
}
/**
* Add a vertex to the region.
*
* @param vertex the vertex
* @return true, if something changed.
*/
public boolean addVertex(Vector vertex) {
checkNotNull(vertex);
lastTriangle = null; // Probably not necessary
if (vertices.contains(vertex)) {
return false;
}
if (vertices.size() == 3) {
if (vertexBacklog.contains(vertex)) {
return false;
}
if (containsRaw(vertex)) {
return vertexBacklog.add(vertex);
}
}
vertices.add(vertex);
centerAccum = centerAccum.add(vertex);
if (minimumPoint == null) {
minimumPoint = maximumPoint = vertex;
} else {
minimumPoint = Vector.getMinimum(minimumPoint, vertex);
maximumPoint = Vector.getMaximum(maximumPoint, vertex);
}
switch (vertices.size()) {
case 0:
case 1:
case 2:
// Incomplete, can't make a mesh yet
return true;
case 3:
// Generate minimal mesh to start from
final Vector[] v = vertices.toArray(new Vector[vertices.size()]);
triangles.add((new Triangle(v[0], v[1], v[2])));
triangles.add((new Triangle(v[0], v[2], v[1])));
return true;
}
// Look for triangles that face the vertex and remove them
final Set<Edge> borderEdges = new LinkedHashSet<Edge>();
for (Iterator<Triangle> it = triangles.iterator(); it.hasNext(); ) {
final Triangle triangle = it.next();
// If the triangle can't be seen, it's not relevant
if (!triangle.above(vertex)) {
continue;
}
// Remove the triangle from the mesh
it.remove();
// ...and remember its edges
for (int i = 0; i < 3; ++i) {
final Edge edge = triangle.getEdge(i);
if (borderEdges.remove(edge)) {
continue;
}
borderEdges.add(edge);
}
}
// Add triangles between the remembered edges and the new vertex.
for (Edge edge : borderEdges) {
triangles.add(edge.createTriangle(vertex));
}
if (!vertexBacklog.isEmpty()) {
// Remove the new vertex
vertices.remove(vertex);
// Clone, clear and work through the backlog
final List<Vector> vertexBacklog2 = new ArrayList<Vector>(vertexBacklog);
vertexBacklog.clear();
for (Vector vertex2 : vertexBacklog2) {
addVertex(vertex2);
}
// Re-add the new vertex after the backlog.
vertices.add(vertex);
}
return true;
}
public boolean isDefined() {
return !triangles.isEmpty();
}
@Override
public Vector getMinimumPoint() {
return minimumPoint;
}
@Override
public Vector getMaximumPoint() {
return maximumPoint;
}
@Override
public Vector getCenter() {
return centerAccum.divide(vertices.size());
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
}
@Override
public void shift(Vector change) throws RegionOperationException {
shiftCollection(vertices, change);
shiftCollection(vertexBacklog, change);
for (int i = 0; i < triangles.size(); ++i) {
final Triangle triangle = triangles.get(i);
final Vector v0 = change.add(triangle.getVertex(0));
final Vector v1 = change.add(triangle.getVertex(1));
final Vector v2 = change.add(triangle.getVertex(2));
triangles.set(i, new Triangle(v0, v1, v2));
}
minimumPoint = change.add(minimumPoint);
maximumPoint = change.add(maximumPoint);
centerAccum = change.multiply(vertices.size()).add(centerAccum);
lastTriangle = null;
}
private static void shiftCollection(Collection<Vector> collection, Vector change) {
final List<Vector> tmp = new ArrayList<Vector>(collection);
collection.clear();
for (Vector vertex : tmp) {
collection.add(change.add(vertex));
}
}
@Override
public boolean contains(Vector position) {
if (!isDefined()) {
return false;
}
final int x = position.getBlockX();
final int y = position.getBlockY();
final int z = position.getBlockZ();
final Vector min = getMinimumPoint();
final Vector max = getMaximumPoint();
if (x < min.getBlockX()) return false;
if (x > max.getBlockX()) return false;
if (y < min.getBlockY()) return false;
if (y > max.getBlockY()) return false;
if (z < min.getBlockZ()) return false;
if (z > max.getBlockZ()) return false;
return containsRaw(position);
}
private boolean containsRaw(Vector pt) {
if (lastTriangle != null && lastTriangle.above(pt)) {
return false;
}
for (Triangle triangle : triangles) {
if (lastTriangle == triangle) {
continue;
}
if (triangle.above(pt)) {
lastTriangle = triangle;
return false;
}
}
return true;
}
public Collection<Vector> getVertices() {
if (vertexBacklog.isEmpty()) {
return vertices;
}
final List<Vector> ret = new ArrayList<Vector>(vertices);
ret.addAll(vertexBacklog);
return ret;
}
public Collection<Triangle> getTriangles() {
return triangles;
}
@Override
public AbstractRegion clone() {
return new ConvexPolyhedralRegion(this);
}
}

View File

@@ -0,0 +1,456 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An axis-aligned cuboid. It can be defined using two corners of the cuboid.
*/
public class CuboidRegion extends AbstractRegion implements FlatRegion {
private Vector pos1;
private Vector pos2;
/**
* Construct a new instance of this cuboid using two corners of the cuboid.
*
* @param pos1 the first position
* @param pos2 the second position
*/
public CuboidRegion(Vector pos1, Vector pos2) {
this(null, pos1, pos2);
}
/**
* @deprecated cast {@code world} to {@link World}
*/
@Deprecated
public CuboidRegion(LocalWorld world, Vector pos1, Vector pos2) {
this((World) world, pos1, pos2);
}
/**
* Construct a new instance of this cuboid using two corners of the cuboid.
*
* @param world the world
* @param pos1 the first position
* @param pos2 the second position
*/
public CuboidRegion(World world, Vector pos1, Vector pos2) {
super(world);
checkNotNull(pos1);
checkNotNull(pos2);
this.pos1 = pos1;
this.pos2 = pos2;
recalculate();
}
/**
* Get the first cuboid-defining corner.
*
* @return a position
*/
public Vector getPos1() {
return pos1;
}
/**
* Set the first cuboid-defining corner.
*
* @param pos1 a position
*/
public void setPos1(Vector pos1) {
this.pos1 = pos1;
}
/**
* Get the second cuboid-defining corner.
*
* @return a position
*/
public Vector getPos2() {
return pos2;
}
/**
* Set the second cuboid-defining corner.
*
* @param pos2 a position
*/
public void setPos2(Vector pos2) {
this.pos2 = pos2;
}
/**
* Clamps the cuboid according to boundaries of the world.
*/
private void recalculate() {
pos1 = pos1.clampY(0, world == null ? 255 : world.getMaxY());
pos2 = pos2.clampY(0, world == null ? 255 : world.getMaxY());
}
/**
* Get a region that contains the faces of this cuboid.
*
* @return a new complex region
*/
public Region getFaces() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return new RegionIntersection(
// Project to Z-Y plane
new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())),
new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())),
// Project to X-Y plane
new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())),
new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ())),
// Project to the X-Z plane
new CuboidRegion(pos1.setY(min.getY()), pos2.setY(min.getY())),
new CuboidRegion(pos1.setY(max.getY()), pos2.setY(max.getY())));
}
/**
* Get a region that contains the walls (all faces but the ones parallel to
* the X-Z plane) of this cuboid.
*
* @return a new complex region
*/
public Region getWalls() {
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return new RegionIntersection(
// Project to Z-Y plane
new CuboidRegion(pos1.setX(min.getX()), pos2.setX(min.getX())),
new CuboidRegion(pos1.setX(max.getX()), pos2.setX(max.getX())),
// Project to X-Y plane
new CuboidRegion(pos1.setZ(min.getZ()), pos2.setZ(min.getZ())),
new CuboidRegion(pos1.setZ(max.getZ()), pos2.setZ(max.getZ())));
}
@Override
public Vector getMinimumPoint() {
return new Vector(Math.min(pos1.getX(), pos2.getX()),
Math.min(pos1.getY(), pos2.getY()),
Math.min(pos1.getZ(), pos2.getZ()));
}
@Override
public Vector getMaximumPoint() {
return new Vector(Math.max(pos1.getX(), pos2.getX()),
Math.max(pos1.getY(), pos2.getY()),
Math.max(pos1.getZ(), pos2.getZ()));
}
@Override
public int getMinimumY() {
return Math.min(pos1.getBlockY(), pos2.getBlockY());
}
@Override
public int getMaximumY() {
return Math.max(pos1.getBlockY(), pos2.getBlockY());
}
@Override
public void expand(Vector... changes) {
checkNotNull(changes);
for (Vector change : changes) {
if (change.getX() > 0) {
if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) {
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
} else {
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
}
} else {
if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) {
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
} else {
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
}
}
if (change.getY() > 0) {
if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) {
pos1 = pos1.add(new Vector(0, change.getY(), 0));
} else {
pos2 = pos2.add(new Vector(0, change.getY(), 0));
}
} else {
if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) {
pos1 = pos1.add(new Vector(0, change.getY(), 0));
} else {
pos2 = pos2.add(new Vector(0, change.getY(), 0));
}
}
if (change.getZ() > 0) {
if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
} else {
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
}
} else {
if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
} else {
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
}
}
}
recalculate();
}
@Override
public void contract(Vector... changes) {
checkNotNull(changes);
for (Vector change : changes) {
if (change.getX() < 0) {
if (Math.max(pos1.getX(), pos2.getX()) == pos1.getX()) {
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
} else {
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
}
} else {
if (Math.min(pos1.getX(), pos2.getX()) == pos1.getX()) {
pos1 = pos1.add(new Vector(change.getX(), 0, 0));
} else {
pos2 = pos2.add(new Vector(change.getX(), 0, 0));
}
}
if (change.getY() < 0) {
if (Math.max(pos1.getY(), pos2.getY()) == pos1.getY()) {
pos1 = pos1.add(new Vector(0, change.getY(), 0));
} else {
pos2 = pos2.add(new Vector(0, change.getY(), 0));
}
} else {
if (Math.min(pos1.getY(), pos2.getY()) == pos1.getY()) {
pos1 = pos1.add(new Vector(0, change.getY(), 0));
} else {
pos2 = pos2.add(new Vector(0, change.getY(), 0));
}
}
if (change.getZ() < 0) {
if (Math.max(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
} else {
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
}
} else {
if (Math.min(pos1.getZ(), pos2.getZ()) == pos1.getZ()) {
pos1 = pos1.add(new Vector(0, 0, change.getZ()));
} else {
pos2 = pos2.add(new Vector(0, 0, change.getZ()));
}
}
}
recalculate();
}
@Override
public void shift(Vector change) throws RegionOperationException {
pos1 = pos1.add(change);
pos2 = pos2.add(change);
recalculate();
}
@Override
public Set<Vector2D> getChunks() {
Set<Vector2D> chunks = new HashSet<Vector2D>();
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
chunks.add(new BlockVector2D(x >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS));
}
}
return chunks;
}
@Override
public Set<Vector> getChunkCubes() {
Set<Vector> chunks = new HashSet<Vector>();
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int y = min.getBlockY(); y <= max.getBlockY(); ++y) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
chunks.add(new BlockVector(x >> ChunkStore.CHUNK_SHIFTS,
y >> ChunkStore.CHUNK_SHIFTS, z >> ChunkStore.CHUNK_SHIFTS));
}
}
}
return chunks;
}
@Override
public boolean contains(Vector position) {
double x = position.getX();
double y = position.getY();
double z = position.getZ();
Vector min = getMinimumPoint();
Vector max = getMaximumPoint();
return x >= min.getBlockX() && x <= max.getBlockX()
&& y >= min.getBlockY() && y <= max.getBlockY()
&& z >= min.getBlockZ() && z <= max.getBlockZ();
}
@Override
public Iterator<BlockVector> iterator() {
return new Iterator<BlockVector>() {
private Vector min = getMinimumPoint();
private Vector max = getMaximumPoint();
private int nextX = min.getBlockX();
private int nextY = min.getBlockY();
private int nextZ = min.getBlockZ();
@Override
public boolean hasNext() {
return (nextX != Integer.MIN_VALUE);
}
@Override
public BlockVector next() {
if (!hasNext()) throw new java.util.NoSuchElementException();
BlockVector answer = new BlockVector(nextX, nextY, nextZ);
if (++nextX > max.getBlockX()) {
nextX = min.getBlockX();
if (++nextY > max.getBlockY()) {
nextY = min.getBlockY();
if (++nextZ > max.getBlockZ()) {
nextX = Integer.MIN_VALUE;
}
}
}
return answer;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public Iterable<Vector2D> asFlatRegion() {
return new Iterable<Vector2D>() {
@Override
public Iterator<Vector2D> iterator() {
return new Iterator<Vector2D>() {
private Vector min = getMinimumPoint();
private Vector max = getMaximumPoint();
private int nextX = min.getBlockX();
private int nextZ = min.getBlockZ();
@Override
public boolean hasNext() {
return (nextX != Integer.MIN_VALUE);
}
@Override
public Vector2D next() {
if (!hasNext()) throw new java.util.NoSuchElementException();
Vector2D answer = new Vector2D(nextX, nextZ);
if (++nextX > max.getBlockX()) {
nextX = min.getBlockX();
if (++nextZ > max.getBlockZ()) {
nextX = Integer.MIN_VALUE;
}
}
return answer;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
@Override
public String toString() {
return getMinimumPoint() + " - " + getMaximumPoint();
}
@Override
public CuboidRegion clone() {
return (CuboidRegion) super.clone();
}
/**
* Make a cuboid region out of the given region using the minimum and maximum
* bounds of the provided region.
*
* @param region the region
* @return a new cuboid region
*/
public static CuboidRegion makeCuboid(Region region) {
checkNotNull(region);
return new CuboidRegion(region.getMinimumPoint(), region.getMaximumPoint());
}
/**
* Make a cuboid from the center.
*
* @param origin the origin
* @param apothem the apothem, where 0 is the minimum value to make a 1x1 cuboid
* @return a cuboid region
*/
public static CuboidRegion fromCenter(Vector origin, int apothem) {
checkNotNull(origin);
checkArgument(apothem >= 0, "apothem => 0 required");
Vector size = new Vector(1, 1, 1).multiply(apothem);
return new CuboidRegion(origin.subtract(size), origin.add(size));
}
}

View File

@@ -0,0 +1,395 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.geom.Polygons;
import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator;
import com.sk89q.worldedit.regions.iterator.FlatRegionIterator;
import com.sk89q.worldedit.world.World;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents a cylindrical region.
*/
public class CylinderRegion extends AbstractRegion implements FlatRegion {
private Vector2D center;
private Vector2D radius;
private int minY;
private int maxY;
private boolean hasY = false;
/**
* Construct the region
*/
public CylinderRegion() {
this((World) null);
}
/**
* @deprecated cast {@code world} to {@link World}
*/
@Deprecated
public CylinderRegion(LocalWorld world) {
this((World) world);
}
/**
* Construct the region.
*
* @param world the world
*/
public CylinderRegion(World world) {
this(world, new Vector(), new Vector2D(), 0, 0);
hasY = false;
}
@Deprecated
public CylinderRegion(LocalWorld world, Vector center, Vector2D radius, int minY, int maxY) {
this((World) world, center, radius, minY, maxY);
}
/**
* Construct the region.
*
* @param world the world
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(World world, Vector center, Vector2D radius, int minY, int maxY) {
super(world);
setCenter(center.toVector2D());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
/**
* Construct the region.
*
* @param center the center position
* @param radius the radius along the X and Z axes
* @param minY the minimum Y, inclusive
* @param maxY the maximum Y, inclusive
*/
public CylinderRegion(Vector center, Vector2D radius, int minY, int maxY) {
super(null);
setCenter(center.toVector2D());
setRadius(radius);
this.minY = minY;
this.maxY = maxY;
hasY = true;
}
public CylinderRegion(CylinderRegion region) {
this(region.world, region.getCenter(), region.getRadius(), region.minY, region.maxY);
hasY = region.hasY;
}
@Override
public Vector getCenter() {
return center.toVector((maxY + minY) / 2);
}
/**
* Sets the main center point of the region
*
* @deprecated replaced by {@link #setCenter(Vector2D)}
*/
@Deprecated
public void setCenter(Vector center) {
setCenter(center.toVector2D());
}
/**
* Sets the main center point of the region
*
* @param center the center point
*/
public void setCenter(Vector2D center) {
this.center = center;
}
/**
* Returns the radius of the cylinder
*
* @return the radius along the X and Z axes
*/
public Vector2D getRadius() {
return radius.subtract(0.5, 0.5);
}
/**
* Sets the radius of the cylinder
*
* @param radius the radius along the X and Z axes
*/
public void setRadius(Vector2D radius) {
this.radius = radius.add(0.5, 0.5);
}
/**
* Extends the radius to be at least the given radius
*
* @param minRadius the minimum radius
*/
public void extendRadius(Vector2D minRadius) {
setRadius(Vector2D.getMaximum(minRadius, getRadius()));
}
/**
* Set the minimum Y.
*
* @param y the y
*/
public void setMinimumY(int y) {
hasY = true;
minY = y;
}
/**
* Se the maximum Y.
*
* @param y the y
*/
public void setMaximumY(int y) {
hasY = true;
maxY = y;
}
@Override
public Vector getMinimumPoint() {
return center.subtract(getRadius()).toVector(minY);
}
@Override
public Vector getMaximumPoint() {
return center.add(getRadius()).toVector(maxY);
}
@Override
public int getMaximumY() {
return maxY;
}
@Override
public int getMinimumY() {
return minY;
}
@Override
public int getArea() {
return (int) Math.floor(radius.getX() * radius.getZ() * Math.PI * getHeight());
}
@Override
public int getWidth() {
return (int) (2 * radius.getX());
}
@Override
public int getHeight() {
return maxY - minY + 1;
}
@Override
public int getLength() {
return (int) (2 * radius.getZ());
}
private Vector2D calculateDiff2D(Vector... changes) throws RegionOperationException {
Vector2D diff = new Vector2D();
for (Vector change : changes) {
diff = diff.add(change.toVector2D());
}
if ((diff.getBlockX() & 1) + (diff.getBlockZ() & 1) != 0) {
throw new RegionOperationException("Cylinders changes must be even for each horizontal dimensions.");
}
return diff.divide(2).floor();
}
private Vector2D calculateChanges2D(Vector... changes) {
Vector2D total = new Vector2D();
for (Vector change : changes) {
total = total.add(change.toVector2D().positive());
}
return total.divide(2).floor();
}
/**
* Expand the region.
* Expand the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
@Override
public void expand(Vector... changes) throws RegionOperationException {
center = center.add(calculateDiff2D(changes));
radius = radius.add(calculateChanges2D(changes));
for (Vector change : changes) {
int changeY = change.getBlockY();
if (changeY > 0) {
maxY += changeY;
} else {
minY += changeY;
}
}
}
/**
* Contract the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
@Override
public void contract(Vector... changes) throws RegionOperationException {
center = center.subtract(calculateDiff2D(changes));
Vector2D newRadius = radius.subtract(calculateChanges2D(changes));
radius = Vector2D.getMaximum(new Vector2D(1.5, 1.5), newRadius);
for (Vector change : changes) {
int height = maxY - minY;
int changeY = change.getBlockY();
if (changeY > 0) {
minY += Math.min(height, changeY);
} else {
maxY += Math.max(-height, changeY);
}
}
}
@Override
public void shift(Vector change) throws RegionOperationException {
center = center.add(change.toVector2D());
int changeY = change.getBlockY();
maxY += changeY;
minY += changeY;
}
/**
* Checks to see if a point is inside this region.
*/
@Override
public boolean contains(Vector position) {
final int blockY = position.getBlockY();
if (blockY < minY || blockY > maxY) {
return false;
}
return position.toVector2D().subtract(center).divide(radius).lengthSq() <= 1;
}
/**
* Sets the height of the cylinder to fit the specified Y.
*
* @param y the y value
* @return true if the area was expanded
*/
public boolean setY(int y) {
if (!hasY) {
minY = y;
maxY = y;
hasY = true;
return true;
} else if (y < minY) {
minY = y;
return true;
} else if (y > maxY) {
maxY = y;
return true;
}
return false;
}
@Override
public Iterator<BlockVector> iterator() {
return new FlatRegion3DIterator(this);
}
@Override
public Iterable<Vector2D> asFlatRegion() {
return new Iterable<Vector2D>() {
@Override
public Iterator<Vector2D> iterator() {
return new FlatRegionIterator(CylinderRegion.this);
}
};
}
/**
* Returns string representation in the format
* "(centerX, centerZ) - (radiusX, radiusZ) - (minY, maxY)"
*
* @return string
*/
@Override
public String toString() {
return center + " - " + radius + "(" + minY + ", " + maxY + ")";
}
@Override
public CylinderRegion clone() {
return (CylinderRegion) super.clone();
}
@Override
public List<BlockVector2D> polygonize(int maxPoints) {
return Polygons.polygonizeCylinder(center, radius, maxPoints);
}
/**
* Return a new instance with the given center and radius in the X and Z
* axes with a Y that extends from the bottom of the extent to the top
* of the extent.
*
* @param extent the extent
* @param center the center position
* @param radius the radius in the X and Z axes
* @return a region
*/
public static CylinderRegion createRadius(Extent extent, Vector center, double radius) {
checkNotNull(extent);
checkNotNull(center);
Vector2D radiusVec = new Vector2D(radius, radius);
int minY = extent.getMinimumPoint().getBlockY();
int maxY = extent.getMaximumPoint().getBlockY();
return new CylinderRegion(center, radiusVec, minY, maxY);
}
}

View File

@@ -0,0 +1,233 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.util.Set;
import java.util.HashSet;
/**
* Represents an ellipsoid region.
*/
public class EllipsoidRegion extends AbstractRegion {
/**
* Stores the center.
*/
private Vector center;
/**
* Stores the radii plus 0.5 on each axis.
*/
private Vector radius;
/**
* Construct a new instance of this ellipsoid region.
*
* @param pos1 the first position
* @param pos2 the second position
*/
public EllipsoidRegion(Vector pos1, Vector pos2) {
this(null, pos1, pos2);
}
@Deprecated
public EllipsoidRegion(LocalWorld world, Vector center, Vector radius) {
this((World) world, center, radius);
}
/**
* Construct a new instance of this ellipsoid region.
*
* @param world the world
* @param center the center
* @param radius the radius
*/
public EllipsoidRegion(World world, Vector center, Vector radius) {
super(world);
this.center = center;
setRadius(radius);
}
public EllipsoidRegion(EllipsoidRegion ellipsoidRegion) {
this(ellipsoidRegion.world, ellipsoidRegion.center, ellipsoidRegion.getRadius());
}
@Override
public Vector getMinimumPoint() {
return center.subtract(getRadius());
}
@Override
public Vector getMaximumPoint() {
return center.add(getRadius());
}
@Override
public int getArea() {
return (int) Math.floor((4.0 / 3.0) * Math.PI * radius.getX() * radius.getY() * radius.getZ());
}
@Override
public int getWidth() {
return (int) (2 * radius.getX());
}
@Override
public int getHeight() {
return (int) (2 * radius.getY());
}
@Override
public int getLength() {
return (int) (2 * radius.getZ());
}
private Vector calculateDiff(Vector... changes) throws RegionOperationException {
Vector diff = new Vector().add(changes);
if ((diff.getBlockX() & 1) + (diff.getBlockY() & 1) + (diff.getBlockZ() & 1) != 0) {
throw new RegionOperationException(
"Ellipsoid changes must be even for each dimensions.");
}
return diff.divide(2).floor();
}
private Vector calculateChanges(Vector... changes) {
Vector total = new Vector();
for (Vector change : changes) {
total = total.add(change.positive());
}
return total.divide(2).floor();
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
center = center.add(calculateDiff(changes));
radius = radius.add(calculateChanges(changes));
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
center = center.subtract(calculateDiff(changes));
Vector newRadius = radius.subtract(calculateChanges(changes));
radius = Vector.getMaximum(new Vector(1.5, 1.5, 1.5), newRadius);
}
@Override
public void shift(Vector change) throws RegionOperationException {
center = center.add(change);
}
/**
* Get the center.
*
* @return center
*/
@Override
public Vector getCenter() {
return center;
}
/**
* Set the center.
*
* @param center the center
*/
public void setCenter(Vector center) {
this.center = center;
}
/**
* Get the radii.
*
* @return radii
*/
public Vector getRadius() {
return radius.subtract(0.5, 0.5, 0.5);
}
/**
* Set the radii.
*
* @param radius the radius
*/
public void setRadius(Vector radius) {
this.radius = radius.add(0.5, 0.5, 0.5);
}
@Override
public Set<Vector2D> getChunks() {
final Set<Vector2D> chunks = new HashSet<Vector2D>();
final Vector min = getMinimumPoint();
final Vector max = getMaximumPoint();
final int centerY = getCenter().getBlockY();
for (int x = min.getBlockX(); x <= max.getBlockX(); ++x) {
for (int z = min.getBlockZ(); z <= max.getBlockZ(); ++z) {
if (!contains(new BlockVector(x, centerY, z))) {
continue;
}
chunks.add(new BlockVector2D(
x >> ChunkStore.CHUNK_SHIFTS,
z >> ChunkStore.CHUNK_SHIFTS
));
}
}
return chunks;
}
@Override
public boolean contains(Vector position) {
return position.subtract(center).divide(radius).lengthSq() <= 1;
}
/**
* Returns string representation in the format
* "(centerX, centerY, centerZ) - (radiusX, radiusY, radiusZ)".
*
* @return string
*/
@Override
public String toString() {
return center + " - " + getRadius();
}
public void extendRadius(Vector minRadius) {
setRadius(Vector.getMaximum(minRadius, getRadius()));
}
@Override
public EllipsoidRegion clone() {
return (EllipsoidRegion) super.clone();
}
}

View File

@@ -0,0 +1,46 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.Vector2D;
public interface FlatRegion extends Region {
/**
* Gets the minimum Y value
*
* @return the Y value
*/
public int getMinimumY();
/**
* Gets the maximum Y value
*
* @return the Y value
*/
public int getMaximumY();
/**
* Get this region as an iterable flat region.
*
* @return a flat region iterable
*/
public Iterable<Vector2D> asFlatRegion();
}

View File

@@ -0,0 +1,145 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.world.World;
import java.util.*;
/**
* A region that contains no points.
*/
public class NullRegion implements Region {
private World world;
@Override
public Vector getMinimumPoint() {
return new Vector(0, 0, 0);
}
@Override
public Vector getMaximumPoint() {
return new Vector(0, 0, 0);
}
@Override
public Vector getCenter() {
return new Vector(0, 0, 0);
}
@Override
public int getArea() {
return 0;
}
@Override
public int getWidth() {
return 0;
}
@Override
public int getHeight() {
return 0;
}
@Override
public int getLength() {
return 0;
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
throw new RegionOperationException("Cannot change NullRegion");
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
throw new RegionOperationException("Cannot change NullRegion");
}
@Override
public void shift(Vector change) throws RegionOperationException {
throw new RegionOperationException("Cannot change NullRegion");
}
@Override
public boolean contains(Vector position) {
return false;
}
@Override
public Set<Vector2D> getChunks() {
return Collections.emptySet();
}
@Override
public Set<Vector> getChunkCubes() {
return Collections.emptySet();
}
@Override
public World getWorld() {
return world;
}
@Override
public void setWorld(World world) {
this.world = world;
}
@Override
public void setWorld(LocalWorld world) {
setWorld((World) world);
}
@Override
public NullRegion clone() {
return new NullRegion();
}
@Override
public List<BlockVector2D> polygonize(int maxPoints) {
return Collections.emptyList();
}
@Override
public Iterator<BlockVector> iterator() {
return new Iterator<BlockVector>() {
@Override
public boolean hasNext() {
return false;
}
@Override
public BlockVector next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove");
}
};
}
}

View File

@@ -0,0 +1,467 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.regions.iterator.FlatRegion3DIterator;
import com.sk89q.worldedit.regions.iterator.FlatRegionIterator;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Represents a 2D polygonal region.
*/
public class Polygonal2DRegion extends AbstractRegion implements FlatRegion {
private List<BlockVector2D> points;
private Vector2D min;
private Vector2D max;
private int minY;
private int maxY;
private boolean hasY = false;
/**
* Construct the region
*/
public Polygonal2DRegion() {
this((World) null);
}
@Deprecated
public Polygonal2DRegion(LocalWorld world) {
this((World) world);
}
/**
* Construct the region.
*
* @param world the world
*/
public Polygonal2DRegion(World world) {
this(world, Collections.<BlockVector2D>emptyList(), 0, 0);
hasY = false;
}
@Deprecated
public Polygonal2DRegion(LocalWorld world, List<BlockVector2D> points, int minY, int maxY) {
this((World) world, points, minY, maxY);
}
/**
* Construct the region.
*
* @param world the world
* @param points list of points
* @param minY minimum Y
* @param maxY maximum Y
*/
public Polygonal2DRegion(World world, List<BlockVector2D> points, int minY, int maxY) {
super(world);
this.points = new ArrayList<BlockVector2D>(points);
this.minY = minY;
this.maxY = maxY;
hasY = true;
recalculate();
}
/**
* Make a copy of another region.
*
* @param region the other region
*/
public Polygonal2DRegion(Polygonal2DRegion region) {
this(region.world, region.points, region.minY, region.maxY);
hasY = region.hasY;
}
/**
* Get the list of points.
*
* @return a list of points
*/
public List<BlockVector2D> getPoints() {
return Collections.unmodifiableList(points);
}
/**
* Recalculate the bounding box of this polygonal region. This should be
* called after points have been changed.
*/
protected void recalculate() {
if (points.isEmpty()) {
min = new Vector2D(0, 0);
minY = 0;
max = new Vector2D(0, 0);
maxY = 0;
return;
}
int minX = points.get(0).getBlockX();
int minZ = points.get(0).getBlockZ();
int maxX = points.get(0).getBlockX();
int maxZ = points.get(0).getBlockZ();
for (BlockVector2D v : points) {
int x = v.getBlockX();
int z = v.getBlockZ();
if (x < minX) minX = x;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (z > maxZ) maxZ = z;
}
int oldMinY = minY;
int oldMaxY = maxY;
minY = Math.min(oldMinY, oldMaxY);
maxY = Math.max(oldMinY, oldMaxY);
minY = Math.min(Math.max(0, minY), world == null ? 255 : world.getMaxY());
maxY = Math.min(Math.max(0, maxY), world == null ? 255 : world.getMaxY());
min = new Vector2D(minX, minZ);
max = new Vector2D(maxX, maxZ);
}
/**
* Add a point to the list.
*
* @param position the position
*/
public void addPoint(Vector2D position) {
points.add(position.toBlockVector2D());
recalculate();
}
/**
* Add a point to the list.
*
* @param position the position
*/
public void addPoint(BlockVector2D position) {
points.add(position);
recalculate();
}
/**
* Add a point to the list.
*
* @param position the position
*/
public void addPoint(Vector position) {
points.add(new BlockVector2D(position.getBlockX(), position.getBlockZ()));
recalculate();
}
@Override
public int getMinimumY() {
return minY;
}
@Deprecated
public int getMininumY() {
return minY;
}
/**
* Set the minimum Y.
*
* @param y the Y
*/
public void setMinimumY(int y) {
hasY = true;
minY = y;
recalculate();
}
@Override
public int getMaximumY() {
return maxY;
}
/**
* Set the maximum Y.
*
* @param y the Y
*/
public void setMaximumY(int y) {
hasY = true;
maxY = y;
recalculate();
}
@Override
public Vector getMinimumPoint() {
return min.toVector(minY);
}
@Override
public Vector getMaximumPoint() {
return max.toVector(maxY);
}
@Override
public int getArea() {
double area = 0;
int i, j = points.size() - 1;
for (i = 0; i < points.size(); ++i) {
area += (points.get(j).getBlockX() + points.get(i).getBlockX())
* (points.get(j).getBlockZ() - points.get(i).getBlockZ());
j = i;
}
return (int) Math.floor(Math.abs(area * 0.5)
* (maxY - minY + 1));
}
@Override
public int getWidth() {
return max.getBlockX() - min.getBlockX() + 1;
}
@Override
public int getHeight() {
return maxY - minY + 1;
}
@Override
public int getLength() {
return max.getBlockZ() - min.getBlockZ() + 1;
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
for (Vector change : changes) {
if (change.getBlockX() != 0 || change.getBlockZ() != 0) {
throw new RegionOperationException("Polygons can only be expanded vertically.");
}
}
for (Vector change : changes) {
int changeY = change.getBlockY();
if (changeY > 0) {
maxY += changeY;
} else {
minY += changeY;
}
}
recalculate();
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
for (Vector change : changes) {
if (change.getBlockX() != 0 || change.getBlockZ() != 0) {
throw new RegionOperationException("Polygons can only be contracted vertically.");
}
}
for (Vector change : changes) {
int changeY = change.getBlockY();
if (changeY > 0) {
minY += changeY;
} else {
maxY += changeY;
}
}
recalculate();
}
@Override
public void shift(Vector change) throws RegionOperationException {
final double changeX = change.getX();
final double changeY = change.getY();
final double changeZ = change.getZ();
for (int i = 0; i < points.size(); ++i) {
BlockVector2D point = points.get(i);
points.set(i, new BlockVector2D(point.getX() + changeX, point.getZ() + changeZ));
}
minY += changeY;
maxY += changeY;
recalculate();
}
@Override
public boolean contains(Vector position) {
return contains(points, minY, maxY, position);
}
/**
* Checks to see if a point is inside a region.
*
* @param points a list of points
* @param minY the min Y
* @param maxY the max Y
* @param pt the position to check
* @return true if the given polygon contains the given point
*/
public static boolean contains(List<BlockVector2D> points, int minY, int maxY, Vector pt) {
if (points.size() < 3) {
return false;
}
int targetX = pt.getBlockX(); //wide
int targetY = pt.getBlockY(); //height
int targetZ = pt.getBlockZ(); //depth
if (targetY < minY || targetY > maxY) {
return false;
}
boolean inside = false;
int npoints = points.size();
int xNew, zNew;
int xOld, zOld;
int x1, z1;
int x2, z2;
long crossproduct;
int i;
xOld = points.get(npoints - 1).getBlockX();
zOld = points.get(npoints - 1).getBlockZ();
for (i = 0; i < npoints; ++i) {
xNew = points.get(i).getBlockX();
zNew = points.get(i).getBlockZ();
//Check for corner
if (xNew == targetX && zNew == targetZ) {
return true;
}
if (xNew > xOld) {
x1 = xOld;
x2 = xNew;
z1 = zOld;
z2 = zNew;
} else {
x1 = xNew;
x2 = xOld;
z1 = zNew;
z2 = zOld;
}
if (x1 <= targetX && targetX <= x2) {
crossproduct = ((long) targetZ - (long) z1) * (long) (x2 - x1)
- ((long) z2 - (long) z1) * (long) (targetX - x1);
if (crossproduct == 0) {
if ((z1 <= targetZ) == (targetZ <= z2)) return true; //on edge
} else if (crossproduct < 0 && (x1 != targetX)) {
inside = !inside;
}
}
xOld = xNew;
zOld = zNew;
}
return inside;
}
/**
* Return the number of points.
*
* @return the number of points
*/
public int size() {
return points.size();
}
/**
* Expand the height of the polygon to fit the specified Y.
*
* @param y the amount to expand
* @return true if the area was expanded
*/
public boolean expandY(int y) {
if (!hasY) {
minY = y;
maxY = y;
hasY = true;
return true;
} else if (y < minY) {
minY = y;
return true;
} else if (y > maxY) {
maxY = y;
return true;
}
return false;
}
@Override
public Iterator<BlockVector> iterator() {
return new FlatRegion3DIterator(this);
}
@Override
public Iterable<Vector2D> asFlatRegion() {
return new Iterable<Vector2D>() {
@Override
public Iterator<Vector2D> iterator() {
return new FlatRegionIterator(Polygonal2DRegion.this);
}
};
}
/**
* Returns string representation in the format
* "(x1, z1) - ... - (xN, zN) * (minY - maxY)"
*
* @return string
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
List<BlockVector2D> pts = getPoints();
Iterator<BlockVector2D> it = pts.iterator();
while (it.hasNext()) {
BlockVector2D current = it.next();
sb.append("(").append(current.getBlockX()).append(", ").append(current.getBlockZ()).append(")");
if (it.hasNext()) sb.append(" - ");
}
sb.append(" * (").append(minY).append(" - ").append(maxY).append(")");
return sb.toString();
}
@Override
public Polygonal2DRegion clone() {
Polygonal2DRegion clone = (Polygonal2DRegion) super.clone();
clone.points = new ArrayList<BlockVector2D>(points);
return clone;
}
@Override
public List<BlockVector2D> polygonize(int maxPoints) {
if (maxPoints >= 0 && maxPoints < points.size()) {
throw new IllegalArgumentException("Cannot polygonize a this Polygonal2DRegion into the amount of points given.");
}
return points;
}
}

View File

@@ -0,0 +1,172 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
/**
* Represents a physical shape.
*/
public interface Region extends Iterable<BlockVector>, Cloneable {
/**
* Get the lower point of a region.
*
* @return min. point
*/
public Vector getMinimumPoint();
/**
* Get the upper point of a region.
*
* @return max. point
*/
public Vector getMaximumPoint();
/**
* Get the center point of a region.
* Note: Coordinates will not be integers
* if the corresponding lengths are even.
*
* @return center point
*/
public Vector getCenter();
/**
* Get the number of blocks in the region.
*
* @return number of blocks
*/
public int getArea();
/**
* Get X-size.
*
* @return width
*/
public int getWidth();
/**
* Get Y-size.
*
* @return height
*/
public int getHeight();
/**
* Get Z-size.
*
* @return length
*/
public int getLength();
/**
* Expand the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
public void expand(Vector... changes) throws RegionOperationException;
/**
* Contract the region.
*
* @param changes array/arguments with multiple related changes
* @throws RegionOperationException
*/
public void contract(Vector... changes) throws RegionOperationException;
/**
* Shift the region.
*
* @param change the change
* @throws RegionOperationException
*/
public void shift(Vector change) throws RegionOperationException;
/**
* Returns true based on whether the region contains the point.
*
* @param position the position
* @return true if contained
*/
public boolean contains(Vector position);
/**
* Get a list of chunks.
*
* @return a list of chunk coordinates
*/
public Set<Vector2D> getChunks();
/**
* Return a list of 16*16*16 chunks in a region
*
* @return the chunk cubes this region overlaps with
*/
public Set<Vector> getChunkCubes();
/**
* Sets the world that the selection is in.
*
* @return the world, or null
*/
@Nullable
public World getWorld();
/**
* Sets the world that the selection is in.
*
* @param world the world, which may be null
*/
public void setWorld(@Nullable World world);
/**
* Sets the world that the selection is in.
*
* @param world the world, which may be null
*/
@Deprecated
public void setWorld(@Nullable LocalWorld world);
/**
* Make a clone of the region.
*
* @return a cloned version
*/
public Region clone();
/**
* Polygonizes a cross-section or a 2D projection of the region orthogonal to the Y axis.
*
* @param maxPoints maximum number of points to generate. -1 for no limit.
* @return the points.
*/
public List<BlockVector2D> polygonize(int maxPoints);
}

View File

@@ -0,0 +1,147 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.google.common.collect.Iterators;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* An intersection of several other regions. Any location that is contained in one
* of the child regions is considered as contained by this region.
*
* <p>{@link #iterator()} returns a special iterator that will iterate through
* the iterators of each region in an undefined sequence. Some positions may
* be repeated if the position is contained in more than one region, but this cannot
* be guaranteed to occur.</p>
*/
public class RegionIntersection extends AbstractRegion {
private final List<Region> regions = new ArrayList<Region>();
/**
* Create a new instance with the included list of regions.
*
* @param regions a list of regions, which is copied
*/
public RegionIntersection(List<Region> regions) {
this(null, regions);
}
/**
* Create a new instance with the included list of regions.
*
* @param regions a list of regions, which is copied
*/
public RegionIntersection(Region... regions) {
this(null, regions);
}
/**
* Create a new instance with the included list of regions.
*
* @param world the world
* @param regions a list of regions, which is copied
*/
public RegionIntersection(LocalWorld world, List<Region> regions) {
super(world);
checkNotNull(regions);
checkArgument(!regions.isEmpty(), "empty region list is not supported");
for (Region region : regions) {
this.regions.add(region);
}
}
/**
* Create a new instance with the included list of regions.
*
* @param world the world
* @param regions an array of regions, which is copied
*/
public RegionIntersection(LocalWorld world, Region... regions) {
super(world);
checkNotNull(regions);
checkArgument(regions.length > 0, "empty region list is not supported");
Collections.addAll(this.regions, regions);
}
@Override
public Vector getMinimumPoint() {
Vector minimum = regions.get(0).getMinimumPoint();
for (int i = 1; i < regions.size(); i++) {
minimum = Vector.getMinimum(regions.get(i).getMinimumPoint(), minimum);
}
return minimum;
}
@Override
public Vector getMaximumPoint() {
Vector maximum = regions.get(0).getMaximumPoint();
for (int i = 1; i < regions.size(); i++) {
maximum = Vector.getMaximum(regions.get(i).getMaximumPoint(), maximum);
}
return maximum;
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
checkNotNull(changes);
throw new RegionOperationException("Cannot expand a region intersection");
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
checkNotNull(changes);
throw new RegionOperationException("Cannot contract a region intersection");
}
@Override
public boolean contains(Vector position) {
checkNotNull(position);
for (Region region : regions) {
if (region.contains(position)) {
return true;
}
}
return false;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Iterator<BlockVector> iterator() {
Iterator<BlockVector>[] iterators = (Iterator<BlockVector>[]) new Iterator[regions.size()];
for (int i = 0; i < regions.size(); i++) {
iterators[i] = regions.get(i).iterator();
}
return Iterators.concat(iterators);
}
}

View File

@@ -0,0 +1,30 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.WorldEditException;
public class RegionOperationException extends WorldEditException {
public RegionOperationException(String msg) {
super(msg);
}
}

View File

@@ -0,0 +1,159 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.List;
/**
* Region selectors create {@link Region}s from a series of "selected points."
* They are used, for example, to allow users to create a {@link CuboidRegion}
* by selecting two corners of the cuboid.
*/
public interface RegionSelector {
/**
* Get the world for the region selector.
*
* @return a world, which may be null
*/
@Nullable
public World getWorld();
/**
* Set the world for the region selector.
*
* @param world the world, which may be null
*/
public void setWorld(@Nullable World world);
/**
* Called when the first point is selected.
*
* @param position the position
* @return true if something changed
*/
public boolean selectPrimary(Vector position, SelectorLimits limits);
/**
* Called when the second point is selected.
*
* @param position the position
* @return true if something changed
*/
public boolean selectSecondary(Vector position, SelectorLimits limits);
/**
* Tell the player information about his/her primary selection.
*
* @param actor the actor
* @param session the session
* @param position position
*/
public void explainPrimarySelection(Actor actor, LocalSession session, Vector position);
/**
* Tell the player information about his/her secondary selection.
*
* @param actor the actor
* @param session the session
* @param position position
*/
public void explainSecondarySelection(Actor actor, LocalSession session, Vector position);
/**
* The the player information about the region's changes. This may resend
* all the defining region information if needed.
*
* @param actor the actor
* @param session the session
*/
public void explainRegionAdjust(Actor actor, LocalSession session);
/**
* Get the primary position.
*
* @return the primary position
* @throws IncompleteRegionException thrown if a region has not been fully defined
*/
public BlockVector getPrimaryPosition() throws IncompleteRegionException;
/**
* Get the selection.
*
* @return the created region
* @throws IncompleteRegionException thrown if a region has not been fully defined
*/
public Region getRegion() throws IncompleteRegionException;
/**
* Get the region even if it's not fully defined.
*
* @return an incomplete region object that is incomplete
*/
public Region getIncompleteRegion();
/**
* Returns whether the region has been fully defined.
*
* @return true if a selection is available
*/
public boolean isDefined();
/**
* Get the number of blocks inside the region.
*
* @return number of blocks, or -1 if undefined
*/
public int getArea();
/**
* Update the selector with changes to the region.
*/
public void learnChanges();
/**
* Clear the selection.
*/
public void clear();
/**
* Get a lowercase name of this region selector type.
*
* @return a lower case name of the type
*/
public String getTypeName();
/**
* Get lines of information about the selection.
*
* @return a list of lines describing the region
*/
public List<String> getInformationLines();
}

View File

@@ -0,0 +1,92 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
/**
* Utility methods relating to {@link Region}s.
*/
public final class Regions {
private Regions() {
}
/**
* Get the minimum Y coordinate of the given region using the region's
* {@link Region#getMinimumPoint()} method.
*
* @param region the region
* @return the Y coordinate
*/
public static double minimumY(Region region) {
return region.getMinimumPoint().getY();
}
/**
* Get the maximum Y coordinate of the given region using the region's
* {@link Region#getMaximumPoint()} method.
*
* @param region the region
* @return the Y coordinate
*/
public static double maximumY(Region region) {
return region.getMaximumPoint().getY();
}
/**
* Get the minimum Y coordinate of the given region using the region's
* {@link Region#getMinimumPoint()} method.
*
* @param region the region
* @return the Y coordinate
*/
public static int minimumBlockY(Region region) {
return region.getMinimumPoint().getBlockY();
}
/**
* Get the maximum Y coordinate of the given region using the region's
* {@link Region#getMaximumPoint()} method.
*
* @param region the region
* @return the Y coordinate
*/
public static int maximumBlockY(Region region) {
return region.getMaximumPoint().getBlockY();
}
/**
* Attempt to get a {@link FlatRegion} from the given region.
*
* <p>If the given region is already a {@link FlatRegion}, then the region
* will be cast and returned. Otherwise, a new {@link CuboidRegion} will
* be created covers the provided region's minimum and maximum extents.</p>
*
* @param region the region
* @return a flat region
*/
public static FlatRegion asFlatRegion(Region region) {
if (region instanceof FlatRegion) {
return (FlatRegion) region;
} else {
return CuboidRegion.makeCuboid(region);
}
}
}

View File

@@ -0,0 +1,190 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.math.transform.Identity;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Transforms another region according to a provided vector {@code Transform}.
*
* @see Transform
*/
public class TransformRegion extends AbstractRegion {
private final Region region;
private Transform transform = new Identity();
/**
* Create a new instance.
*
* @param region the region
* @param transform the transform
*/
public TransformRegion(Region region, Transform transform) {
this(null, region, transform);
}
/**
* Create a new instance.
*
* @param world the world, which may be null
* @param region the region
* @param transform the transform
*/
public TransformRegion(@Nullable World world, Region region, Transform transform) {
super(world);
checkNotNull(region);
checkNotNull(transform);
this.region = region;
this.transform = transform;
}
/**
* Get the untransformed, base region.
*
* @return the base region
*/
public Region getRegion() {
return region;
}
/**
* Get the transform that is applied.
*
* @return the transform
*/
public Transform getTransform() {
return transform;
}
/**
* Set the transform that is applied.
*
* @param transform the transform
*/
public void setTransform(Transform transform) {
checkNotNull(transform);
this.transform = transform;
}
@Override
public Vector getMinimumPoint() {
return transform.apply(region.getMinimumPoint());
}
@Override
public Vector getMaximumPoint() {
return transform.apply(region.getMaximumPoint());
}
@Override
public Vector getCenter() {
return transform.apply(region.getCenter());
}
@Override
public int getArea() {
return region.getArea(); // Cannot transform this
}
@Override
public int getWidth() {
return getMaximumPoint().subtract(getMinimumPoint()).getBlockX() + 1;
}
@Override
public int getHeight() {
return getMaximumPoint().subtract(getMinimumPoint()).getBlockY() + 1;
}
@Override
public int getLength() {
return getMaximumPoint().subtract(getMinimumPoint()).getBlockZ() + 1;
}
@Override
public void expand(Vector... changes) throws RegionOperationException {
throw new RegionOperationException("Can't expand a TransformedRegion");
}
@Override
public void contract(Vector... changes) throws RegionOperationException {
throw new RegionOperationException("Can't contract a TransformedRegion");
}
@Override
public void shift(Vector change) throws RegionOperationException {
throw new RegionOperationException("Can't change a TransformedRegion");
}
@Override
public boolean contains(Vector position) {
return region.contains(transform.inverse().apply(position));
}
@Override
public List<BlockVector2D> polygonize(int maxPoints) {
List<BlockVector2D> origPoints = region.polygonize(maxPoints);
List<BlockVector2D> transformedPoints = new ArrayList<BlockVector2D>();
for (BlockVector2D vector : origPoints) {
transformedPoints.add(transform.apply(vector.toVector(0)).toVector2D().toBlockVector2D());
}
return transformedPoints;
}
@Override
public Iterator<BlockVector> iterator() {
final Iterator<BlockVector> it = region.iterator();
return new Iterator<BlockVector>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public BlockVector next() {
BlockVector next = it.next();
if (next != null) {
return transform.apply(next).toBlockVector();
} else {
return null;
}
}
@Override
public void remove() {
it.remove();
}
};
}
}

View File

@@ -0,0 +1,89 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.iterator;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.regions.FlatRegion;
import java.util.Iterator;
import java.util.NoSuchElementException;
import static com.google.common.base.Preconditions.checkNotNull;
public class FlatRegion3DIterator implements Iterator<BlockVector> {
private Iterator<Vector2D> flatIterator;
private int minY;
private int maxY;
private Vector2D next2D;
private int nextY;
public FlatRegion3DIterator(FlatRegion region, Iterator<Vector2D> flatIterator) {
checkNotNull(region);
checkNotNull(flatIterator);
this.flatIterator = flatIterator;
this.minY = region.getMinimumY();
this.maxY = region.getMaximumY();
if (flatIterator.hasNext()) {
this.next2D = flatIterator.next();
} else {
this.next2D = null;
}
this.nextY = minY;
}
public FlatRegion3DIterator(FlatRegion region) {
this(region, region.asFlatRegion().iterator());
}
@Override
public boolean hasNext() {
return next2D != null;
}
@Override
public BlockVector next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
BlockVector current = new BlockVector(next2D.getBlockX(), nextY, next2D.getBlockZ());
if (nextY < maxY) {
nextY++;
} else if (flatIterator.hasNext()) {
next2D = flatIterator.next();
nextY = minY;
} else {
next2D = null;
}
return current;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,103 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.iterator;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.regions.Region;
import java.util.Iterator;
import static com.google.common.base.Preconditions.checkNotNull;
public class FlatRegionIterator implements Iterator<Vector2D> {
private Region region;
private int y;
private int minX;
private int nextX;
private int nextZ;
private int maxX;
private int maxZ;
public FlatRegionIterator(Region region) {
checkNotNull(region);
this.region = region;
Vector min = region.getMinimumPoint();
Vector max = region.getMaximumPoint();
this.y = min.getBlockY();
this.minX = min.getBlockX();
this.nextX = minX;
this.nextZ = min.getBlockZ();
this.maxX = max.getBlockX();
this.maxZ = max.getBlockZ();
forward();
}
@Override
public boolean hasNext() {
return nextX != Integer.MIN_VALUE;
}
private void forward() {
while (hasNext() && !region.contains(new Vector(nextX, y, nextZ))) {
forwardOne();
}
}
@Override
public Vector2D next() {
if (!hasNext()) {
throw new java.util.NoSuchElementException();
}
Vector2D answer = new Vector2D(nextX, nextZ);
forwardOne();
forward();
return answer;
}
private void forwardOne() {
if (++nextX <= maxX) {
return;
}
nextX = minX;
if (++nextZ <= maxZ) {
return;
}
nextX = Integer.MIN_VALUE;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,104 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.iterator;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.Region;
import java.util.Iterator;
import static com.google.common.base.Preconditions.checkNotNull;
public class RegionIterator implements Iterator<BlockVector> {
private final Region region;
private final int maxX;
private final int maxY;
private final int maxZ;
private final Vector min;
private int nextX;
private int nextY;
private int nextZ;
public RegionIterator(Region region) {
checkNotNull(region);
this.region = region;
Vector max = region.getMaximumPoint();
this.maxX = max.getBlockX();
this.maxY = max.getBlockY();
this.maxZ = max.getBlockZ();
this.min = region.getMinimumPoint();
this.nextX = min.getBlockX();
this.nextY = min.getBlockY();
this.nextZ = min.getBlockZ();
forward();
}
@Override
public boolean hasNext() {
return nextX != Integer.MIN_VALUE;
}
private void forward() {
while (hasNext() && !region.contains(new BlockVector(nextX, nextY, nextZ))) {
forwardOne();
}
}
@Override
public BlockVector next() {
if (!hasNext()) throw new java.util.NoSuchElementException();
BlockVector answer = new BlockVector(nextX, nextY, nextZ);
forwardOne();
forward();
return answer;
}
private void forwardOne() {
if (++nextX <= maxX) {
return;
}
nextX = min.getBlockX();
if (++nextY <= maxY) {
return;
}
nextY = min.getBlockY();
if (++nextZ <= maxZ) {
return;
}
nextX = Integer.MIN_VALUE;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,90 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.Vector;
import static com.google.common.base.Preconditions.checkNotNull;
public class Edge {
private final Vector start;
private final Vector end;
public Edge(Vector start, Vector end) {
checkNotNull(start);
checkNotNull(end);
this.start = start;
this.end = end;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Edge)) {
return false;
}
Edge otherEdge = (Edge) other;
if ((this.start == otherEdge.end) && (this.end == otherEdge.start)) {
return true;
}
if ((this.end == otherEdge.end) && (this.start == otherEdge.start)) {
return true;
}
return false;
}
@Override
public int hashCode() {
return start.hashCode() ^ end.hashCode();
}
@Override
public String toString() {
return "(" + this.start + "," + this.end + ")";
}
/**
* Create a triangle from { this.start, this.end, vertex }
*
* @param vertex the 3rd vertex for the triangle
* @return a triangle
*/
public Triangle createTriangle(Vector vertex) {
checkNotNull(vertex);
return new Triangle(this.start, this.end, vertex);
}
/**
* Create a triangle from { this.start, vertex, this.end }.
*
* @param vertex the second vertex
* @return a new triangle
*/
public Triangle createTriangle2(Vector vertex) {
checkNotNull(vertex);
return new Triangle(this.start, vertex, this.end);
}
}

View File

@@ -0,0 +1,113 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.polyhedron;
import com.sk89q.worldedit.Vector;
import static com.google.common.base.Preconditions.checkNotNull;
public class Triangle {
private String tag = "Triangle";
private final Vector[] vertices;
private final Vector normal;
private final double b;
/**
* Constructs a triangle with the given vertices (counter-clockwise)
*
* @param v0 first vertex
* @param v1 second vertex
* @param v2 third vertex
*/
public Triangle(Vector v0, Vector v1, Vector v2) {
checkNotNull(v0);
checkNotNull(v1);
checkNotNull(v2);
vertices = new Vector[] { v0, v1, v2 };
this.normal = v1.subtract(v0).cross(v2.subtract(v0)).normalize();
this.b = Math.max(Math.max(normal.dot(v0), normal.dot(v1)), normal.dot(v2));
}
/**
* Returns the triangle's vertex with the given index, counter-clockwise.
*
* @param index Vertex index. Valid input: 0..2
* @return a vertex
*/
public Vector getVertex(int index) {
return vertices[index];
}
/**
* Returns the triangle's edge with the given index, counter-clockwise.
*
* @param index Edge index. Valid input: 0..2
* @return an edge
*/
public Edge getEdge(int index) {
if (index == vertices.length - 1) {
return new Edge(vertices[index], vertices[0]);
}
return new Edge(vertices[index], vertices[index + 1]);
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is below
*/
public boolean below(Vector pt) {
checkNotNull(pt);
return normal.dot(pt) < b;
}
/**
* Returns whether the given point is above the plane the triangle is in.
*
* @param pt the point to test
* @return true if the point is above
*/
public boolean above(Vector pt) {
checkNotNull(pt);
return normal.dot(pt) > b;
}
/**
* Set the triangle's tag.
*
* @param tag the tag
* @return this object
*/
public Triangle tag(String tag) {
checkNotNull(tag);
this.tag = tag;
return this;
}
@Override
public String toString() {
return tag + "(" + this.vertices[0] + "," + this.vertices[1] + "," + this.vertices[2] + ")";
}
}

View File

@@ -0,0 +1,274 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.google.common.base.Optional;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIRegion;
import com.sk89q.worldedit.internal.cui.SelectionPointEvent;
import com.sk89q.worldedit.internal.cui.SelectionPolygonEvent;
import com.sk89q.worldedit.regions.ConvexPolyhedralRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.polyhedron.Triangle;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates a {@code ConvexPolyhedralRegion} from a user's selections.
*/
public class ConvexPolyhedralRegionSelector extends com.sk89q.worldedit.regions.ConvexPolyhedralRegionSelector implements RegionSelector, CUIRegion {
private final transient ConvexPolyhedralRegion region;
private transient BlockVector pos1;
/**
* Create a new selector with a {@code null} world.
*/
public ConvexPolyhedralRegionSelector() {
this((World) null);
}
/**
* Create a new selector.
*
* @param world the world, which may be {@code null}
*/
public ConvexPolyhedralRegionSelector(@Nullable World world) {
region = new ConvexPolyhedralRegion(world);
}
/**
* Create a new selector.
*
* @param oldSelector the old selector
*/
public ConvexPolyhedralRegionSelector(RegionSelector oldSelector) {
checkNotNull(oldSelector);
if (oldSelector instanceof ConvexPolyhedralRegionSelector) {
final ConvexPolyhedralRegionSelector convexPolyhedralRegionSelector = (ConvexPolyhedralRegionSelector) oldSelector;
pos1 = convexPolyhedralRegionSelector.pos1;
region = new ConvexPolyhedralRegion(convexPolyhedralRegionSelector.region);
} else {
final Region oldRegion;
try {
oldRegion = oldSelector.getRegion();
} catch (IncompleteRegionException e) {
region = new ConvexPolyhedralRegion(oldSelector.getIncompleteRegion().getWorld());
return;
}
final int minY = oldRegion.getMinimumPoint().getBlockY();
final int maxY = oldRegion.getMaximumPoint().getBlockY();
region = new ConvexPolyhedralRegion(oldRegion.getWorld());
for (final BlockVector2D pt : new ArrayList<BlockVector2D>(oldRegion.polygonize(Integer.MAX_VALUE))) {
region.addVertex(pt.toVector(minY));
region.addVertex(pt.toVector(maxY));
}
learnChanges();
}
}
@Nullable
@Override
public World getWorld() {
return region.getWorld();
}
@Override
public void setWorld(@Nullable World world) {
region.setWorld(world);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
checkNotNull(position);
clear();
pos1 = position.toBlockVector();
return region.addVertex(position);
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
checkNotNull(position);
Optional<Integer> vertexLimit = limits.getPolyhedronVertexLimit();
if (vertexLimit.isPresent() && region.getVertices().size() > vertexLimit.get()) {
return false;
}
return region.addVertex(position);
}
@Override
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
return pos1;
}
@Override
public Region getRegion() throws IncompleteRegionException {
if (!region.isDefined()) {
throw new IncompleteRegionException();
}
return region;
}
@Override
public Region getIncompleteRegion() {
return region;
}
@Override
public boolean isDefined() {
return region.isDefined();
}
@Override
public int getArea() {
return region.getArea();
}
@Override
public void learnChanges() {
pos1 = region.getVertices().iterator().next().toBlockVector();
}
@Override
public void clear() {
region.clear();
}
@Override
public String getTypeName() {
return "Convex Polyhedron";
}
@Override
public List<String> getInformationLines() {
List<String> ret = new ArrayList<String>();
ret.add("Vertices: "+region.getVertices().size());
ret.add("Triangles: "+region.getTriangles().size());
return ret;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
checkNotNull(player);
checkNotNull(session);
checkNotNull(pos);
session.describeCUI(player);
player.print("Started new selection with vertex "+pos+".");
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
checkNotNull(player);
checkNotNull(session);
checkNotNull(pos);
session.describeCUI(player);
player.print("Added vertex " + pos + " to the selection.");
}
@Override
public void explainRegionAdjust(Actor player, LocalSession session) {
checkNotNull(player);
checkNotNull(session);
session.describeCUI(player);
}
@Override
public int getProtocolVersion() {
return 3;
}
@Override
public String getTypeID() {
return "polyhedron";
}
@Override
public void describeCUI(LocalSession session, Actor player) {
checkNotNull(player);
checkNotNull(session);
Collection<Vector> vertices = region.getVertices();
Collection<Triangle> triangles = region.getTriangles();
Map<Vector, Integer> vertexIds = new HashMap<Vector, Integer>(vertices.size());
int lastVertexId = -1;
for (Vector vertex : vertices) {
vertexIds.put(vertex, ++lastVertexId);
session.dispatchCUIEvent(player, new SelectionPointEvent(lastVertexId, vertex, getArea()));
}
for (Triangle triangle : triangles) {
final int[] v = new int[3];
for (int i = 0; i < 3; ++i) {
v[i] = vertexIds.get(triangle.getVertex(i));
}
session.dispatchCUIEvent(player, new SelectionPolygonEvent(v));
}
}
@Override
public String getLegacyTypeID() {
return "cuboid";
}
@Override
public void describeLegacyCUI(LocalSession session, Actor player) {
checkNotNull(player);
checkNotNull(session);
if (isDefined()) {
session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea()));
session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea()));
}
}
}

View File

@@ -0,0 +1,294 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIRegion;
import com.sk89q.worldedit.internal.cui.SelectionPointEvent;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates a {@code CuboidRegion} from a user's selections.
*/
public class CuboidRegionSelector extends com.sk89q.worldedit.regions.CuboidRegionSelector implements RegionSelector, CUIRegion {
protected transient BlockVector position1;
protected transient BlockVector position2;
protected transient CuboidRegion region;
/**
* Create a new region selector with a {@code null} world.
*/
public CuboidRegionSelector() {
this((World) null);
}
/**
* Create a new region selector.
*
* @param world the world, which may be {@code null}
*/
public CuboidRegionSelector(@Nullable World world) {
region = new CuboidRegion(world, new Vector(), new Vector());
}
/**
* Create a copy of another selector.
*
* @param oldSelector another selector
*/
public CuboidRegionSelector(RegionSelector oldSelector) {
this(checkNotNull(oldSelector).getIncompleteRegion().getWorld());
if (oldSelector instanceof CuboidRegionSelector) {
final CuboidRegionSelector cuboidRegionSelector = (CuboidRegionSelector) oldSelector;
position1 = cuboidRegionSelector.position1;
position2 = cuboidRegionSelector.position2;
} else {
final Region oldRegion;
try {
oldRegion = oldSelector.getRegion();
} catch (IncompleteRegionException e) {
return;
}
position1 = oldRegion.getMinimumPoint().toBlockVector();
position2 = oldRegion.getMaximumPoint().toBlockVector();
}
region.setPos1(position1);
region.setPos2(position2);
}
/**
* Create a new region selector with the given two positions.
*
* @param world the world
* @param position1 position 1
* @param position2 position 2
*/
public CuboidRegionSelector(@Nullable World world, Vector position1, Vector position2) {
this(world);
checkNotNull(position1);
checkNotNull(position2);
this.position1 = position1.toBlockVector();
this.position2 = position2.toBlockVector();
region.setPos1(position1);
region.setPos2(position2);
}
@Nullable
@Override
public World getWorld() {
return region.getWorld();
}
@Override
public void setWorld(@Nullable World world) {
region.setWorld(world);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
checkNotNull(position);
if (position1 != null && (position.compareTo(position1) == 0)) {
return false;
}
position1 = position.toBlockVector();
region.setPos1(position1);
return true;
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
checkNotNull(position);
if (position2 != null && (position.compareTo(position2)) == 0) {
return false;
}
position2 = position.toBlockVector();
region.setPos2(position2);
return true;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
checkNotNull(player);
checkNotNull(session);
checkNotNull(pos);
if (position1 != null && position2 != null) {
player.print("First position set to " + position1 + " (" + region.getArea() + ").");
} else {
player.print("First position set to " + position1 + ".");
}
session.dispatchCUIEvent(player, new SelectionPointEvent(0, pos, getArea()));
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
checkNotNull(player);
checkNotNull(session);
checkNotNull(pos);
if (position1 != null && position2 != null) {
player.print("Second position set to " + position2 + " (" + region.getArea() + ").");
} else {
player.print("Second position set to " + position2 + ".");
}
session.dispatchCUIEvent(player, new SelectionPointEvent(1, pos, getArea()));
}
@Override
public void explainRegionAdjust(Actor player, LocalSession session) {
checkNotNull(player);
checkNotNull(session);
if (position1 != null) {
session.dispatchCUIEvent(player, new SelectionPointEvent(0, position1, getArea()));
}
if (position2 != null) {
session.dispatchCUIEvent(player, new SelectionPointEvent(1, position2, getArea()));
}
}
@Override
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
if (position1 == null) {
throw new IncompleteRegionException();
}
return position1;
}
@Override
public boolean isDefined() {
return position1 != null && position2 != null;
}
@Override
public CuboidRegion getRegion() throws IncompleteRegionException {
if (position1 == null || position2 == null) {
throw new IncompleteRegionException();
}
return region;
}
@Override
public CuboidRegion getIncompleteRegion() {
return region;
}
@Override
public void learnChanges() {
position1 = region.getPos1().toBlockVector();
position2 = region.getPos2().toBlockVector();
}
@Override
public void clear() {
position1 = null;
position2 = null;
}
@Override
public String getTypeName() {
return "cuboid";
}
@Override
public List<String> getInformationLines() {
final List<String> lines = new ArrayList<String>();
if (position1 != null) {
lines.add("Position 1: " + position1);
}
if (position2 != null) {
lines.add("Position 2: " + position2);
}
return lines;
}
@Override
public int getArea() {
if (position1 == null) {
return -1;
}
if (position2 == null) {
return -1;
}
return region.getArea();
}
@Override
public void describeCUI(LocalSession session, Actor player) {
if (position1 != null) {
session.dispatchCUIEvent(player, new SelectionPointEvent(0, position1, getArea()));
}
if (position2 != null) {
session.dispatchCUIEvent(player, new SelectionPointEvent(1, position2, getArea()));
}
}
@Override
public void describeLegacyCUI(LocalSession session, Actor player) {
describeCUI(session, player);
}
@Override
public int getProtocolVersion() {
return 0;
}
@Override
public String getTypeID() {
return "cuboid";
}
@Override
public String getLegacyTypeID() {
return "cuboid";
}
}

View File

@@ -0,0 +1,274 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.*;
import com.sk89q.worldedit.regions.CylinderRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates a {@code CylinderRegionSelector} from a user's selections.
*/
public class CylinderRegionSelector extends com.sk89q.worldedit.regions.CylinderRegionSelector implements RegionSelector, CUIRegion {
protected static transient final NumberFormat NUMBER_FORMAT;
protected transient CylinderRegion region;
static {
NUMBER_FORMAT = (NumberFormat) NumberFormat.getInstance().clone();
NUMBER_FORMAT.setMaximumFractionDigits(3);
}
/**
* Create a new region selector with a {@code null} world.
*/
public CylinderRegionSelector() {
this((World) null);
}
/**
* Create a new region selector.
*
* @param world the world, which may be {@code null}
*/
public CylinderRegionSelector(@Nullable World world) {
region = new CylinderRegion(world);
}
/**
* Create a new selector from the given one.
*
* @param oldSelector the old selector
*/
public CylinderRegionSelector(RegionSelector oldSelector) {
this(checkNotNull(oldSelector).getIncompleteRegion().getWorld());
if (oldSelector instanceof CylinderRegionSelector) {
final CylinderRegionSelector cylSelector = (CylinderRegionSelector) oldSelector;
region = new CylinderRegion(cylSelector.region);
} else {
final Region oldRegion;
try {
oldRegion = oldSelector.getRegion();
} catch (IncompleteRegionException e) {
return;
}
Vector pos1 = oldRegion.getMinimumPoint();
Vector pos2 = oldRegion.getMaximumPoint();
Vector center = pos1.add(pos2).divide(2).floor();
region.setCenter(center.toVector2D());
region.setRadius(pos2.toVector2D().subtract(center.toVector2D()));
region.setMaximumY(Math.max(pos1.getBlockY(), pos2.getBlockY()));
region.setMinimumY(Math.min(pos1.getBlockY(), pos2.getBlockY()));
}
}
/**
* Create a new selector.
*
* @param world the world
* @param center the center
* @param radius the radius
* @param minY the minimum Y
* @param maxY the maximum Y
*/
public CylinderRegionSelector(@Nullable World world, Vector2D center, Vector2D radius, int minY, int maxY) {
this(world);
region.setCenter(center);
region.setRadius(radius);
region.setMinimumY(Math.min(minY, maxY));
region.setMaximumY(Math.max(minY, maxY));
}
@Nullable
@Override
public World getWorld() {
return region.getWorld();
}
@Override
public void setWorld(@Nullable World world) {
region.setWorld(world);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
if (!region.getCenter().equals(Vector.ZERO) && position.compareTo(region.getCenter()) == 0) {
return false;
}
region = new CylinderRegion(region.getWorld());
region.setCenter(position.toVector2D());
region.setY(position.getBlockY());
return true;
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
Vector center = region.getCenter();
if ((center.compareTo(Vector.ZERO)) == 0) {
return true;
}
final Vector2D diff = position.subtract(center).toVector2D();
final Vector2D minRadius = Vector2D.getMaximum(diff, diff.multiply(-1.0));
region.extendRadius(minRadius);
region.setY(position.getBlockY());
return true;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
player.print("Starting a new cylindrical selection at " + pos + ".");
session.describeCUI(player);
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
Vector center = region.getCenter();
if (!center.equals(Vector.ZERO)) {
player.print("Radius set to " + NUMBER_FORMAT.format(region.getRadius().getX()) + "/" + NUMBER_FORMAT.format(region.getRadius().getZ()) + " blocks. (" + region.getArea() + ").");
} else {
player.printError("You must select the center point before setting the radius.");
return;
}
session.describeCUI(player);
}
@Override
public void explainRegionAdjust(Actor player, LocalSession session) {
session.describeCUI(player);
}
@Override
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
if (!isDefined()) {
throw new IncompleteRegionException();
}
return region.getCenter().toBlockVector();
}
@Override
public CylinderRegion getRegion() throws IncompleteRegionException {
if (!isDefined()) {
throw new IncompleteRegionException();
}
return region;
}
@Override
public CylinderRegion getIncompleteRegion() {
return region;
}
@Override
public boolean isDefined() {
return !region.getRadius().equals(Vector2D.ZERO);
}
@Override
public void learnChanges() {
}
@Override
public void clear() {
region = new CylinderRegion(region.getWorld());
}
@Override
public String getTypeName() {
return "Cylinder";
}
@Override
public List<String> getInformationLines() {
final List<String> lines = new ArrayList<String>();
if (!region.getCenter().equals(Vector.ZERO)) {
lines.add("Center: " + region.getCenter());
}
if (!region.getRadius().equals(Vector2D.ZERO)) {
lines.add("Radius: " + region.getRadius());
}
return lines;
}
@Override
public int getArea() {
return region.getArea();
}
@Override
public void describeCUI(LocalSession session, Actor player) {
session.dispatchCUIEvent(player, new SelectionCylinderEvent(region.getCenter(), region.getRadius()));
session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY()));
}
@Override
public void describeLegacyCUI(LocalSession session, Actor player) {
if (isDefined()) {
session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea()));
session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea()));
}
}
@Override
public int getProtocolVersion() {
return 1;
}
@Override
public String getTypeID() {
return "cylinder";
}
@Override
public String getLegacyTypeID() {
return "cuboid";
}
}

View File

@@ -0,0 +1,256 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIRegion;
import com.sk89q.worldedit.internal.cui.SelectionEllipsoidPointEvent;
import com.sk89q.worldedit.internal.cui.SelectionPointEvent;
import com.sk89q.worldedit.regions.EllipsoidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates a {@code EllipsoidRegionSelector} from a user's selections.
*/
public class EllipsoidRegionSelector extends com.sk89q.worldedit.regions.EllipsoidRegionSelector implements RegionSelector, CUIRegion {
protected transient EllipsoidRegion region;
protected transient boolean started = false;
/**
* Create a new selector with a {@code null} world.
*/
public EllipsoidRegionSelector() {
this((World) null);
}
/**
* Create a new selector.
*
* @param world the world, which may be {@code null}
*/
public EllipsoidRegionSelector(@Nullable World world) {
region = new EllipsoidRegion(world, new Vector(), new Vector());
}
/**
* Create a new selector from the given selector.
*
* @param oldSelector the old selector
*/
public EllipsoidRegionSelector(RegionSelector oldSelector) {
this(checkNotNull(oldSelector).getIncompleteRegion().getWorld());
if (oldSelector instanceof EllipsoidRegionSelector) {
final EllipsoidRegionSelector ellipsoidRegionSelector = (EllipsoidRegionSelector) oldSelector;
region = new EllipsoidRegion(ellipsoidRegionSelector.getIncompleteRegion());
} else {
Region oldRegion;
try {
oldRegion = oldSelector.getRegion();
} catch (IncompleteRegionException e) {
return;
}
BlockVector pos1 = oldRegion.getMinimumPoint().toBlockVector();
BlockVector pos2 = oldRegion.getMaximumPoint().toBlockVector();
Vector center = pos1.add(pos2).divide(2).floor();
region.setCenter(center);
region.setRadius(pos2.subtract(center));
}
}
/**
* Create a new selector.
*
* @param world the world
* @param center the center
* @param radius the radius
*/
public EllipsoidRegionSelector(@Nullable World world, Vector center, Vector radius) {
this(world);
region.setCenter(center);
region.setRadius(radius);
}
@Nullable
@Override
public World getWorld() {
return region.getWorld();
}
@Override
public void setWorld(@Nullable World world) {
region.setWorld(world);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
if (position.equals(region.getCenter()) && region.getRadius().lengthSq() == 0) {
return false;
}
region.setCenter(position.toBlockVector());
region.setRadius(new Vector());
started = true;
return true;
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
if (!started) {
return false;
}
final Vector diff = position.subtract(region.getCenter());
final Vector minRadius = Vector.getMaximum(diff, diff.multiply(-1.0));
region.extendRadius(minRadius);
return true;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
if (isDefined()) {
player.print("Center position set to " + region.getCenter() + " (" + region.getArea() + ").");
} else {
player.print("Center position set to " + region.getCenter() + ".");
}
session.describeCUI(player);
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
if (isDefined()) {
player.print("Radius set to " + region.getRadius() + " (" + region.getArea() + ").");
} else {
player.print("Radius set to " + region.getRadius() + ".");
}
session.describeCUI(player);
}
@Override
public void explainRegionAdjust(Actor player, LocalSession session) {
session.describeCUI(player);
}
@Override
public boolean isDefined() {
return started && region.getRadius().lengthSq() > 0;
}
@Override
public EllipsoidRegion getRegion() throws IncompleteRegionException {
if (!isDefined()) {
throw new IncompleteRegionException();
}
return region;
}
@Override
public EllipsoidRegion getIncompleteRegion() {
return region;
}
@Override
public void learnChanges() {
}
@Override
public void clear() {
region.setCenter(new Vector());
region.setRadius(new Vector());
}
@Override
public String getTypeName() {
return "ellipsoid";
}
@Override
public List<String> getInformationLines() {
final List<String> lines = new ArrayList<String>();
final Vector center = region.getCenter();
if (center.lengthSq() > 0) {
lines.add("Center: " + center);
}
final Vector radius = region.getRadius();
if (radius.lengthSq() > 0) {
lines.add("X/Y/Z radius: " + radius);
}
return lines;
}
@Override
public int getArea() {
return region.getArea();
}
@Override
public void describeCUI(LocalSession session, Actor player) {
session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(0, region.getCenter()));
session.dispatchCUIEvent(player, new SelectionEllipsoidPointEvent(1, region.getRadius()));
}
@Override
public void describeLegacyCUI(LocalSession session, Actor player) {
session.dispatchCUIEvent(player, new SelectionPointEvent(0, region.getMinimumPoint(), getArea()));
session.dispatchCUIEvent(player, new SelectionPointEvent(1, region.getMaximumPoint(), getArea()));
}
@Override
public String getLegacyTypeID() {
return "cuboid";
}
@Override
public int getProtocolVersion() {
return 1;
}
@Override
public String getTypeID() {
return "ellipsoid";
}
@Override
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
return region.getCenter().toBlockVector();
}
}

View File

@@ -0,0 +1,145 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
/**
* Creates a {@code CuboidRegion} from a user's selections by expanding
* the region on every right click.
*/
public class ExtendingCuboidRegionSelector extends CuboidRegionSelector {
/**
* Create a new selector with a {@code null} world.
*/
public ExtendingCuboidRegionSelector() {
super((World) null);
}
/**
* Create a new selector.
*
* @param world the world, which may be {@code null}
*/
public ExtendingCuboidRegionSelector(@Nullable World world) {
super(world);
}
/**
* Create a new selector from another one.
*
* @param oldSelector the other selector
*/
public ExtendingCuboidRegionSelector(RegionSelector oldSelector) {
super(oldSelector);
if (position1 == null || position2 == null) {
return;
}
position1 = region.getMinimumPoint().toBlockVector();
position2 = region.getMaximumPoint().toBlockVector();
region.setPos1(position1);
region.setPos2(position2);
}
/**
* Create a new selector.
*
* @param world the world
* @param position1 the first position
* @param position2 the second position
*/
public ExtendingCuboidRegionSelector(@Nullable World world, Vector position1, Vector position2) {
this(world);
position1 = Vector.getMinimum(position1, position2);
position2 = Vector.getMaximum(position1, position2);
region.setPos1(position1);
region.setPos2(position2);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
if (position1 != null && position2 != null && position.compareTo(position1) == 0 && position.compareTo(position2) == 0) {
return false;
}
position1 = position2 = position.toBlockVector();
region.setPos1(position1);
region.setPos2(position2);
return true;
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
if (position1 == null || position2 == null) {
return selectPrimary(position, limits);
}
if (region.contains(position)) {
return false;
}
double x1 = Math.min(position.getX(), position1.getX());
double y1 = Math.min(position.getY(), position1.getY());
double z1 = Math.min(position.getZ(), position1.getZ());
double x2 = Math.max(position.getX(), position2.getX());
double y2 = Math.max(position.getY(), position2.getY());
double z2 = Math.max(position.getZ(), position2.getZ());
final BlockVector o1 = position1;
final BlockVector o2 = position2;
position1 = new BlockVector(x1, y1, z1);
position2 = new BlockVector(x2, y2, z2);
region.setPos1(position1);
region.setPos2(position2);
assert(region.contains(o1));
assert(region.contains(o2));
assert(region.contains(position));
return true;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
player.print("Started selection at " + pos + " (" + region.getArea() + ").");
explainRegionAdjust(player, session);
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
player.print("Extended selection to encompass " + pos + " (" + region.getArea() + ").");
explainRegionAdjust(player, session);
}
}

View File

@@ -0,0 +1,286 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.google.common.base.Optional;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIRegion;
import com.sk89q.worldedit.internal.cui.SelectionMinMaxEvent;
import com.sk89q.worldedit.internal.cui.SelectionPoint2DEvent;
import com.sk89q.worldedit.internal.cui.SelectionShapeEvent;
import com.sk89q.worldedit.regions.Polygonal2DRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates a {@code Polygonal2DRegion} from a user's selections.
*/
public class Polygonal2DRegionSelector extends com.sk89q.worldedit.regions.Polygonal2DRegionSelector implements RegionSelector, CUIRegion {
private transient BlockVector pos1;
private transient Polygonal2DRegion region;
/**
* Create a new selector with a {@code null} world.
*/
public Polygonal2DRegionSelector() {
this((World) null);
}
/**
* Create a new selector with the given world.
*
* @param world the world
*/
public Polygonal2DRegionSelector(@Nullable World world) {
region = new Polygonal2DRegion(world);
}
/**
* Create a new selector from another one.
*
* @param oldSelector the old selector
*/
public Polygonal2DRegionSelector(RegionSelector oldSelector) {
this(checkNotNull(oldSelector).getIncompleteRegion().getWorld());
if (oldSelector instanceof Polygonal2DRegionSelector) {
final Polygonal2DRegionSelector polygonal2DRegionSelector = (Polygonal2DRegionSelector) oldSelector;
pos1 = polygonal2DRegionSelector.pos1;
region = new Polygonal2DRegion(polygonal2DRegionSelector.region);
} else {
final Region oldRegion;
try {
oldRegion = oldSelector.getRegion();
} catch (IncompleteRegionException e) {
return;
}
final int minY = oldRegion.getMinimumPoint().getBlockY();
final int maxY = oldRegion.getMaximumPoint().getBlockY();
List<BlockVector2D> points = oldRegion.polygonize(Integer.MAX_VALUE);
pos1 = points.get(0).toVector(minY).toBlockVector();
region = new Polygonal2DRegion(oldRegion.getWorld(), points, minY, maxY);
}
}
/**
* @deprecated cast {@code world} to {@link World}
*/
@Deprecated
public Polygonal2DRegionSelector(@Nullable LocalWorld world, List<BlockVector2D> points, int minY, int maxY) {
this((World) world, points, minY, maxY);
}
/**
* Create a new selector.
*
* @param world the world
* @param points a list of points
* @param minY the minimum Y
* @param maxY the maximum Y
*/
public Polygonal2DRegionSelector(@Nullable World world, List<BlockVector2D> points, int minY, int maxY) {
checkNotNull(points);
final BlockVector2D pos2D = points.get(0);
pos1 = new BlockVector(pos2D.getX(), minY, pos2D.getZ());
region = new Polygonal2DRegion(world, points, minY, maxY);
}
@Nullable
@Override
public World getWorld() {
return region.getWorld();
}
@Override
public void setWorld(@Nullable World world) {
region.setWorld(world);
}
@Override
public boolean selectPrimary(Vector position, SelectorLimits limits) {
if (position.equals(pos1)) {
return false;
}
pos1 = position.toBlockVector();
region = new Polygonal2DRegion(region.getWorld());
region.addPoint(position);
region.expandY(position.getBlockY());
return true;
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
if (region.size() > 0) {
final List<BlockVector2D> points = region.getPoints();
final BlockVector2D lastPoint = points.get(region.size() - 1);
if (lastPoint.getBlockX() == position.getBlockX() && lastPoint.getBlockZ() == position.getBlockZ()) {
return false;
}
Optional<Integer> vertexLimit = limits.getPolygonVertexLimit();
if (vertexLimit.isPresent() && points.size() > vertexLimit.get()) {
return false;
}
}
region.addPoint(position);
region.expandY(position.getBlockY());
return true;
}
@Override
public void explainPrimarySelection(Actor player, LocalSession session, Vector pos) {
player.print("Starting a new polygon at " + pos + ".");
session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID()));
session.dispatchCUIEvent(player, new SelectionPoint2DEvent(0, pos, getArea()));
session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY()));
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
player.print("Added point #" + region.size() + " at " + pos + ".");
session.dispatchCUIEvent(player, new SelectionPoint2DEvent(region.size() - 1, pos, getArea()));
session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY()));
}
@Override
public void explainRegionAdjust(Actor player, LocalSession session) {
session.dispatchCUIEvent(player, new SelectionShapeEvent(getTypeID()));
describeCUI(session, player);
}
@Override
public BlockVector getPrimaryPosition() throws IncompleteRegionException {
if (pos1 == null) {
throw new IncompleteRegionException();
}
return pos1;
}
@Override
public Polygonal2DRegion getRegion() throws IncompleteRegionException {
if (!isDefined()) {
throw new IncompleteRegionException();
}
return region;
}
@Override
public Polygonal2DRegion getIncompleteRegion() {
return region;
}
@Override
public boolean isDefined() {
return region.size() > 2;
}
@Override
public void learnChanges() {
BlockVector2D pt = region.getPoints().get(0);
pos1 = new BlockVector(pt.getBlockX(), region.getMinimumPoint().getBlockY(), pt.getBlockZ());
}
@Override
public void clear() {
pos1 = null;
region = new Polygonal2DRegion(region.getWorld());
}
@Override
public String getTypeName() {
return "2Dx1D polygon";
}
@Override
public List<String> getInformationLines() {
return Collections.singletonList("# points: " + region.size());
}
@Override
public int getArea() {
return region.getArea();
}
/**
* Get the number of points.
*
* @return the number of points
*/
@Override
public int getPointCount() {
return region.getPoints().size();
}
@Override
public void describeCUI(LocalSession session, Actor player) {
final List<BlockVector2D> points = region.getPoints();
for (int id = 0; id < points.size(); id++) {
session.dispatchCUIEvent(player, new SelectionPoint2DEvent(id, points.get(id), getArea()));
}
session.dispatchCUIEvent(player, new SelectionMinMaxEvent(region.getMinimumY(), region.getMaximumY()));
}
@Override
public void describeLegacyCUI(LocalSession session, Actor player) {
describeCUI(session, player);
}
@Override
public int getProtocolVersion() {
return 0;
}
@Override
public String getTypeID() {
return "polygon2d";
}
@Override
public String getLegacyTypeID() {
return "polygon2d";
}
}

View File

@@ -0,0 +1,67 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.regions.RegionSelector;
/**
* An enum of default region selector types.
*/
public enum RegionSelectorType {
CUBOID(CuboidRegionSelector.class),
EXTENDING_CUBOID(ExtendingCuboidRegionSelector.class),
CYLINDER(CylinderRegionSelector.class),
SPHERE(SphereRegionSelector.class),
ELLIPSOID(EllipsoidRegionSelector.class),
POLYGON(Polygonal2DRegionSelector.class),
CONVEX_POLYHEDRON(ConvexPolyhedralRegionSelector.class);
private final Class<? extends RegionSelector> selectorClass;
private RegionSelectorType(Class<? extends RegionSelector> selectorClass) {
this.selectorClass = selectorClass;
}
/**
* Get the selector class.
*
* @return a selector class
*/
public Class<? extends RegionSelector> getSelectorClass() {
return selectorClass;
}
/**
* Create a new selector instance.
*
* @return a selector
*/
public RegionSelector createSelector() {
try {
return getSelectorClass().newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Could not create selector", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not create selector", e);
}
}
}

View File

@@ -0,0 +1,103 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
/**
* Creates a {@code SphereRegion} from a user's selections.
*/
public class SphereRegionSelector extends EllipsoidRegionSelector {
/**
* Create a new selector with a {@code null world}.
*/
public SphereRegionSelector() {
super();
}
/**
* Create a new selector.
*
* @param world the world, which may be {@code null}
*/
public SphereRegionSelector(@Nullable World world) {
super(world);
}
/**
* Create a new selector from another one
*
* @param oldSelector the old selector
*/
public SphereRegionSelector(RegionSelector oldSelector) {
super(oldSelector);
final Vector radius = region.getRadius();
final double radiusScalar = Math.max(Math.max(radius.getX(), radius.getY()), radius.getZ());
region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar));
}
/**
* Create a new selector.
*
* @param world the world
* @param center the center position
* @param radius the radius
*/
public SphereRegionSelector(@Nullable World world, Vector center, int radius) {
super(world, center, new Vector(radius, radius, radius));
}
@Override
public boolean selectSecondary(Vector position, SelectorLimits limits) {
if (!started) {
return false;
}
final double radiusScalar = Math.ceil(position.distance(region.getCenter()));
region.setRadius(new Vector(radiusScalar, radiusScalar, radiusScalar));
return true;
}
@Override
public void explainSecondarySelection(Actor player, LocalSession session, Vector pos) {
if (isDefined()) {
player.print("Radius set to " + region.getRadius().getX() + " (" + region.getArea() + ").");
} else {
player.print("Radius set to " + region.getRadius().getX() + ".");
}
session.describeCUI(player);
}
@Override
public String getTypeName() {
return "sphere";
}
}

View File

@@ -0,0 +1,53 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector.limit;
import com.google.common.base.Optional;
/**
* No limits at all.
*/
public class PermissiveSelectorLimits implements SelectorLimits {
private static final PermissiveSelectorLimits INSTANCE = new PermissiveSelectorLimits();
private PermissiveSelectorLimits() {
}
@Override
public Optional<Integer> getPolygonVertexLimit() {
return Optional.absent();
}
@Override
public Optional<Integer> getPolyhedronVertexLimit() {
return Optional.absent();
}
/**
* Get a static instance.
*
* @return an instance
*/
public static PermissiveSelectorLimits getInstance() {
return INSTANCE;
}
}

View File

@@ -0,0 +1,47 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.selector.limit;
import com.google.common.base.Optional;
/**
* Defines limits for selections.
*/
public interface SelectorLimits {
/**
* Get the optionally defined vertex limit for polygons.
*
* <p>If one is not present, then there is no limitation.</p>
*
* @return an optional vertex limit
*/
Optional<Integer> getPolygonVertexLimit();
/**
* Get the optionally defined vertex limit for polyhedrons.
*
* <p>If one is not present, then there is no limitation.</p>
*
* @return an optional vertex limit
*/
Optional<Integer> getPolyhedronVertexLimit();
}

View File

@@ -0,0 +1,195 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.shape;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BaseBiome;
/**
* Generates solid and hollow shapes according to materials returned by the
* {@link #getBiome} method.
*/
public abstract class ArbitraryBiomeShape {
private final FlatRegion extent;
private int cacheOffsetX;
private int cacheOffsetZ;
@SuppressWarnings("FieldCanBeLocal")
private int cacheSizeX;
private int cacheSizeZ;
public ArbitraryBiomeShape(Region extent) {
if (extent instanceof FlatRegion) {
this.extent = (FlatRegion) extent;
}
else {
// TODO: polygonize
this.extent = new CuboidRegion(extent.getWorld(), extent.getMinimumPoint(), extent.getMaximumPoint());
}
Vector2D min = extent.getMinimumPoint().toVector2D();
Vector2D max = extent.getMaximumPoint().toVector2D();
cacheOffsetX = min.getBlockX() - 1;
cacheOffsetZ = min.getBlockZ() - 1;
cacheSizeX = (int) (max.getX() - cacheOffsetX + 2);
cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2);
cache = new BaseBiome[cacheSizeX * cacheSizeZ];
}
protected Iterable<Vector2D> getExtent() {
return extent.asFlatRegion();
}
/**
* Cache entries:
* null = unknown
* OUTSIDE = outside
* else = inside
*/
private final BaseBiome[] cache;
/**
* Override this function to specify the shape to generate.
*
* @param x X coordinate to be queried
* @param z Z coordinate to be queried
* @param defaultBaseBiome The default biome for the current column.
* @return material to place or null to not place anything.
*/
protected abstract BaseBiome getBiome(int x, int z, BaseBiome defaultBaseBiome);
private BaseBiome getBiomeCached(int x, int z, BaseBiome baseBiome) {
final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ;
final BaseBiome cacheEntry = cache[index];
if (cacheEntry == null) {// unknown, fetch material
final BaseBiome material = getBiome(x, z, baseBiome);
if (material == null) {
// outside
cache[index] = OUTSIDE;
return null;
}
cache[index] = material;
return material;
}
if (cacheEntry == OUTSIDE) {
// outside
return null;
}
return cacheEntry;
}
private boolean isInsideCached(int x, int z, BaseBiome baseBiome) {
final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ;
final BaseBiome cacheEntry = cache[index];
if (cacheEntry == null) {
// unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape
return getBiomeCached(x, z, baseBiome) != null;
}
return cacheEntry != OUTSIDE;
}
/**
* Generates the shape.
*
* @param editSession The EditSession to use.
* @param baseBiome The default biome type.
* @param hollow Specifies whether to generate a hollow shape.
* @return number of affected blocks.
*/
public int generate(EditSession editSession, BaseBiome baseBiome, boolean hollow) {
int affected = 0;
for (Vector2D position : getExtent()) {
int x = position.getBlockX();
int z = position.getBlockZ();
if (!hollow) {
final BaseBiome material = getBiome(x, z, baseBiome);
if (material != OUTSIDE) {
editSession.getWorld().setBiome(position, material);
++affected;
}
continue;
}
final BaseBiome material = getBiomeCached(x, z, baseBiome);
if (material == null) {
continue;
}
boolean draw = false;
do {
if (!isInsideCached(x + 1, z, baseBiome)) {
draw = true;
break;
}
if (!isInsideCached(x - 1, z, baseBiome)) {
draw = true;
break;
}
if (!isInsideCached(x, z + 1, baseBiome)) {
draw = true;
break;
}
if (!isInsideCached(x, z - 1, baseBiome)) {
draw = true;
break;
}
} while (false);
if (!draw) {
continue;
}
editSession.getWorld().setBiome(position, material);
++affected;
}
return affected;
}
private static final BaseBiome OUTSIDE = new BaseBiome(0) {
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object o) {
return this == o;
}
};
}

View File

@@ -0,0 +1,211 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.shape;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.patterns.Pattern;
import com.sk89q.worldedit.regions.Region;
/**
* Generates solid and hollow shapes according to materials returned by the
* {@link #getMaterial} method.
*/
public abstract class ArbitraryShape {
protected final Region extent;
private int cacheOffsetX;
private int cacheOffsetY;
private int cacheOffsetZ;
@SuppressWarnings("FieldCanBeLocal")
private int cacheSizeX;
private int cacheSizeY;
private int cacheSizeZ;
public ArbitraryShape(Region extent) {
this.extent = extent;
Vector min = extent.getMinimumPoint();
Vector max = extent.getMaximumPoint();
cacheOffsetX = min.getBlockX() - 1;
cacheOffsetY = min.getBlockY() - 1;
cacheOffsetZ = min.getBlockZ() - 1;
cacheSizeX = (int) (max.getX() - cacheOffsetX + 2);
cacheSizeY = (int) (max.getY() - cacheOffsetY + 2);
cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2);
cache = new short[cacheSizeX * cacheSizeY * cacheSizeZ];
}
protected Region getExtent() {
return extent;
}
/**
* Cache entries:
* 0 = unknown
* -1 = outside
* -2 = inside but type and data 0
* > 0 = inside, value = (type | (data << 8)), not handling data < 0
*/
private final short[] cache;
/**
* Override this function to specify the shape to generate.
*
* @param x X coordinate to be queried
* @param y Y coordinate to be queried
* @param z Z coordinate to be queried
* @param defaultMaterial The material returned by the pattern for the current block.
* @return material to place or null to not place anything.
*/
protected abstract BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial);
private BaseBlock getMaterialCached(int x, int y, int z, Pattern pattern) {
final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
final short cacheEntry = cache[index];
switch (cacheEntry) {
case 0:
// unknown, fetch material
final BaseBlock material = getMaterial(x, y, z, pattern.next(new BlockVector(x, y, z)));
if (material == null) {
// outside
cache[index] = -1;
return null;
}
short newCacheEntry = (short) (material.getType() | ((material.getData() + 1) << 8));
if (newCacheEntry == 0) {
// type and data 0
newCacheEntry = -2;
}
cache[index] = newCacheEntry;
return material;
case -1:
// outside
return null;
case -2:
// type and data 0
return new BaseBlock(0, 0);
}
return new BaseBlock(cacheEntry & 255, ((cacheEntry >> 8) - 1) & 15);
}
private boolean isInsideCached(int x, int y, int z, Pattern pattern) {
final int index = (y - cacheOffsetY) + (z - cacheOffsetZ) * cacheSizeY + (x - cacheOffsetX) * cacheSizeY * cacheSizeZ;
switch (cache[index]) {
case 0:
// unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape
return getMaterialCached(x, y, z, pattern) != null;
case -1:
// outside
return false;
default:
// inside
return true;
}
}
/**
* Generates the shape.
*
* @param editSession The EditSession to use.
* @param pattern The pattern to generate default materials from.
* @param hollow Specifies whether to generate a hollow shape.
* @return number of affected blocks.
* @throws MaxChangedBlocksException
*/
public int generate(EditSession editSession, Pattern pattern, boolean hollow) throws MaxChangedBlocksException {
int affected = 0;
for (BlockVector position : getExtent()) {
int x = position.getBlockX();
int y = position.getBlockY();
int z = position.getBlockZ();
if (!hollow) {
final BaseBlock material = getMaterial(x, y, z, pattern.next(position));
if (material != null && editSession.setBlock(position, material)) {
++affected;
}
continue;
}
final BaseBlock material = getMaterialCached(x, y, z, pattern);
if (material == null) {
continue;
}
boolean draw = false;
do {
if (!isInsideCached(x + 1, y, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x - 1, y, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y, z + 1, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y, z - 1, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y + 1, z, pattern)) {
draw = true;
break;
}
if (!isInsideCached(x, y - 1, z, pattern)) {
draw = true;
break;
}
} while (false);
if (!draw) {
continue;
}
if (editSession.setBlock(position, material)) {
++affected;
}
}
return affected;
}
}

View File

@@ -0,0 +1,45 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.shape;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.regions.Region;
/**
* Generates solid and hollow shapes according to materials returned by the
* {@link #getMaterial} method.
*/
public class RegionShape extends ArbitraryShape {
public RegionShape(Region extent) {
super(extent);
}
@Override
protected BaseBlock getMaterial(int x, int y, int z, BaseBlock defaultMaterial) {
if (!this.extent.contains(new Vector(x, y, z))) {
return null;
}
return defaultMaterial;
}
}

View File

@@ -0,0 +1,83 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.regions.shape;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
public class WorldEditExpressionEnvironment implements ExpressionEnvironment {
private final Vector unit;
private final Vector zero2;
private Vector current = new Vector();
private EditSession editSession;
public WorldEditExpressionEnvironment(EditSession editSession, Vector unit, Vector zero) {
this.editSession = editSession;
this.unit = unit;
this.zero2 = zero.add(0.5, 0.5, 0.5);
}
public BlockVector toWorld(double x, double y, double z) {
// unscale, unoffset, round-nearest
return new Vector(x, y, z).multiply(unit).add(zero2).toBlockPoint();
}
public Vector toWorldRel(double x, double y, double z) {
return current.add(x, y, z);
}
@Override
public int getBlockType(double x, double y, double z) {
return editSession.getBlockType(toWorld(x, y, z));
}
@Override
public int getBlockData(double x, double y, double z) {
return editSession.getBlockData(toWorld(x, y, z));
}
@Override
public int getBlockTypeAbs(double x, double y, double z) {
return editSession.getBlockType(new Vector(x, y, z));
}
@Override
public int getBlockDataAbs(double x, double y, double z) {
return editSession.getBlockData(new Vector(x, y, z));
}
@Override
public int getBlockTypeRel(double x, double y, double z) {
return editSession.getBlockType(toWorldRel(x, y, z));
}
@Override
public int getBlockDataRel(double x, double y, double z) {
return editSession.getBlockData(toWorldRel(x, y, z));
}
public void setCurrentBlock(Vector current) {
this.current = current;
}
}