package org.osm2world.core.math;
import static java.lang.Math.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.osm2world.core.math.datastructures.IntersectionTestObject;
/**
* immutable representation of an axis-aligned bounding box
* with x and z dimensions
*/
public class AxisAlignedBoundingBoxXZ implements Cloneable {
public final double minX, minZ, maxX, maxZ;
public AxisAlignedBoundingBoxXZ(double minX, double minZ,
double maxX, double maxZ) {
this.minX = minX;
this.minZ = minZ;
this.maxX = maxX;
this.maxZ = maxZ;
}
/**
* @param boundedPoints must contain at least one point
*/
public AxisAlignedBoundingBoxXZ(Collection<? extends Vector3D> boundedPoints) {
assert (!boundedPoints.isEmpty());
double minX = Double.POSITIVE_INFINITY, minZ = Double.POSITIVE_INFINITY;
double maxX = Double.NEGATIVE_INFINITY, maxZ = Double.NEGATIVE_INFINITY;
for (Vector3D p : boundedPoints) {
minX = min(minX, p.getX()); minZ = min(minZ, p.getZ());
maxX = max(maxX, p.getX()); maxZ = max(maxZ, p.getZ());
}
this.minX = minX; this.minZ = minZ;
this.maxX = maxX; this.maxZ = maxZ;
}
public double sizeX() { return maxX - minX; }
public double sizeZ() { return maxZ - minZ; }
public VectorXZ center() {
return new VectorXZ(minX + sizeX()/2, minZ + sizeZ()/2);
}
private SimplePolygonXZ polygonXZ;
public SimplePolygonXZ polygonXZ() {
if (polygonXZ == null) {
List<VectorXZ> vertexLoop = new ArrayList<VectorXZ>(5);
vertexLoop.add(new VectorXZ(minX, minZ));
vertexLoop.add(new VectorXZ(maxX, minZ));
vertexLoop.add(new VectorXZ(maxX, maxZ));
vertexLoop.add(new VectorXZ(minX, maxZ));
vertexLoop.add(vertexLoop.get(0));
polygonXZ = new SimplePolygonXZ(vertexLoop);
}
return polygonXZ;
}
public VectorXZ bottomLeft() {
return polygonXZ().getVertexCollection().get(0);
}
public VectorXZ bottomRight() {
return polygonXZ().getVertexCollection().get(1);
}
public VectorXZ topRight() {
return polygonXZ().getVertexCollection().get(2);
}
public VectorXZ topLeft() {
return polygonXZ().getVertexCollection().get(3);
}
/**
* returns a bounding box that is a bit larger than this one
*/
public AxisAlignedBoundingBoxXZ pad(double paddingSize) {
return new AxisAlignedBoundingBoxXZ(
minX - paddingSize,
minZ - paddingSize,
maxX + paddingSize,
maxZ + paddingSize);
}
public boolean overlaps(AxisAlignedBoundingBoxXZ otherBox) {
return !(maxX <= otherBox.minX
|| minX >= otherBox.maxX
|| maxZ <= otherBox.minZ
|| minZ >= otherBox.maxZ);
}
public boolean contains(AxisAlignedBoundingBoxXZ otherBox) {
return minX <= otherBox.minX
&& minZ <= otherBox.minZ
&& maxX >= otherBox.maxX
&& maxZ >= otherBox.maxZ;
}
public boolean contains(IntersectionTestObject object) {
return polygonXZ().contains(
object.getAxisAlignedBoundingBoxXZ().polygonXZ());
}
public boolean contains(VectorXZ v) {
return v.x >= minX && v.x <= maxX && v.z >= minZ && v.z <= maxZ;
}
public static final AxisAlignedBoundingBoxXZ union(
AxisAlignedBoundingBoxXZ box1, AxisAlignedBoundingBoxXZ box2) {
return new AxisAlignedBoundingBoxXZ(
Math.min(box1.minX, box2.minX),
Math.min(box1.minZ, box2.minZ),
Math.max(box1.maxX, box2.maxX),
Math.max(box1.maxZ, box2.maxZ));
}
@Override
public AxisAlignedBoundingBoxXZ clone() {
try {
return (AxisAlignedBoundingBoxXZ) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError("unexpected super.clone behavior");
}
}
}