Refactor boundary checks into unified bounding box (#1126)
This commit is contained in:
parent
6927a0b48c
commit
d5c5e4983e
12
pom.xml
12
pom.xml
|
|
@ -127,18 +127,6 @@
|
|||
<version>5.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>3.4.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>3.4.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package me.ryanhamshire.GriefPrevention;
|
||||
|
||||
import me.ryanhamshire.GriefPrevention.util.BoundingBox;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.GameMode;
|
||||
|
|
@ -540,36 +541,10 @@ public class BlockEventHandler implements Listener
|
|||
return;
|
||||
}
|
||||
|
||||
// Initialize bounding box for moved blocks with first in list.
|
||||
int minX, maxX, minY, maxY, minZ, maxZ;
|
||||
Block movedBlock = blocks.get(0);
|
||||
minX = maxX = movedBlock.getX();
|
||||
minY = maxY = movedBlock.getY();
|
||||
minZ = maxZ = movedBlock.getZ();
|
||||
|
||||
// Fill in rest of bounding box with remaining blocks.
|
||||
for (int count = 1; count < blocks.size(); ++count)
|
||||
{
|
||||
movedBlock = blocks.get(count);
|
||||
minX = Math.min(minX, movedBlock.getX());
|
||||
minY = Math.min(minY, movedBlock.getY());
|
||||
minZ = Math.min(minZ, movedBlock.getZ());
|
||||
maxX = Math.max(maxX, movedBlock.getX());
|
||||
maxY = Math.max(maxY, movedBlock.getY());
|
||||
maxZ = Math.max(maxZ, movedBlock.getZ());
|
||||
}
|
||||
|
||||
// Add direction to include invaded zone.
|
||||
if (direction.getModX() > 0)
|
||||
maxX += direction.getModX();
|
||||
else
|
||||
minX += direction.getModX();
|
||||
if (direction.getModY() > 0)
|
||||
maxY += direction.getModY();
|
||||
if (direction.getModZ() > 0)
|
||||
maxZ += direction.getModZ();
|
||||
else
|
||||
minZ += direction.getModZ();
|
||||
// Create bounding box for moved blocks.
|
||||
BoundingBox movedBlocks = BoundingBox.ofBlocks(blocks);
|
||||
// Expand to include invaded zone.
|
||||
movedBlocks.resize(direction, 1);
|
||||
|
||||
/*
|
||||
* Claims-only mode. All moved blocks must be inside of the owning claim.
|
||||
|
|
@ -579,10 +554,7 @@ public class BlockEventHandler implements Listener
|
|||
*/
|
||||
if (pistonMode == PistonMode.CLAIMS_ONLY)
|
||||
{
|
||||
Location minLoc = pistonClaim.getLesserBoundaryCorner();
|
||||
Location maxLoc = pistonClaim.getGreaterBoundaryCorner();
|
||||
|
||||
if (minY < minLoc.getY() || minX < minLoc.getBlockX() || maxX > maxLoc.getBlockX() || minZ < minLoc.getBlockZ() || maxZ > maxLoc.getBlockZ())
|
||||
if (!new BoundingBox(pistonClaim).contains(movedBlocks))
|
||||
event.setCancelled(true);
|
||||
|
||||
return;
|
||||
|
|
@ -591,19 +563,26 @@ public class BlockEventHandler implements Listener
|
|||
// Ensure we have top level claim - piston ownership is only checked based on claim owner in everywhere mode.
|
||||
while (pistonClaim != null && pistonClaim.parent != null) pistonClaim = pistonClaim.parent;
|
||||
|
||||
// Pushing down or pulling up is safe if all blocks are in line with the piston.
|
||||
if (minX == maxX && minZ == maxZ && direction == (isRetract ? BlockFace.UP : BlockFace.DOWN)) return;
|
||||
// Check if blocks are in line vertically.
|
||||
if (movedBlocks.getLength() == 1 && movedBlocks.getWidth() == 1)
|
||||
{
|
||||
// Pulling up is always safe. The claim may not contain the area pulled from, but claims cannot stack.
|
||||
if (isRetract && direction == BlockFace.UP) return;
|
||||
|
||||
// Pushing down is always safe. The claim may not contain the area pushed into, but claims cannot stack.
|
||||
if (!isRetract && direction == BlockFace.DOWN) return;
|
||||
}
|
||||
|
||||
// Fast mode: Use the intersection of a cuboid containing all blocks instead of individual locations.
|
||||
if (pistonMode == PistonMode.EVERYWHERE_SIMPLE)
|
||||
{
|
||||
ArrayList<Claim> intersectable = new ArrayList<>();
|
||||
int chunkXMax = maxX >> 4;
|
||||
int chunkZMax = maxZ >> 4;
|
||||
int chunkXMax = movedBlocks.getMaxX() >> 4;
|
||||
int chunkZMax = movedBlocks.getMaxZ() >> 4;
|
||||
|
||||
for (int chunkX = minX >> 4; chunkX <= chunkXMax; ++chunkX)
|
||||
for (int chunkX = movedBlocks.getMinX() >> 4; chunkX <= chunkXMax; ++chunkX)
|
||||
{
|
||||
for (int chunkZ = minZ >> 4; chunkZ <= chunkZMax; ++chunkZ)
|
||||
for (int chunkZ = movedBlocks.getMinZ() >> 4; chunkZ <= chunkZMax; ++chunkZ)
|
||||
{
|
||||
ArrayList<Claim> chunkClaims = dataStore.chunksToClaimsMap.get(DataStore.getChunkHash(chunkX, chunkZ));
|
||||
if (chunkClaims == null) continue;
|
||||
|
|
@ -620,12 +599,8 @@ public class BlockEventHandler implements Listener
|
|||
{
|
||||
if (claim == pistonClaim) continue;
|
||||
|
||||
Location minLoc = claim.getLesserBoundaryCorner();
|
||||
Location maxLoc = claim.getGreaterBoundaryCorner();
|
||||
|
||||
// Ensure claim intersects with bounding box.
|
||||
if (maxY < minLoc.getBlockY() || minX > maxLoc.getBlockX() || maxX < minLoc.getBlockX() || minZ > maxLoc.getBlockZ() || maxZ < minLoc.getBlockZ())
|
||||
continue;
|
||||
if (!new BoundingBox(claim).intersects(movedBlocks)) continue;
|
||||
|
||||
// If owners are different, cancel.
|
||||
if (pistonClaim == null || !Objects.equals(pistonClaim.getOwnerID(), claim.getOwnerID()))
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package me.ryanhamshire.GriefPrevention;
|
||||
|
||||
import me.ryanhamshire.GriefPrevention.util.BoundingBox;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
|
|
@ -35,6 +36,7 @@ import java.util.EnumSet;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -726,20 +728,14 @@ public class Claim
|
|||
public boolean contains(Location location, boolean ignoreHeight, boolean excludeSubdivisions)
|
||||
{
|
||||
//not in the same world implies false
|
||||
if (!location.getWorld().equals(this.lesserBoundaryCorner.getWorld())) return false;
|
||||
if (!Objects.equals(location.getWorld(), this.lesserBoundaryCorner.getWorld())) return false;
|
||||
|
||||
double x = location.getX();
|
||||
double y = location.getY();
|
||||
double z = location.getZ();
|
||||
int x = (int) location.getX();
|
||||
int y = (int) (ignoreHeight ? getLesserBoundaryCorner().getY() : location.getY());
|
||||
int z = (int) location.getZ();
|
||||
|
||||
//main check
|
||||
boolean inClaim = (ignoreHeight || y >= this.lesserBoundaryCorner.getY()) &&
|
||||
x >= this.lesserBoundaryCorner.getX() &&
|
||||
x < this.greaterBoundaryCorner.getX() + 1 &&
|
||||
z >= this.lesserBoundaryCorner.getZ() &&
|
||||
z < this.greaterBoundaryCorner.getZ() + 1;
|
||||
|
||||
if (!inClaim) return false;
|
||||
if (!new BoundingBox(this).contains(x, y, z)) return false;
|
||||
|
||||
//additional check for subdivisions
|
||||
//you're only in a subdivision when you're also in its parent claim
|
||||
|
|
@ -772,15 +768,9 @@ public class Claim
|
|||
//used internally to prevent overlaps when creating claims
|
||||
boolean overlaps(Claim otherClaim)
|
||||
{
|
||||
// For help visualizing test cases, try https://silentmatt.com/rectangle-intersection/
|
||||
|
||||
if (!this.lesserBoundaryCorner.getWorld().equals(otherClaim.getLesserBoundaryCorner().getWorld())) return false;
|
||||
|
||||
return !(this.getGreaterBoundaryCorner().getX() < otherClaim.getLesserBoundaryCorner().getX() ||
|
||||
this.getLesserBoundaryCorner().getX() > otherClaim.getGreaterBoundaryCorner().getX() ||
|
||||
this.getGreaterBoundaryCorner().getZ() < otherClaim.getLesserBoundaryCorner().getZ() ||
|
||||
this.getLesserBoundaryCorner().getZ() > otherClaim.getGreaterBoundaryCorner().getZ());
|
||||
if (!Objects.equals(this.lesserBoundaryCorner.getWorld(), otherClaim.getLesserBoundaryCorner().getWorld())) return false;
|
||||
|
||||
return new BoundingBox(this).intersects(new BoundingBox(otherClaim));
|
||||
}
|
||||
|
||||
//whether more entities may be added to a claim
|
||||
|
|
|
|||
|
|
@ -0,0 +1,732 @@
|
|||
package me.ryanhamshire.GriefPrevention.util;
|
||||
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A mutable block-based axis-aligned bounding box.
|
||||
*
|
||||
* <p>This is a rectangular box defined by minimum and maximum corners
|
||||
* that can be used to represent a collection of blocks.
|
||||
*
|
||||
* <p>While similar to Bukkit's {@link org.bukkit.util.BoundingBox BoundingBox},
|
||||
* this implementation is much more focused on performance and does not use as
|
||||
* many input sanitization operations.
|
||||
*
|
||||
* @author Jikoo
|
||||
*/
|
||||
public class BoundingBox implements Cloneable
|
||||
{
|
||||
|
||||
/**
|
||||
* Construct a new bounding box containing all of the given blocks.
|
||||
*
|
||||
* @param blocks a collection of blocks to construct a bounding box around
|
||||
* @return the bounding box
|
||||
*/
|
||||
public static BoundingBox ofBlocks(Collection<Block> blocks)
|
||||
{
|
||||
if (blocks.size() == 0) throw new IllegalArgumentException("Cannot create bounding box with no blocks!");
|
||||
|
||||
Iterator<Block> iterator = blocks.iterator();
|
||||
// Initialize bounding box with first block
|
||||
BoundingBox box = new BoundingBox(iterator.next());
|
||||
|
||||
// Fill in rest of bounding box with remaining blocks.
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Block block = iterator.next();
|
||||
box.union(block.getX(), block.getY(), block.getZ());
|
||||
}
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
private int minX;
|
||||
private int minY;
|
||||
private int minZ;
|
||||
private int maxX;
|
||||
private int maxY;
|
||||
private int maxZ;
|
||||
|
||||
/**
|
||||
* Construct a new bounding box with the given corners.
|
||||
*
|
||||
* @param x1 the X coordinate of the first corner
|
||||
* @param y1 the Y coordinate of the first corner
|
||||
* @param z1 the Z coordinate of the first corner
|
||||
* @param x2 the X coordinate of the second corner
|
||||
* @param y2 the Y coordinate of the second corner
|
||||
* @param z2 the Z coordinate of the second corner
|
||||
* @param verify whether or not to verify that the provided corners are in fact the minimum corners
|
||||
*/
|
||||
protected BoundingBox(int x1, int y1, int z1, int x2, int y2, int z2, boolean verify) {
|
||||
if (verify)
|
||||
{
|
||||
verify(x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.minX = x1;
|
||||
this.maxX = x2;
|
||||
this.minY = y1;
|
||||
this.maxY = y2;
|
||||
this.minZ = z1;
|
||||
this.maxZ = z2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box with the given corners.
|
||||
*
|
||||
* @param x1 the X coordinate of the first corner
|
||||
* @param y1 the Y coordinate of the first corner
|
||||
* @param z1 the Z coordinate of the first corner
|
||||
* @param x2 the X coordinate of the second corner
|
||||
* @param y2 the Y coordinate of the second corner
|
||||
* @param z2 the Z coordinate of the second corner
|
||||
*/
|
||||
public BoundingBox(int x1, int y1, int z1, int x2, int y2, int z2)
|
||||
{
|
||||
this(x1, y1, z1, x2, y2, z2, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box with the given corners.
|
||||
*
|
||||
* @param pos1 the position of the first corner
|
||||
* @param pos2 the position of the second corner
|
||||
* @param verify whether or not to verify that the provided corners are in fact the minimum corners
|
||||
*/
|
||||
private BoundingBox(Location pos1, Location pos2, boolean verify)
|
||||
{
|
||||
this(pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ(),
|
||||
pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ(),
|
||||
verify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box with the given corners.
|
||||
*
|
||||
* @param pos1 the position of the first corner
|
||||
* @param pos2 the position of the second corner
|
||||
*/
|
||||
public BoundingBox(Location pos1, Location pos2)
|
||||
{
|
||||
this(pos1, pos2, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box with the given corners.
|
||||
*
|
||||
* @param pos1 the position of the first corner
|
||||
* @param pos2 the position of the second corner
|
||||
*/
|
||||
public BoundingBox(Vector pos1, Vector pos2)
|
||||
{
|
||||
this(pos1.getBlockX(), pos1.getBlockY(), pos1.getBlockZ(),
|
||||
pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box representing the given claim.
|
||||
*
|
||||
* @param claim the claim
|
||||
*/
|
||||
public BoundingBox(Claim claim)
|
||||
{
|
||||
this(claim.getLesserBoundaryCorner(), claim.getGreaterBoundaryCorner(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box representing the given block.
|
||||
*
|
||||
* @param block the block
|
||||
*/
|
||||
public BoundingBox(Block block)
|
||||
{
|
||||
this(block.getX(), block.getY(), block.getZ(), block.getX(), block.getY(), block.getZ(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box representing the given Bukkit {@link org.bukkit.util.BoundingBox BoundingBox}.
|
||||
*
|
||||
* @param boundingBox the Bukkit bounding box
|
||||
*/
|
||||
public BoundingBox(org.bukkit.util.BoundingBox boundingBox)
|
||||
{
|
||||
this((int) boundingBox.getMinX(),
|
||||
(int) boundingBox.getMinY(),
|
||||
(int) boundingBox.getMinZ(),
|
||||
// Since Bukkit bounding boxes are inclusive of upper bounds, subtract a small number.
|
||||
// This ensures that a full block Bukkit bounding boxes yield correct equivalents.
|
||||
// Uses Math.max to account for degenerate boxes.
|
||||
(int) Math.max(boundingBox.getMinX(), boundingBox.getMaxX() - .0001),
|
||||
(int) Math.max(boundingBox.getMinY(), boundingBox.getMaxY() - .0001),
|
||||
(int) Math.max(boundingBox.getMinZ(), boundingBox.getMaxZ() - .0001),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets bounds of this bounding box to the specified values.
|
||||
* Ensures that the minimum and maximum corners are set from the correct respective values.
|
||||
*
|
||||
* @param x1 the first X value
|
||||
* @param y1 the first Y value
|
||||
* @param z1 the first Z value
|
||||
* @param x2 the second X value
|
||||
* @param y2 the second Y value
|
||||
* @param z2 the second Z value
|
||||
*/
|
||||
private void verify(int x1, int y1, int z1, int x2, int y2, int z2) {
|
||||
if (x1 < x2)
|
||||
{
|
||||
this.minX = x1;
|
||||
this.maxX = x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.minX = x2;
|
||||
this.maxX = x1;
|
||||
}
|
||||
if (y1 < y2)
|
||||
{
|
||||
this.minY = y1;
|
||||
this.maxY = y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.minY = y2;
|
||||
this.maxY = y1;
|
||||
}
|
||||
if (z1 < z2)
|
||||
{
|
||||
this.minZ = z1;
|
||||
this.maxZ = z2;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.minZ = z2;
|
||||
this.maxZ = z1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum X coordinate of the bounding box.
|
||||
*
|
||||
* @return the minimum X value
|
||||
*/
|
||||
public int getMinX()
|
||||
{
|
||||
return this.minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum Y coordinate of the bounding box.
|
||||
*
|
||||
* @return the minimum Y value
|
||||
*/
|
||||
public int getMinY()
|
||||
{
|
||||
return this.minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum Y coordinate of the bounding box.
|
||||
*
|
||||
* @return the minimum Y value
|
||||
*/
|
||||
public int getMinZ()
|
||||
{
|
||||
return this.minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum corner's coordinates as a vector.
|
||||
*
|
||||
* @return the minimum corner as a vector
|
||||
*/
|
||||
public Vector getMin()
|
||||
{
|
||||
return new Vector(this.minX, this.minY, this.minZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum X coordinate of the bounding box.
|
||||
*
|
||||
* @return the maximum X value
|
||||
*/
|
||||
public int getMaxX()
|
||||
{
|
||||
return this.maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum Y coordinate of the bounding box.
|
||||
*
|
||||
* @return the maximum Y value
|
||||
*/
|
||||
public int getMaxY()
|
||||
{
|
||||
return this.maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum Z coordinate of the bounding box.
|
||||
*
|
||||
* @return the maximum Z value
|
||||
*/
|
||||
public int getMaxZ()
|
||||
{
|
||||
return this.maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum corner's coordinates as a vector.
|
||||
*
|
||||
* @return the maximum corner as a vector
|
||||
*/
|
||||
public Vector getMax()
|
||||
{
|
||||
return new Vector(this.maxX, this.maxY, this.maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the bounding box on the X axis.
|
||||
*
|
||||
* @return the length on the X axis
|
||||
*/
|
||||
public int getLength()
|
||||
{
|
||||
return (this.maxX - this.minX) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the bounding box on the Y axis.
|
||||
*
|
||||
* @return the length on the Y axis
|
||||
*/
|
||||
public int getHeight()
|
||||
{
|
||||
return (this.maxY - this.minY) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the length of the bounding box on the Z axis.
|
||||
*
|
||||
* @return the length on the Z axis
|
||||
*/
|
||||
public int getWidth()
|
||||
{
|
||||
return (this.maxZ - this.minZ) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the center of the bounding box on the X axis.
|
||||
*
|
||||
* <p>Note that center coordinates are world coordinates
|
||||
* while all of the other coordinates are block coordinates.
|
||||
*
|
||||
* @return the center of the X axis
|
||||
*/
|
||||
public double getCenterX()
|
||||
{
|
||||
return this.minX + (this.getLength() / 2D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the center of the bounding box on the Y axis.
|
||||
*
|
||||
* <p>Note that center coordinates are world coordinates
|
||||
* while all of the other coordinates are block coordinates.
|
||||
*
|
||||
* @return the center of the X axis
|
||||
*/
|
||||
public double getCenterY()
|
||||
{
|
||||
return this.minY + (this.getHeight() / 2D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the center of the bounding box on the Z axis.
|
||||
*
|
||||
* <p>Note that center coordinates are world coordinates
|
||||
* while all of the other coordinates are block coordinates.
|
||||
*
|
||||
* @return the center of the X axis
|
||||
*/
|
||||
public double getCenterZ()
|
||||
{
|
||||
return this.minZ + (this.getWidth() / 2D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the center of the bounding box as a vector.
|
||||
*
|
||||
* <p>Note that center coordinates are world coordinates
|
||||
* while all of the other coordinates are block coordinates.
|
||||
*
|
||||
* @return the center of the X axis
|
||||
*/
|
||||
public Vector getCenter()
|
||||
{
|
||||
return new Vector(this.getCenterX(), this.getCenterY(), this.getCenterZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the area of the base of the bounding box.
|
||||
*
|
||||
* <p>The base is the lowest plane defined by the X and Z axis.
|
||||
*
|
||||
* @return the area of the base of the bounding box
|
||||
*/
|
||||
public int getArea()
|
||||
{
|
||||
return this.getLength() * this.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the volume of the bounding box.
|
||||
*
|
||||
* @return the volume of the bounding box
|
||||
*/
|
||||
public int getVolume()
|
||||
{
|
||||
return this.getArea() * getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the dimensions and location of another bounding box.
|
||||
*
|
||||
* @param other the bounding box to copy
|
||||
*/
|
||||
public void copy(BoundingBox other)
|
||||
{
|
||||
this.minX = other.minX;
|
||||
this.minY = other.minY;
|
||||
this.minZ = other.minZ;
|
||||
this.maxX = other.maxX;
|
||||
this.maxY = other.maxY;
|
||||
this.maxZ = other.maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the size the bounding box in the direction specified by the Minecraft blockface.
|
||||
*
|
||||
* <p>If the specified directional magnitude is negative, the box is contracted instead.
|
||||
*
|
||||
* <p>When contracting, the box does not care if the contraction would cause a negative side length.
|
||||
* In these cases, the lowest point is redefined by the new location of the maximum corner instead.
|
||||
*
|
||||
* @param direction the direction to change size in
|
||||
* @param magnitude the magnitude of the resizing
|
||||
*/
|
||||
public void resize(BlockFace direction, int magnitude)
|
||||
{
|
||||
if (magnitude == 0 || direction == BlockFace.SELF) return;
|
||||
|
||||
Vector vector = direction.getDirection().multiply(magnitude);
|
||||
|
||||
// Force normalized rounding - prevents issues with non-cardinal directions.
|
||||
int modX = NumberConversions.round(vector.getX());
|
||||
int modY = NumberConversions.round(vector.getY());
|
||||
int modZ = NumberConversions.round(vector.getZ());
|
||||
|
||||
if (modX == 0 && modY == 0 && modZ == 0) return;
|
||||
|
||||
// Modify correct point.
|
||||
if (direction.getModX() > 0)
|
||||
this.maxX += modX;
|
||||
else
|
||||
this.minX += modX;
|
||||
if (direction.getModY() > 0)
|
||||
this.maxY += modY;
|
||||
else
|
||||
this.minY += modY;
|
||||
if (direction.getModZ() > 0)
|
||||
this.maxZ += modZ;
|
||||
else
|
||||
this.minZ += modZ;
|
||||
|
||||
// If box is contracting, re-verify points in case corners have swapped.
|
||||
if (magnitude < 0)
|
||||
verify(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the bounding box in the direction specified by the Minecraft BlockFace and magnitude.
|
||||
*
|
||||
* <p>Note that a negative direction will move in the opposite direction
|
||||
* to the extent that the following example returns true:
|
||||
* <pre>
|
||||
* public boolean testBoxMove(BoundingBox box, BlockFace face, int magnitude)
|
||||
* {
|
||||
* BoundingBox box2 = box.clone();
|
||||
* box.move(face, magnitude);
|
||||
* box2.move(face.getOpposite(), -magnitude);
|
||||
* return box.equals(box2);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param direction the direction to move in
|
||||
* @param magnitude the magnitude of the move
|
||||
*/
|
||||
public void move(BlockFace direction, int magnitude)
|
||||
{
|
||||
if (magnitude == 0 || direction == BlockFace.SELF) return;
|
||||
|
||||
Vector vector = direction.getDirection().multiply(magnitude);
|
||||
|
||||
int blockX = NumberConversions.round(vector.getX());
|
||||
this.minX += blockX;
|
||||
this.maxX += blockX;
|
||||
int blockY = NumberConversions.round(vector.getY());
|
||||
this.minY += blockY;
|
||||
this.maxY += blockY;
|
||||
int blockZ = NumberConversions.round(vector.getZ());
|
||||
this.minZ += blockZ;
|
||||
this.maxZ += blockZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bounding box to contain the position specified.
|
||||
*
|
||||
* @param x the X coordinate to include
|
||||
* @param y the Y coordinate to include
|
||||
* @param z the Z coordinate to include
|
||||
*/
|
||||
public void union(int x, int y, int z)
|
||||
{
|
||||
this.minX = Math.min(x, this.minX);
|
||||
this.maxX = Math.max(x, this.maxX);
|
||||
this.minY = Math.min(y, this.minY);
|
||||
this.maxY = Math.max(y, this.maxY);
|
||||
this.minZ = Math.min(z, this.minZ);
|
||||
this.maxZ = Math.max(z, this.maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bounding box to contain the position specified.
|
||||
*
|
||||
* @param position the position to include
|
||||
*/
|
||||
public void union(Block position)
|
||||
{
|
||||
this.union(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bounding box to contain the position specified.
|
||||
*
|
||||
* @param position the position to include
|
||||
*/
|
||||
public void union(Vector position)
|
||||
{
|
||||
this.union(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bounding box to contain the position specified.
|
||||
*
|
||||
* @param position the position to include
|
||||
*/
|
||||
public void union(Location position)
|
||||
{
|
||||
this.union(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the bounding box to contain the bounding box specified.
|
||||
*
|
||||
* @param other the bounding box to include
|
||||
*/
|
||||
public void union(BoundingBox other)
|
||||
{
|
||||
this.minX = Math.min(this.minX, other.minX);
|
||||
this.maxX = Math.max(this.maxX, other.maxX);
|
||||
this.minY = Math.min(this.minY, other.minY);
|
||||
this.maxY = Math.max(this.maxY, other.maxY);
|
||||
this.minZ = Math.min(this.minZ, other.minZ);
|
||||
this.maxZ = Math.max(this.maxZ, other.maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal containment check.
|
||||
*
|
||||
* @param minX the minimum X value to check for containment
|
||||
* @param minY the minimum Y value to check for containment
|
||||
* @param minZ the minimum Z value to check for containment
|
||||
* @param maxX the maximum X value to check for containment
|
||||
* @param maxY the maximum X value to check for containment
|
||||
* @param maxZ the maximum X value to check for containment
|
||||
* @return true if the specified values are inside the bounding box
|
||||
*/
|
||||
private boolean containsInternal(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
|
||||
{
|
||||
return minX >= this.minX && maxX <= this.maxX
|
||||
&& minY >= this.minY && maxY <= this.maxY
|
||||
&& minZ >= this.minZ && maxZ <= this.maxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains the position specified.
|
||||
*
|
||||
* @param x the X coordinate of the position
|
||||
* @param y the Y coordinate of the position
|
||||
* @param z the Z coordinate of the position
|
||||
* @return true if the specified position is inside the bounding box
|
||||
*/
|
||||
public boolean contains(int x, int y, int z)
|
||||
{
|
||||
return containsInternal(x, y, z, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains the position specified.
|
||||
*
|
||||
* @param position the position
|
||||
* @return true if the specified position is inside the bounding box
|
||||
*/
|
||||
public boolean contains(Vector position)
|
||||
{
|
||||
return contains(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains the position specified.
|
||||
*
|
||||
* @param position the position
|
||||
* @return true if the specified position is inside the bounding box
|
||||
*/
|
||||
public boolean contains(Location position)
|
||||
{
|
||||
return contains(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains the position specified.
|
||||
*
|
||||
* @param position the position
|
||||
* @return true if the specified position is inside the bounding box
|
||||
*/
|
||||
public boolean contains(Block position)
|
||||
{
|
||||
return contains(position.getX(), position.getY(), position.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains another bounding box consisting of the positions specified.
|
||||
*
|
||||
* @param x1 the X coordinate of the first position
|
||||
* @param y1 the Y coordinate of the first position
|
||||
* @param z1 the Z coordinate of the first position
|
||||
* @param x2 the X coordinate of the second position
|
||||
* @param y2 the Y coordinate of the second position
|
||||
* @param z2 the Z coordinate of the second position
|
||||
* @return true if the specified positions are inside the bounding box
|
||||
*/
|
||||
public boolean contains(int x1, int y1, int z1, int x2, int y2, int z2)
|
||||
{
|
||||
return contains(new BoundingBox(x1, y1, z1, x2, y2, z2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box contains another bounding box.
|
||||
*
|
||||
* @param other the other bounding box
|
||||
* @return true if the specified positions are inside the bounding box
|
||||
*/
|
||||
public boolean contains(BoundingBox other)
|
||||
{
|
||||
return containsInternal(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the bounding box intersects another bounding box.
|
||||
*
|
||||
* @param other the other bounding box
|
||||
* @return true if the specified positions are inside the bounding box
|
||||
*/
|
||||
public boolean intersects(BoundingBox other)
|
||||
{
|
||||
// For help visualizing test cases, try https://silentmatt.com/rectangle-intersection/
|
||||
return this.minX <= other.maxX && this.maxX >= other.minX
|
||||
&& this.minY <= other.maxY && this.maxY >= other.minY
|
||||
&& this.minZ <= other.maxZ && this.maxZ >= other.minZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a bounding box containing the intersection of the bounding box with another.
|
||||
*
|
||||
* @param other the other bounding box
|
||||
* @return the bounding box representing overlapping area or null if the boxes do not overlap.
|
||||
*/
|
||||
public BoundingBox intersection(BoundingBox other)
|
||||
{
|
||||
if (!intersects(other)) return null;
|
||||
|
||||
return new BoundingBox(
|
||||
Math.max(this.minX, other.minX),
|
||||
Math.max(this.minY, other.minY),
|
||||
Math.max(this.minZ, other.minZ),
|
||||
Math.min(this.maxX, other.maxX),
|
||||
Math.min(this.maxY, other.maxY),
|
||||
Math.min(this.maxZ, other.maxZ),
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BoundingBox other = (BoundingBox) o;
|
||||
return this.minX == other.minX
|
||||
&& this.minY == other.minY
|
||||
&& this.minZ == other.minZ
|
||||
&& this.maxX == other.maxX
|
||||
&& this.maxY == other.maxY
|
||||
&& this.maxZ == other.maxZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "BoundingBox{" +
|
||||
"minX=" + minX +
|
||||
", minY=" + minY +
|
||||
", minZ=" + minZ +
|
||||
", maxX=" + maxX +
|
||||
", maxY=" + maxY +
|
||||
", maxZ=" + maxZ +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox clone()
|
||||
{
|
||||
try
|
||||
{
|
||||
return (BoundingBox) super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
package me.ryanhamshire.GriefPrevention;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ClaimTest {
|
||||
|
||||
@Test
|
||||
public void testClaimOverlap()
|
||||
{
|
||||
World world = Mockito.mock(World.class);
|
||||
|
||||
// One corner inside
|
||||
Claim claimA = new Claim(new Location(world, 0, 0, 0), new Location(world, 10, 0, 10), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
Claim claimB = new Claim(new Location(world, 5, 0, 5), new Location(world, 15, 0, 15), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
Claim claimC = new Claim(new Location(world, -5, 0, -5), new Location(world, 4, 0, 4), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
|
||||
assertTrue(claimA.overlaps(claimB));
|
||||
assertTrue(claimB.overlaps(claimA));
|
||||
assertTrue(claimA.overlaps(claimC));
|
||||
assertTrue(claimC.overlaps(claimA));
|
||||
assertFalse(claimB.overlaps(claimC));
|
||||
assertFalse(claimC.overlaps(claimB));
|
||||
|
||||
// Complete containment
|
||||
claimA = new Claim(new Location(world, 0, 0, 0), new Location(world, 20, 0, 20), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
claimB = new Claim(new Location(world, 5, 0, 5), new Location(world, 15, 0, 15), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
|
||||
assertTrue(claimA.overlaps(claimB));
|
||||
assertTrue(claimB.overlaps(claimA));
|
||||
|
||||
// Central intersection
|
||||
claimA = new Claim(new Location(world, 0, 0, 5), new Location(world, 10, 0, 15), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
claimB = new Claim(new Location(world, 5, 0, 0), new Location(world, 15, 0, 10), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
|
||||
assertTrue(claimA.overlaps(claimB));
|
||||
assertTrue(claimB.overlaps(claimA));
|
||||
|
||||
// Linear North-South
|
||||
claimA = new Claim(new Location(world, 0, 0, 0), new Location(world, 10, 0, 10), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
claimB = new Claim(new Location(world, 0, 0, 15), new Location(world, 15, 0, 25), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
|
||||
assertFalse(claimA.overlaps(claimB));
|
||||
assertFalse(claimB.overlaps(claimA));
|
||||
|
||||
// Linear East-West
|
||||
claimA = new Claim(new Location(world, 0, 0, 0), new Location(world, 10, 0, 10), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
claimB = new Claim(new Location(world, 15, 0, 0), new Location(world, 25, 0, 15), null,
|
||||
Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false, 0L);
|
||||
|
||||
assertFalse(claimA.overlaps(claimB));
|
||||
assertFalse(claimB.overlaps(claimA));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package me.ryanhamshire.GriefPrevention.util;
|
||||
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class BoundingBoxTest
|
||||
{
|
||||
@Test
|
||||
public void testVerify()
|
||||
{
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 10, 10);
|
||||
BoundingBox boxB = new BoundingBox(10, 0, 10, 0, 10, 0);
|
||||
assertEquals(boxA, boxB);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMeasurements()
|
||||
{
|
||||
BoundingBox boxA = new BoundingBox(-1, 0, 1, 5, 4, 3);
|
||||
assertEquals(7, boxA.getLength());
|
||||
assertEquals(5, boxA.getHeight());
|
||||
assertEquals(3, boxA.getWidth());
|
||||
assertEquals(7 * 3, boxA.getArea());
|
||||
assertEquals(7 * 3 * 5, boxA.getVolume());
|
||||
assertEquals(2.5, boxA.getCenterX());
|
||||
assertEquals(2.5, boxA.getCenterY());
|
||||
assertEquals(2.5, boxA.getCenterZ());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopy()
|
||||
{
|
||||
BoundingBox boxA = new BoundingBox(1, 2, 3, 4, 5, 6);
|
||||
BoundingBox boxB = new BoundingBox(7, 8, 9, 10, 11, 12);
|
||||
boxB.copy(boxA);
|
||||
assertEquals(boxA.getMinX(), boxB.getMinX());
|
||||
assertEquals(boxA.getMinY(), boxB.getMinY());
|
||||
assertEquals(boxA.getMinZ(), boxB.getMinZ());
|
||||
assertEquals(boxA.getMaxX(), boxB.getMaxX());
|
||||
assertEquals(boxA.getMaxY(), boxB.getMaxY());
|
||||
assertEquals(boxA.getMaxZ(), boxB.getMaxZ());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResize()
|
||||
{
|
||||
testBlockfaceFunction(BoundingBox::resize,
|
||||
new BoundingBox(0, 0, -10, 10, 10, 10));
|
||||
}
|
||||
|
||||
private void testBlockfaceFunction(TriConsumer<BoundingBox, BlockFace, Integer> function, BoundingBox boxB)
|
||||
{
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 10, 10);
|
||||
function.apply(boxA, BlockFace.NORTH, 10);
|
||||
assertEquals(boxB, boxA);
|
||||
|
||||
for (BlockFace face : BlockFace.values())
|
||||
{
|
||||
if (face == BlockFace.SELF)
|
||||
{
|
||||
function.apply(boxA, face, 15);
|
||||
assertEquals(boxB, boxA);
|
||||
continue;
|
||||
}
|
||||
function.apply(boxA, face, 15);
|
||||
assertNotEquals(boxB, boxA);
|
||||
function.apply(boxA, face, -15);
|
||||
assertEquals(boxB, boxA);
|
||||
}
|
||||
}
|
||||
|
||||
private interface TriConsumer<T, U, V> {
|
||||
void apply(T t, U u, V v);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMove()
|
||||
{
|
||||
testBlockfaceFunction(BoundingBox::move,
|
||||
new BoundingBox(0, 0, -10, 10, 10, 0));
|
||||
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 10, 10);
|
||||
BoundingBox boxB = boxA.clone();
|
||||
boxA.move(BlockFace.EAST, 15);
|
||||
assertNotEquals(boxB, boxA);
|
||||
BoundingBox boxC = boxA.clone();
|
||||
boxA.move(BlockFace.EAST, -15);
|
||||
assertEquals(boxB, boxA);
|
||||
boxC.move(BlockFace.EAST.getOppositeFace(), 15);
|
||||
assertEquals(boxB, boxC);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnion()
|
||||
{
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 10, 10);
|
||||
BoundingBox boxB = new BoundingBox(0, 0, 0, 10, 15, 20);
|
||||
BoundingBox boxC = new BoundingBox(-10, 0, 0, 10, 15, 20);
|
||||
boxA.union(0, 15, 20);
|
||||
|
||||
assertEquals(boxB, boxA);
|
||||
boxA.union(-10, 7, 10);
|
||||
assertEquals(boxC, boxA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectCorner()
|
||||
{
|
||||
// One corner inside
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 0, 10);
|
||||
BoundingBox boxB = new BoundingBox(5, 0, 5, 15, 0, 15);
|
||||
BoundingBox boxC = new BoundingBox(-5, 0, -5, 4, 0, 4);
|
||||
|
||||
assertTrue(boxA.intersects(boxB));
|
||||
assertTrue(boxB.intersects(boxA));
|
||||
assertTrue(boxA.intersects(boxC));
|
||||
assertTrue(boxC.intersects(boxA));
|
||||
assertFalse(boxB.intersects(boxC));
|
||||
assertFalse(boxC.intersects(boxB));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectCenter()
|
||||
{
|
||||
// Central intersection
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 5, 10, 0, 15);
|
||||
BoundingBox boxB = new BoundingBox(5, 0, 0, 15, 0, 10);
|
||||
|
||||
assertTrue(boxA.intersects(boxB));
|
||||
assertTrue(boxB.intersects(boxA));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectLinearAdjacent()
|
||||
{
|
||||
// Linear North-South
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 10, 0, 10);
|
||||
BoundingBox boxB = new BoundingBox(0, 0, 11, 10, 0, 21);
|
||||
BoundingBox boxC = new BoundingBox(0, 0, 10, 10, 0, 20);
|
||||
|
||||
// Adjacent
|
||||
assertFalse(boxA.intersects(boxB));
|
||||
assertFalse(boxB.intersects(boxA));
|
||||
// Overlapping on edge
|
||||
assertTrue(boxA.intersects(boxC));
|
||||
assertTrue(boxC.intersects(boxA));
|
||||
|
||||
// Linear East-West
|
||||
boxA = new BoundingBox(0, 0, 0, 10, 0, 10);
|
||||
boxB = new BoundingBox(11, 0, 0, 21, 0, 10);
|
||||
boxC = new BoundingBox(10, 0, 0, 20, 0, 10);
|
||||
|
||||
// Adjacent
|
||||
assertFalse(boxA.intersects(boxB));
|
||||
assertFalse(boxB.intersects(boxA));
|
||||
// Overlapping on edge
|
||||
assertTrue(boxA.intersects(boxC));
|
||||
assertTrue(boxC.intersects(boxA));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainment()
|
||||
{
|
||||
// Complete containment
|
||||
BoundingBox boxA = new BoundingBox(0, 0, 0, 20, 0, 20);
|
||||
BoundingBox boxB = new BoundingBox(5, 0, 5, 15, 0, 15);
|
||||
BoundingBox boxC = new BoundingBox(-5, 0, -5, 4, 0, 4);
|
||||
BoundingBox boxD = boxA.clone();
|
||||
|
||||
assertTrue(boxA.contains(boxB));
|
||||
assertTrue(boxB.intersects(boxA));
|
||||
assertFalse(boxB.contains(boxA));
|
||||
assertFalse(boxA.contains(boxC));
|
||||
assertTrue(boxA.contains(boxD));
|
||||
assertTrue(boxD.contains(boxA));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user