415 lines
12 KiB
Java
415 lines
12 KiB
Java
![]() |
package game.world;
|
||
|
|
||
|
import game.world.HitPosition.ObjectType;
|
||
|
|
||
|
public class BoundingBox
|
||
|
{
|
||
|
public final double minX;
|
||
|
public final double minY;
|
||
|
public final double minZ;
|
||
|
public final double maxX;
|
||
|
public final double maxY;
|
||
|
public final double maxZ;
|
||
|
|
||
|
public BoundingBox(double x1, double y1, double z1, double x2, double y2, double z2)
|
||
|
{
|
||
|
this.minX = Math.min(x1, x2);
|
||
|
this.minY = Math.min(y1, y2);
|
||
|
this.minZ = Math.min(z1, z2);
|
||
|
this.maxX = Math.max(x1, x2);
|
||
|
this.maxY = Math.max(y1, y2);
|
||
|
this.maxZ = Math.max(z1, z2);
|
||
|
}
|
||
|
|
||
|
public BoundingBox(BlockPos pos1, BlockPos pos2)
|
||
|
{
|
||
|
this.minX = (double)pos1.getX();
|
||
|
this.minY = (double)pos1.getY();
|
||
|
this.minZ = (double)pos1.getZ();
|
||
|
this.maxX = (double)pos2.getX();
|
||
|
this.maxY = (double)pos2.getY();
|
||
|
this.maxZ = (double)pos2.getZ();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds the coordinates to the bounding box extending it if the point lies outside the current ranges. Args: x, y, z
|
||
|
*/
|
||
|
public BoundingBox addCoord(double x, double y, double z)
|
||
|
{
|
||
|
double d0 = this.minX;
|
||
|
double d1 = this.minY;
|
||
|
double d2 = this.minZ;
|
||
|
double d3 = this.maxX;
|
||
|
double d4 = this.maxY;
|
||
|
double d5 = this.maxZ;
|
||
|
|
||
|
if (x < 0.0D)
|
||
|
{
|
||
|
d0 += x;
|
||
|
}
|
||
|
else if (x > 0.0D)
|
||
|
{
|
||
|
d3 += x;
|
||
|
}
|
||
|
|
||
|
if (y < 0.0D)
|
||
|
{
|
||
|
d1 += y;
|
||
|
}
|
||
|
else if (y > 0.0D)
|
||
|
{
|
||
|
d4 += y;
|
||
|
}
|
||
|
|
||
|
if (z < 0.0D)
|
||
|
{
|
||
|
d2 += z;
|
||
|
}
|
||
|
else if (z > 0.0D)
|
||
|
{
|
||
|
d5 += z;
|
||
|
}
|
||
|
|
||
|
return new BoundingBox(d0, d1, d2, d3, d4, d5);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a bounding box expanded by the specified vector (if negative numbers are given it will shrink). Args: x,
|
||
|
* y, z
|
||
|
*/
|
||
|
public BoundingBox expand(double x, double y, double z)
|
||
|
{
|
||
|
double d0 = this.minX - x;
|
||
|
double d1 = this.minY - y;
|
||
|
double d2 = this.minZ - z;
|
||
|
double d3 = this.maxX + x;
|
||
|
double d4 = this.maxY + y;
|
||
|
double d5 = this.maxZ + z;
|
||
|
return new BoundingBox(d0, d1, d2, d3, d4, d5);
|
||
|
}
|
||
|
|
||
|
public BoundingBox union(BoundingBox other)
|
||
|
{
|
||
|
double d0 = Math.min(this.minX, other.minX);
|
||
|
double d1 = Math.min(this.minY, other.minY);
|
||
|
double d2 = Math.min(this.minZ, other.minZ);
|
||
|
double d3 = Math.max(this.maxX, other.maxX);
|
||
|
double d4 = Math.max(this.maxY, other.maxY);
|
||
|
double d5 = Math.max(this.maxZ, other.maxZ);
|
||
|
return new BoundingBox(d0, d1, d2, d3, d4, d5);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* returns an AABB with corners x1, y1, z1 and x2, y2, z2
|
||
|
*/
|
||
|
public static BoundingBox fromBounds(double x1, double y1, double z1, double x2, double y2, double z2)
|
||
|
{
|
||
|
double d0 = Math.min(x1, x2);
|
||
|
double d1 = Math.min(y1, y2);
|
||
|
double d2 = Math.min(z1, z2);
|
||
|
double d3 = Math.max(x1, x2);
|
||
|
double d4 = Math.max(y1, y2);
|
||
|
double d5 = Math.max(z1, z2);
|
||
|
return new BoundingBox(d0, d1, d2, d3, d4, d5);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Offsets the current bounding box by the specified coordinates. Args: x, y, z
|
||
|
*/
|
||
|
public BoundingBox offset(double x, double y, double z)
|
||
|
{
|
||
|
return new BoundingBox(this.minX + x, this.minY + y, this.minZ + z, this.maxX + x, this.maxY + y, this.maxZ + z);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* if instance and the argument bounding boxes overlap in the Y and Z dimensions, calculate the offset between them
|
||
|
* in the X dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
|
||
|
* calculated offset. Otherwise return the calculated offset.
|
||
|
*/
|
||
|
public double calculateXOffset(BoundingBox other, double offsetX)
|
||
|
{
|
||
|
if (other.maxY > this.minY && other.minY < this.maxY && other.maxZ > this.minZ && other.minZ < this.maxZ)
|
||
|
{
|
||
|
if (offsetX > 0.0D && other.maxX <= this.minX)
|
||
|
{
|
||
|
double d1 = this.minX - other.maxX;
|
||
|
|
||
|
if (d1 < offsetX)
|
||
|
{
|
||
|
offsetX = d1;
|
||
|
}
|
||
|
}
|
||
|
else if (offsetX < 0.0D && other.minX >= this.maxX)
|
||
|
{
|
||
|
double d0 = this.maxX - other.minX;
|
||
|
|
||
|
if (d0 > offsetX)
|
||
|
{
|
||
|
offsetX = d0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return offsetX;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return offsetX;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* if instance and the argument bounding boxes overlap in the X and Z dimensions, calculate the offset between them
|
||
|
* in the Y dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
|
||
|
* calculated offset. Otherwise return the calculated offset.
|
||
|
*/
|
||
|
public double calculateYOffset(BoundingBox other, double offsetY)
|
||
|
{
|
||
|
if (other.maxX > this.minX && other.minX < this.maxX && other.maxZ > this.minZ && other.minZ < this.maxZ)
|
||
|
{
|
||
|
if (offsetY > 0.0D && other.maxY <= this.minY)
|
||
|
{
|
||
|
double d1 = this.minY - other.maxY;
|
||
|
|
||
|
if (d1 < offsetY)
|
||
|
{
|
||
|
offsetY = d1;
|
||
|
}
|
||
|
}
|
||
|
else if (offsetY < 0.0D && other.minY >= this.maxY)
|
||
|
{
|
||
|
double d0 = this.maxY - other.minY;
|
||
|
|
||
|
if (d0 > offsetY)
|
||
|
{
|
||
|
offsetY = d0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return offsetY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return offsetY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* if instance and the argument bounding boxes overlap in the Y and X dimensions, calculate the offset between them
|
||
|
* in the Z dimension. return var2 if the bounding boxes do not overlap or if var2 is closer to 0 then the
|
||
|
* calculated offset. Otherwise return the calculated offset.
|
||
|
*/
|
||
|
public double calculateZOffset(BoundingBox other, double offsetZ)
|
||
|
{
|
||
|
if (other.maxX > this.minX && other.minX < this.maxX && other.maxY > this.minY && other.minY < this.maxY)
|
||
|
{
|
||
|
if (offsetZ > 0.0D && other.maxZ <= this.minZ)
|
||
|
{
|
||
|
double d1 = this.minZ - other.maxZ;
|
||
|
|
||
|
if (d1 < offsetZ)
|
||
|
{
|
||
|
offsetZ = d1;
|
||
|
}
|
||
|
}
|
||
|
else if (offsetZ < 0.0D && other.minZ >= this.maxZ)
|
||
|
{
|
||
|
double d0 = this.maxZ - other.minZ;
|
||
|
|
||
|
if (d0 > offsetZ)
|
||
|
{
|
||
|
offsetZ = d0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return offsetZ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return offsetZ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the given bounding box intersects with this one. Args: axisAlignedBB
|
||
|
*/
|
||
|
public boolean intersectsWith(BoundingBox other)
|
||
|
{
|
||
|
return other.maxX > this.minX && other.minX < this.maxX ? (other.maxY > this.minY && other.minY < this.maxY ? other.maxZ > this.minZ && other.minZ < this.maxZ : false) : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns if the supplied Vec3D is completely inside the bounding box
|
||
|
*/
|
||
|
public boolean isVecInside(Vec3 vec)
|
||
|
{
|
||
|
return vec.xCoord > this.minX && vec.xCoord < this.maxX ? (vec.yCoord > this.minY && vec.yCoord < this.maxY ? vec.zCoord > this.minZ && vec.zCoord < this.maxZ : false) : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the average length of the edges of the bounding box.
|
||
|
*/
|
||
|
public double getAverageEdgeLength()
|
||
|
{
|
||
|
double d0 = this.maxX - this.minX;
|
||
|
double d1 = this.maxY - this.minY;
|
||
|
double d2 = this.maxZ - this.minZ;
|
||
|
return (d0 + d1 + d2) / 3.0D;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a bounding box that is inset by the specified amounts
|
||
|
*/
|
||
|
public BoundingBox contract(double x, double y, double z)
|
||
|
{
|
||
|
double d0 = this.minX + x;
|
||
|
double d1 = this.minY + y;
|
||
|
double d2 = this.minZ + z;
|
||
|
double d3 = this.maxX - x;
|
||
|
double d4 = this.maxY - y;
|
||
|
double d5 = this.maxZ - z;
|
||
|
return new BoundingBox(d0, d1, d2, d3, d4, d5);
|
||
|
}
|
||
|
|
||
|
public HitPosition calculateIntercept(Vec3 vecA, Vec3 vecB)
|
||
|
{
|
||
|
Vec3 vec3 = vecA.getIntermediateWithXValue(vecB, this.minX);
|
||
|
Vec3 vec31 = vecA.getIntermediateWithXValue(vecB, this.maxX);
|
||
|
Vec3 vec32 = vecA.getIntermediateWithYValue(vecB, this.minY);
|
||
|
Vec3 vec33 = vecA.getIntermediateWithYValue(vecB, this.maxY);
|
||
|
Vec3 vec34 = vecA.getIntermediateWithZValue(vecB, this.minZ);
|
||
|
Vec3 vec35 = vecA.getIntermediateWithZValue(vecB, this.maxZ);
|
||
|
|
||
|
if (!this.isVecInYZ(vec3))
|
||
|
{
|
||
|
vec3 = null;
|
||
|
}
|
||
|
|
||
|
if (!this.isVecInYZ(vec31))
|
||
|
{
|
||
|
vec31 = null;
|
||
|
}
|
||
|
|
||
|
if (!this.isVecInXZ(vec32))
|
||
|
{
|
||
|
vec32 = null;
|
||
|
}
|
||
|
|
||
|
if (!this.isVecInXZ(vec33))
|
||
|
{
|
||
|
vec33 = null;
|
||
|
}
|
||
|
|
||
|
if (!this.isVecInXY(vec34))
|
||
|
{
|
||
|
vec34 = null;
|
||
|
}
|
||
|
|
||
|
if (!this.isVecInXY(vec35))
|
||
|
{
|
||
|
vec35 = null;
|
||
|
}
|
||
|
|
||
|
Vec3 vec36 = null;
|
||
|
|
||
|
if (vec3 != null)
|
||
|
{
|
||
|
vec36 = vec3;
|
||
|
}
|
||
|
|
||
|
if (vec31 != null && (vec36 == null || vecA.squareDistanceTo(vec31) < vecA.squareDistanceTo(vec36)))
|
||
|
{
|
||
|
vec36 = vec31;
|
||
|
}
|
||
|
|
||
|
if (vec32 != null && (vec36 == null || vecA.squareDistanceTo(vec32) < vecA.squareDistanceTo(vec36)))
|
||
|
{
|
||
|
vec36 = vec32;
|
||
|
}
|
||
|
|
||
|
if (vec33 != null && (vec36 == null || vecA.squareDistanceTo(vec33) < vecA.squareDistanceTo(vec36)))
|
||
|
{
|
||
|
vec36 = vec33;
|
||
|
}
|
||
|
|
||
|
if (vec34 != null && (vec36 == null || vecA.squareDistanceTo(vec34) < vecA.squareDistanceTo(vec36)))
|
||
|
{
|
||
|
vec36 = vec34;
|
||
|
}
|
||
|
|
||
|
if (vec35 != null && (vec36 == null || vecA.squareDistanceTo(vec35) < vecA.squareDistanceTo(vec36)))
|
||
|
{
|
||
|
vec36 = vec35;
|
||
|
}
|
||
|
|
||
|
if (vec36 == null)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Facing enumfacing = null;
|
||
|
|
||
|
if (vec36 == vec3)
|
||
|
{
|
||
|
enumfacing = Facing.WEST;
|
||
|
}
|
||
|
else if (vec36 == vec31)
|
||
|
{
|
||
|
enumfacing = Facing.EAST;
|
||
|
}
|
||
|
else if (vec36 == vec32)
|
||
|
{
|
||
|
enumfacing = Facing.DOWN;
|
||
|
}
|
||
|
else if (vec36 == vec33)
|
||
|
{
|
||
|
enumfacing = Facing.UP;
|
||
|
}
|
||
|
else if (vec36 == vec34)
|
||
|
{
|
||
|
enumfacing = Facing.NORTH;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
enumfacing = Facing.SOUTH;
|
||
|
}
|
||
|
|
||
|
return new HitPosition(ObjectType.BLOCK, vec36, enumfacing, BlockPos.ORIGIN);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if the specified vector is within the YZ dimensions of the bounding box. Args: Vec3D
|
||
|
*/
|
||
|
private boolean isVecInYZ(Vec3 vec)
|
||
|
{
|
||
|
return vec == null ? false : vec.yCoord >= this.minY && vec.yCoord <= this.maxY && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if the specified vector is within the XZ dimensions of the bounding box. Args: Vec3D
|
||
|
*/
|
||
|
private boolean isVecInXZ(Vec3 vec)
|
||
|
{
|
||
|
return vec == null ? false : vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.zCoord >= this.minZ && vec.zCoord <= this.maxZ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if the specified vector is within the XY dimensions of the bounding box. Args: Vec3D
|
||
|
*/
|
||
|
private boolean isVecInXY(Vec3 vec)
|
||
|
{
|
||
|
return vec == null ? false : vec.xCoord >= this.minX && vec.xCoord <= this.maxX && vec.yCoord >= this.minY && vec.yCoord <= this.maxY;
|
||
|
}
|
||
|
|
||
|
public String toString()
|
||
|
{
|
||
|
return "box[" + this.minX + ", " + this.minY + ", " + this.minZ + " -> " + this.maxX + ", " + this.maxY + ", " + this.maxZ + "]";
|
||
|
}
|
||
|
|
||
|
public boolean hasNaN()
|
||
|
{
|
||
|
return Double.isNaN(this.minX) || Double.isNaN(this.minY) || Double.isNaN(this.minZ) || Double.isNaN(this.maxX) || Double.isNaN(this.maxY) || Double.isNaN(this.maxZ);
|
||
|
}
|
||
|
}
|