+package com.irtimaled.bbor.client.models;
+
+import com.irtimaled.bbor.common.BoundingBoxType;
+import com.irtimaled.bbor.common.TypeHelper;
+import com.irtimaled.bbor.common.models.AbstractBoundingBox;
+import com.irtimaled.bbor.common.models.Point;
+
+public class BoundingBoxLine extends AbstractBoundingBox {
+ private final Point minPoint;
+ private final Point maxPoint;
+ private final Double width;
+ private final Point[] corners;
+
+ protected BoundingBoxLine(Point minPoint, Point maxPoint, double width, BoundingBoxType type, Point... corners) {
+ super(type);
+ this.minPoint = minPoint;
+ this.maxPoint = maxPoint;
+ this.width = width;
+ this.corners = corners;
+ }
+
+ public static BoundingBoxLine from(Point minPoint, Point maxPoint, Double width, BoundingBoxType type) {
+ if (width == 0) return new BoundingBoxLine(minPoint, maxPoint, width, type);
+
+ double halfWidth = width / 2.0d;
+
+ double dx = maxPoint.getX() - minPoint.getX();
+ double dz = maxPoint.getZ() - minPoint.getZ();
+
+ double dxm = dx == 0 ? 0 : dx / Math.abs(dx);
+ double dzm = dz == 0 ? 0 : dz / Math.abs(dz);
+
+ double xc, zc;
+ if (dxm == 0 || dzm == 0) {
+ xc = Math.abs(dzm) * halfWidth;
+ zc = Math.abs(dxm) * halfWidth;
+ } else {
+ double h = Math.sqrt(dx * dx + dz * dz);
+ double theta = Math.acos((dz * dz + h * h - dx * dx) / (2 * dz * h));
+ zc = halfWidth * Math.sin(theta);
+ xc = Math.sqrt(halfWidth * halfWidth - zc * zc) * dxm * dzm;
+ }
+
+ return new BoundingBoxLine(minPoint, maxPoint, width, type,
+ new Point(minPoint.getX() + xc, minPoint.getY(), minPoint.getZ() - zc),
+ new Point(minPoint.getX() - xc, minPoint.getY(), minPoint.getZ() + zc),
+ new Point(maxPoint.getX() - xc, maxPoint.getY(), maxPoint.getZ() + zc),
+ new Point(maxPoint.getX() + xc, maxPoint.getY(), maxPoint.getZ() - zc));
+ }
+
+ @Override
+ public int hashCode() {
+ return TypeHelper.combineHashCodes(minPoint.hashCode(), maxPoint.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null || getClass() != obj.getClass()) return false;
+ BoundingBoxLine other = (BoundingBoxLine) obj;
+ return minPoint.equals(other.minPoint) && maxPoint.equals(other.maxPoint);
+ }
+
+ public Point getMinPoint() {
+ return minPoint;
+ }
+
+ public Point getMaxPoint() {
+ return maxPoint;
+ }
+
+ public double getWidth() {
+ return width;
+ }
+
+ public Point[] getCorners() {
+ return corners;
+ }
+
+ @Override
+ public Boolean intersectsBounds(int minX, int minZ, int maxX, int maxZ) {
+ boolean minXWithinBounds = isBetween(minPoint.getX(), minX, maxX);
+ boolean maxXWithinBounds = isBetween(maxPoint.getX(), minX, maxX);
+ boolean minZWithinBounds = isBetween(minPoint.getZ(), minZ, maxZ);
+ boolean maxZWithinBounds = isBetween(maxPoint.getZ(), minZ, maxZ);
+
+ return (minXWithinBounds && minZWithinBounds) ||
+ (maxXWithinBounds && maxZWithinBounds) ||
+ (minXWithinBounds && maxZWithinBounds) ||
+ (maxXWithinBounds && minZWithinBounds);
+ }
+
+ private boolean isBetween(double val, int min, int max) {
+ return val >= min && val <= max;
+ }
+}