package com.revolsys.geometry.util;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.Geometry;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.geometry.model.Point;
public class BoundingBoxUtil {
/**
* The bitmask that indicates that a point lies below
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_BOTTOM = 8;
/**
* The bitmask that indicates that a point lies to the left of
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_LEFT = 1;
/**
* The bitmask that indicates that a point lies to the right of
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_RIGHT = 4;
/**
* The bitmask that indicates that a point lies above
* this <code>Rectangle2D</code>.
* @since 1.2
*/
public static final int OUT_TOP = 2;
public static boolean covers(final double minX1, final double minY1, final double maxX1,
final double maxY1, final double minX2, final double minY2, final double maxX2,
final double maxY2) {
return minX2 >= minX1 && maxX2 <= maxX1 && minY2 >= minY1 && maxY2 <= maxY1;
}
public static void expand(final double[] bounds, final int axisCount,
final BoundingBox boundingBox) {
if (boundingBox != null) {
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double min = boundingBox.getMin(axisIndex);
expand(bounds, axisCount, axisIndex, min);
final double max = boundingBox.getMax(axisIndex);
expand(bounds, axisCount, axisIndex, max);
}
}
}
public static void expand(final double[] bounds, final int axisCount,
final double... coordinates) {
for (int axisIndex = 0; axisIndex < axisCount && axisIndex < coordinates.length; axisIndex++) {
final double coordinate = coordinates[axisIndex];
expand(bounds, axisCount, axisIndex, coordinate);
}
}
public static void expand(final double[] bounds, final int axisCount, final Geometry geometry) {
if (geometry != null) {
final BoundingBox boundingBox = geometry.getBoundingBox();
expand(bounds, axisCount, boundingBox);
}
}
public static void expand(final double[] bounds, final int axisCount, final int axisIndex,
final double coordinate) {
if (Double.isFinite(coordinate)) {
final double min = bounds[axisIndex];
if (coordinate < min || Double.isNaN(min)) {
bounds[axisIndex] = coordinate;
}
final double max = bounds[axisCount + axisIndex];
if (coordinate > max || Double.isNaN(max)) {
bounds[axisCount + axisIndex] = coordinate;
}
}
}
public static void expand(final double[] bounds, final int axisCount, final Point point) {
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double value = point.getCoordinate(axisIndex);
expand(bounds, axisCount, axisIndex, value);
}
}
public static void expand(final GeometryFactory geometryFactory, final double[] bounds,
final double... values) {
final int axisCount = bounds.length / 2;
for (int i = 0; i < values.length; i++) {
final double value = values[i];
final int axisIndex = i % axisCount;
expand(geometryFactory, bounds, axisCount, axisIndex, value);
}
}
public static void expand(final GeometryFactory geometryFactory, final double[] bounds,
final int axisIndex, double coordinate) {
if (geometryFactory != null) {
coordinate = geometryFactory.makePrecise(axisIndex, coordinate);
}
if (Double.isFinite(coordinate)) {
final int axisCount = bounds.length / 2;
final double min = bounds[axisIndex];
if (coordinate < min || Double.isNaN(min)) {
bounds[axisIndex] = coordinate;
}
final double max = bounds[axisCount + axisIndex];
if (coordinate > max || Double.isNaN(max)) {
bounds[axisCount + axisIndex] = coordinate;
}
}
}
public static void expand(final GeometryFactory geometryFactory, final double[] bounds,
final int axisCount, final int axisIndex, double coordinate) {
if (geometryFactory != null) {
coordinate = geometryFactory.makePrecise(axisIndex, coordinate);
}
if (Double.isFinite(coordinate)) {
final double min = bounds[axisIndex];
if (coordinate < min || Double.isNaN(min)) {
bounds[axisIndex] = coordinate;
}
final double max = bounds[axisCount + axisIndex];
if (coordinate > max || Double.isNaN(max)) {
bounds[axisCount + axisIndex] = coordinate;
}
}
}
public static void expand(final GeometryFactory geometryFactory, final double[] bounds,
Point point) {
final int axisCount = bounds.length / 2;
point = point.convertGeometry(geometryFactory, axisCount);
final int count = Math.min(axisCount, point.getAxisCount());
for (int axisIndex = 0; axisIndex < count; axisIndex++) {
final double coordinate = point.getCoordinate(axisIndex);
if (Double.isFinite(coordinate)) {
expand(geometryFactory, bounds, axisCount, axisIndex, coordinate);
}
}
}
public static void expandX(final double[] bounds, final int axisCount, final double value) {
expand(bounds, axisCount, 0, value);
}
public static void expandY(final double[] bounds, final int axisCount, final double value) {
expand(bounds, axisCount, 1, value);
}
public static void expandZ(final double[] bounds, final int axisCount, final double value) {
expand(bounds, axisCount, 2, value);
}
public static double getMax(final double[] bounds, final int axisIndex) {
if (bounds == null) {
return Double.NaN;
} else {
final int axisCount = bounds.length / 2;
if (axisIndex < 0 || axisIndex > axisCount) {
return Double.NaN;
} else {
final double max = bounds[axisCount + axisIndex];
return max;
}
}
}
public static double getMin(final double[] bounds, final int axisIndex) {
if (bounds == null) {
return Double.NaN;
} else {
final int axisCount = bounds.length / 2;
if (axisIndex < 0 || axisIndex >= axisCount) {
return Double.NaN;
} else {
final double min = bounds[axisIndex];
return min;
}
}
}
public static int getOutcode(final double minX, final double minY, final double maxX,
final double maxY, final double x, final double y) {
int out = 0;
if (x < minX) {
out = OUT_LEFT;
} else if (x > maxX) {
out = OUT_RIGHT;
} else {
out = 0;
}
if (y < minY) {
out |= OUT_BOTTOM;
} else if (y > maxY) {
out |= OUT_TOP;
}
return out;
}
/**
* Point intersects the bounding box of the line.
*
* @param lineStart
* @param lineEnd
* @param point
* @return
*/
public static boolean intersects(final double p1X, final double p1Y, final double p2X,
final double p2Y, final double qX, final double qY) {
if (qX >= (p1X < p2X ? p1X : p2X) && qX <= (p1X > p2X ? p1X : p2X)
&& qY >= (p1Y < p2Y ? p1Y : p2Y) && qY <= (p1Y > p2Y ? p1Y : p2Y)) {
return true;
} else {
return false;
}
}
public static boolean intersects(final double minX1, final double minY1, final double maxX1,
final double maxY1, double x1, double y1, double x2, double y2) {
if (x1 > x2) {
final double t = x1;
x1 = x2;
x2 = t;
}
if (y1 > y2) {
final double t = y1;
y1 = y2;
y2 = t;
}
return !(x1 > maxX1 || x2 < minX1 || y1 > maxY1 || y2 < minY1);
}
public static boolean intersects(final double[] bounds1, final double[] bounds2) {
if (bounds1 == null || bounds2 == null) {
return false;
} else {
final int axisCount1 = bounds1.length / 2;
final double minX1 = bounds1[0];
final double minY1 = bounds1[1];
final double maxX1 = bounds1[axisCount1];
final double maxY1 = bounds1[axisCount1 + 1];
final int axisCount2 = bounds2.length / 2;
final double minX2 = bounds2[0];
final double minY2 = bounds2[1];
final double maxX2 = bounds2[axisCount2];
final double maxY2 = bounds2[axisCount2 + 1];
return !(minX2 > maxX1 || maxX2 < minX1 || minY2 > maxY1 || maxY2 < minY1);
}
}
/**
* Point intersects the bounding box of the line.
*
* @param lineStart
* @param lineEnd
* @param point
* @return
*/
public static boolean intersects(final Point lineStart, final Point lineEnd, final Point point) {
final double x1 = lineStart.getX();
final double y1 = lineStart.getY();
final double x2 = lineEnd.getX();
final double y2 = lineEnd.getY();
final double x = point.getX();
final double y = point.getY();
return intersects(x1, y1, x2, y2, x, y);
}
/**
* Tests whether the envelope defined by p1-p2
* and the envelope defined by q1-q2
* intersect.
*
* @param p1 one extremal point of the envelope P
* @param p2 another extremal point of the envelope P
* @param q1 one extremal point of the envelope Q
* @param q2 another extremal point of the envelope Q
* @return <code>true</code> if Q intersects P
*/
public static boolean intersects(final Point line1Start, final Point line1End,
final Point line2Start, final Point line2End) {
final double line1x1 = line1Start.getX();
final double line1y1 = line1Start.getY();
final double line1x2 = line1End.getX();
final double line1y2 = line1End.getY();
final double line2x1 = line2Start.getX();
final double line2y1 = line2Start.getY();
final double line2x2 = line2End.getX();
final double line2y2 = line2End.getY();
return intersectsMinMax(line1x1, line1y1, line1x2, line1y2, line2x1, line2y1, line2x2, line2y2);
}
public static boolean intersectsLine(final double minX, final double minY, final double maxX,
final double maxY, double x1, double y1, final double x2, final double y2) {
int out1, out2;
if ((out2 = getOutcode(minX, minY, maxX, maxY, x2, y2)) == 0) {
return true;
}
while ((out1 = getOutcode(minX, minY, maxX, maxY, x1, y1)) != 0) {
if ((out1 & out2) != 0) {
return false;
} else if ((out1 & (OUT_LEFT | OUT_RIGHT)) != 0) {
double x;
if ((out1 & OUT_RIGHT) != 0) {
x = maxX;
} else {
x = minX;
}
y1 = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
x1 = x;
} else {
double y;
if ((out1 & OUT_BOTTOM) != 0) {
y = maxY;
} else {
y = minY;
}
x1 = x1 + (y - y1) * (x2 - x1) / (y2 - y1);
y1 = y;
}
}
return true;
}
public static boolean intersectsMinMax(final double p1X, final double p1Y, final double p2X,
final double p2Y, final double q1X, final double q1Y, final double q2X, final double q2Y) {
double minp = Math.min(p1X, p2X);
double maxq = Math.max(q1X, q2X);
if (minp > maxq) {
return false;
} else {
double minq = Math.min(q1X, q2X);
double maxp = Math.max(p1X, p2X);
if (maxp < minq) {
return false;
} else {
minp = Math.min(p1Y, p2Y);
maxq = Math.max(q1Y, q2Y);
if (minp > maxq) {
return false;
} else {
minq = Math.min(q1Y, q2Y);
maxp = Math.max(p1Y, p2Y);
if (maxp < minq) {
return false;
} else {
return true;
}
}
}
}
}
public static boolean intersectsOutcode(final double minX1, final double minY1,
final double maxX1, final double maxY1, double minX2, double minY2, double maxX2,
double maxY2) {
int out1 = getOutcode(minX1, minY1, maxX1, maxX2, minX2, minY2);
int out2 = getOutcode(minX1, minY1, maxX1, maxX2, maxX2, maxY2);
while (true) {
if ((out1 | out2) == 0) {
return true;
} else if ((out1 & out2) != 0) {
return false;
} else {
int out;
if (out1 != 0) {
out = out1;
} else {
out = out2;
}
double x = 0;
double y = 0;
if ((out & OUT_TOP) != 0) {
x = minX2 + (maxX2 - minX2) * (maxY1 - minY2) / (maxY2 - minY2);
y = maxY1;
} else if ((out & OUT_BOTTOM) != 0) {
x = minX2 + (maxX2 - minX2) * (minY1 - minY2) / (maxY2 - minY2);
y = minY1;
} else if ((out & OUT_RIGHT) != 0) {
y = minY2 + (maxY2 - minY2) * (maxX1 - minX2) / (maxX2 - minX2);
x = maxX1;
} else if ((out & OUT_LEFT) != 0) {
y = minY2 + (maxY2 - minY2) * (minX1 - minX2) / (maxX2 - minX2);
x = minX1;
}
if (out == out1) {
minX2 = x;
minY2 = y;
out1 = getOutcode(minX1, minY1, maxX1, maxX2, minX2, minY2);
} else {
maxX2 = x;
maxY2 = y;
out2 = getOutcode(minX1, minY1, maxX1, maxX2, maxX2, maxY2);
}
}
}
}
public static boolean isEmpty(final BoundingBox boundingBox) {
if (boundingBox == null) {
return true;
} else {
return boundingBox.isEmpty();
}
}
public static double[] newBounds(final double... bounds) {
final int axisCount = bounds.length;
final double[] newBounds = newBounds(axisCount);
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double coordinate = bounds[axisIndex];
if (Double.isFinite(coordinate)) {
newBounds[axisIndex] = coordinate;
newBounds[axisCount + axisCount] = coordinate;
}
}
return newBounds;
}
public static double[] newBounds(final GeometryFactory geometryFactory, final double... bounds) {
final int axisCount = bounds.length;
final double[] newBounds = newBounds(axisCount);
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
double coordinate = bounds[axisIndex];
if (geometryFactory != null) {
coordinate = geometryFactory.makePrecise(axisIndex, coordinate);
}
if (Double.isFinite(coordinate)) {
newBounds[axisIndex] = coordinate;
newBounds[axisCount + axisIndex] = coordinate;
}
}
return newBounds;
}
public static double[] newBounds(final GeometryFactory geometryFactory, final int axisCount,
Point point) {
point = point.convertGeometry(geometryFactory, axisCount);
final double[] bounds = newBounds(axisCount);
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
double coordinate = point.getCoordinate(axisIndex);
if (geometryFactory != null) {
coordinate = geometryFactory.makePrecise(axisIndex, coordinate);
}
if (Double.isFinite(coordinate)) {
bounds[axisIndex] = coordinate;
bounds[axisCount + axisIndex] = coordinate;
}
}
return bounds;
}
public static double[] newBounds(final GeometryFactory geometryFactory, final Point point) {
final int axisCount = point.getAxisCount();
return newBounds(geometryFactory, axisCount, point);
}
public static double[] newBounds(final int axisCount) {
final double[] newBounds = new double[axisCount * 2];
for (int i = 0; i < newBounds.length; i++) {
newBounds[i] = Double.NaN;
}
return newBounds;
}
public static double[] newBounds(final int axisCount, final Point point) {
final double[] bounds = newBounds(axisCount);
for (int axisIndex = 0; axisIndex < axisCount; axisIndex++) {
final double coordinate = point.getCoordinate(axisIndex);
if (Double.isFinite(coordinate)) {
bounds[axisIndex] = coordinate;
bounds[axisCount + axisIndex] = coordinate;
}
}
return bounds;
}
public static double[] newBounds(final Point point) {
final int axisCount = point.getAxisCount();
return newBounds(axisCount, point);
}
public static double[] newBounds2d() {
return new double[] {
Double.NaN, Double.NaN, Double.NaN, Double.NaN
};
}
}