Fix region intersection tests involving polygons.

Fixes WORLDGUARD-3216.
This commit is contained in:
sk89q 2015-01-19 22:56:16 -08:00
parent 47a8bcc442
commit bca1c2bdb3
4 changed files with 105 additions and 46 deletions

View File

@ -23,8 +23,10 @@
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@ -47,6 +49,11 @@ public GlobalProtectedRegion(String id) {
max = new BlockVector(0, 0, 0);
}
@Override
public boolean isPhysicalArea() {
return false;
}
@Override
public List<BlockVector2D> getPoints() {
// This doesn't make sense
@ -74,7 +81,12 @@ public RegionType getType() {
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
// Global regions are handled separately so it must not contain any positions
return new ArrayList<ProtectedRegion>();
return Collections.emptyList();
}
@Override
Area toArea() {
return null;
}
}

View File

@ -24,8 +24,9 @@
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.util.MathUtils;
import java.awt.*;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@ -83,6 +84,11 @@ public void setMaximumPoint(BlockVector position) {
setMinMaxPoints(min, position);
}
@Override
public boolean isPhysicalArea() {
return true;
}
@Override
public List<BlockVector2D> getPoints() {
List<BlockVector2D> pts = new ArrayList<BlockVector2D>();
@ -115,30 +121,21 @@ public RegionType getType() {
}
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
Area toArea() {
int x = getMinimumPoint().getBlockX();
int z = getMinimumPoint().getBlockZ();
int width = getMaximumPoint().getBlockX() - x;
int height = getMaximumPoint().getBlockZ() - z;
return new Area(new Rectangle(x, z, width, height));
}
List<ProtectedRegion> intersectingRegions = new ArrayList<ProtectedRegion>();
for (ProtectedRegion region : regions) {
if (!intersectsBoundingBox(region)) continue;
// If both regions are Cuboids and their bounding boxes intersect, they intersect
if (region instanceof ProtectedCuboidRegion) {
intersectingRegions.add(region);
} else if (region instanceof ProtectedPolygonalRegion) {
// If either region contains the points of the other,
// or if any edges intersect, the regions intersect
if (containsAny(region.getPoints()) || region.containsAny(getPoints()) || intersectsEdges(region)) {
intersectingRegions.add(region);
}
} else if (region instanceof GlobalProtectedRegion) {
// Never intersects
} else {
throw new IllegalArgumentException("Not supported yet.");
}
@Override
protected boolean intersects(ProtectedRegion region, Area thisArea) {
if (region instanceof ProtectedCuboidRegion) {
return intersectsBoundingBox(region);
} else {
return super.intersects(region, thisArea);
}
return intersectingRegions;
}
@Override

View File

@ -22,8 +22,10 @@
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import java.awt.*;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@ -37,7 +39,7 @@ public class ProtectedPolygonalRegion extends ProtectedRegion {
public ProtectedPolygonalRegion(String id, List<BlockVector2D> points, int minY, int maxY) {
super(id);
setMinMaxPoints(points, minY, maxY);
this.points = points;
this.points = Collections.unmodifiableList(points);
this.minY = min.getBlockY();
this.maxY = max.getBlockY();
}
@ -61,6 +63,11 @@ private void setMinMaxPoints(List<BlockVector2D> points2D, int minY, int maxY) {
setMinMaxPoints(points);
}
@Override
public boolean isPhysicalArea() {
return true;
}
@Override
public List<BlockVector2D> getPoints() {
return points;
@ -133,27 +140,21 @@ public RegionType getType() {
}
@Override
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions);
Area toArea() {
List<BlockVector2D> points = getPoints();
int numPoints = points.size();
int[] xCoords = new int[numPoints];
int[] yCoords = new int[numPoints];
List<ProtectedRegion> intersectingRegions = new ArrayList<ProtectedRegion>();
for (ProtectedRegion region : regions) {
if (!intersectsBoundingBox(region)) continue;
if (region instanceof ProtectedPolygonalRegion || region instanceof ProtectedCuboidRegion) {
// If either region contains the points of the other,
// or if any edges intersect, the regions intersect
if (containsAny(region.getPoints()) || region.containsAny(getPoints()) || intersectsEdges(region)) {
intersectingRegions.add(region);
}
} else if (region instanceof GlobalProtectedRegion) {
// Never intersects
} else {
throw new IllegalArgumentException("Not supported yet.");
}
int i = 0;
for (BlockVector2D point : points) {
xCoords[i] = point.getBlockX();
yCoords[i] = point.getBlockZ();
i++;
}
return intersectingRegions;
Polygon polygon = new Polygon(xCoords, yCoords, numPoints);
return new Area(polygon);
}
@Override

View File

@ -19,6 +19,7 @@
package com.sk89q.worldguard.protection.regions;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
@ -29,6 +30,7 @@
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.awt.geom.Area;
import java.awt.geom.Line2D;
import java.util.Collection;
import java.util.List;
@ -118,6 +120,13 @@ public String getId() {
return id;
}
/**
* Return whether this type of region encompasses physical area.
*
* @return Whether physical area is encompassed
*/
public abstract boolean isPhysicalArea();
/**
* Get a vector containing the smallest X, Y, and Z components for the
* corner of the axis-aligned bounding box that contains this region.
@ -570,7 +579,39 @@ public final String getTypeName() {
* @param regions a list of regions to source from
* @return the elements of {@code regions} that intersect with this region
*/
public abstract List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions);
public List<ProtectedRegion> getIntersectingRegions(Collection<ProtectedRegion> regions) {
checkNotNull(regions, "regions");
List<ProtectedRegion> intersecting = Lists.newArrayList();
Area thisArea = toArea();
for (ProtectedRegion region : regions) {
if (!region.isPhysicalArea()) continue;
if (intersects(region, thisArea)) {
intersecting.add(region);
}
}
return intersecting;
}
/**
* Test whether the given region intersects with this area.
*
* @param region the region to test
* @param thisArea an area object for this region
* @return true if the two regions intersect
*/
protected boolean intersects(ProtectedRegion region, Area thisArea) {
if (intersectsBoundingBox(region)) {
Area testArea = region.toArea();
testArea.intersect(thisArea);
return !testArea.isEmpty();
} else {
return false;
}
}
/**
* Checks if the bounding box of a region intersects with with the bounding
@ -631,6 +672,14 @@ protected boolean intersectsEdges(ProtectedRegion region) {
return false;
}
/**
* Return the AWT area, otherwise null if
* {@link #isPhysicalArea()} if false.
*
* @return The shape version
*/
abstract Area toArea();
@Override
public boolean isDirty() {
return dirty || owners.isDirty() || members.isDirty();