mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-17 02:04:04 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
@@ -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");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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] + ")";
|
||||
}
|
||||
|
||||
}
|
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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";
|
||||
}
|
||||
|
||||
}
|
@@ -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";
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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";
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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";
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user