package org.apache.lucene.spatial3d.geom;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
class StandardXYZSolid extends BaseXYZSolid {
protected final double minX;
protected final double maxX;
protected final double minY;
protected final double maxY;
protected final double minZ;
protected final double maxZ;
protected final boolean isWholeWorld;
protected final SidedPlane minXPlane;
protected final SidedPlane maxXPlane;
protected final SidedPlane minYPlane;
protected final SidedPlane maxYPlane;
protected final SidedPlane minZPlane;
protected final SidedPlane maxZPlane;
protected final boolean minXPlaneIntersects;
protected final boolean maxXPlaneIntersects;
protected final boolean minYPlaneIntersects;
protected final boolean maxYPlaneIntersects;
protected final boolean minZPlaneIntersects;
protected final boolean maxZPlaneIntersects;
protected final GeoPoint[] edgePoints;
protected final GeoPoint[] notableMinXPoints;
protected final GeoPoint[] notableMaxXPoints;
protected final GeoPoint[] notableMinYPoints;
protected final GeoPoint[] notableMaxYPoints;
protected final GeoPoint[] notableMinZPoints;
protected final GeoPoint[] notableMaxZPoints;
public StandardXYZSolid(final PlanetModel planetModel,
final double minX,
final double maxX,
final double minY,
final double maxY,
final double minZ,
final double maxZ) {
super(planetModel);
if (maxX - minX < Vector.MINIMUM_RESOLUTION)
throw new IllegalArgumentException("X values in wrong order or identical");
if (maxY - minY < Vector.MINIMUM_RESOLUTION)
throw new IllegalArgumentException("Y values in wrong order or identical");
if (maxZ - minZ < Vector.MINIMUM_RESOLUTION)
throw new IllegalArgumentException("Z values in wrong order or identical");
this.minX = minX;
this.maxX = maxX;
this.minY = minY;
this.maxY = maxY;
this.minZ = minZ;
this.maxZ = maxZ;
final double worldMinX = planetModel.getMinimumXValue();
final double worldMaxX = planetModel.getMaximumXValue();
final double worldMinY = planetModel.getMinimumYValue();
final double worldMaxY = planetModel.getMaximumYValue();
final double worldMinZ = planetModel.getMinimumZValue();
final double worldMaxZ = planetModel.getMaximumZValue();
isWholeWorld =
(minX - worldMinX < -Vector.MINIMUM_RESOLUTION) &&
(maxX - worldMaxX > Vector.MINIMUM_RESOLUTION) &&
(minY - worldMinY < -Vector.MINIMUM_RESOLUTION) &&
(maxY - worldMaxY > Vector.MINIMUM_RESOLUTION) &&
(minZ - worldMinZ < -Vector.MINIMUM_RESOLUTION) &&
(maxZ - worldMaxZ > Vector.MINIMUM_RESOLUTION);
if (isWholeWorld) {
minXPlane = null;
maxXPlane = null;
minYPlane = null;
maxYPlane = null;
minZPlane = null;
maxZPlane = null;
minXPlaneIntersects = false;
maxXPlaneIntersects = false;
minYPlaneIntersects = false;
maxYPlaneIntersects = false;
minZPlaneIntersects = false;
maxZPlaneIntersects = false;
notableMinXPoints = null;
notableMaxXPoints = null;
notableMinYPoints = null;
notableMaxYPoints = null;
notableMinZPoints = null;
notableMaxZPoints = null;
edgePoints = null;
} else {
minXPlane = new SidedPlane(maxX,0.0,0.0,xUnitVector,-minX);
maxXPlane = new SidedPlane(minX,0.0,0.0,xUnitVector,-maxX);
minYPlane = new SidedPlane(0.0,maxY,0.0,yUnitVector,-minY);
maxYPlane = new SidedPlane(0.0,minY,0.0,yUnitVector,-maxY);
minZPlane = new SidedPlane(0.0,0.0,maxZ,zUnitVector,-minZ);
maxZPlane = new SidedPlane(0.0,0.0,minZ,zUnitVector,-maxZ);
final GeoPoint[] minXminY = minXPlane.findIntersections(planetModel,minYPlane,maxXPlane,maxYPlane,minZPlane,maxZPlane);
final GeoPoint[] minXmaxY = minXPlane.findIntersections(planetModel,maxYPlane,maxXPlane,minYPlane,minZPlane,maxZPlane);
final GeoPoint[] minXminZ = minXPlane.findIntersections(planetModel,minZPlane,maxXPlane,maxZPlane,minYPlane,maxYPlane);
final GeoPoint[] minXmaxZ = minXPlane.findIntersections(planetModel,maxZPlane,maxXPlane,minZPlane,minYPlane,maxYPlane);
final GeoPoint[] maxXminY = maxXPlane.findIntersections(planetModel,minYPlane,minXPlane,maxYPlane,minZPlane,maxZPlane);
final GeoPoint[] maxXmaxY = maxXPlane.findIntersections(planetModel,maxYPlane,minXPlane,minYPlane,minZPlane,maxZPlane);
final GeoPoint[] maxXminZ = maxXPlane.findIntersections(planetModel,minZPlane,minXPlane,maxZPlane,minYPlane,maxYPlane);
final GeoPoint[] maxXmaxZ = maxXPlane.findIntersections(planetModel,maxZPlane,minXPlane,minZPlane,minYPlane,maxYPlane);
final GeoPoint[] minYminZ = minYPlane.findIntersections(planetModel,minZPlane,maxYPlane,maxZPlane,minXPlane,maxXPlane);
final GeoPoint[] minYmaxZ = minYPlane.findIntersections(planetModel,maxZPlane,maxYPlane,minZPlane,minXPlane,maxXPlane);
final GeoPoint[] maxYminZ = maxYPlane.findIntersections(planetModel,minZPlane,minYPlane,maxZPlane,minXPlane,maxXPlane);
final GeoPoint[] maxYmaxZ = maxYPlane.findIntersections(planetModel,maxZPlane,minYPlane,minZPlane,minXPlane,maxXPlane);
notableMinXPoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ);
notableMaxXPoints = glueTogether(maxXminY, maxXmaxY, maxXminZ, maxXmaxZ);
notableMinYPoints = glueTogether(minXminY, maxXminY, minYminZ, minYmaxZ);
notableMaxYPoints = glueTogether(minXmaxY, maxXmaxY, maxYminZ, maxYmaxZ);
notableMinZPoints = glueTogether(minXminZ, maxXminZ, minYminZ, maxYminZ);
notableMaxZPoints = glueTogether(minXmaxZ, maxXmaxZ, minYmaxZ, maxYmaxZ);
final boolean minXminYminZ = planetModel.pointOutside(minX, minY, minZ);
final boolean minXminYmaxZ = planetModel.pointOutside(minX, minY, maxZ);
final boolean minXmaxYminZ = planetModel.pointOutside(minX, maxY, minZ);
final boolean minXmaxYmaxZ = planetModel.pointOutside(minX, maxY, maxZ);
final boolean maxXminYminZ = planetModel.pointOutside(maxX, minY, minZ);
final boolean maxXminYmaxZ = planetModel.pointOutside(maxX, minY, maxZ);
final boolean maxXmaxYminZ = planetModel.pointOutside(maxX, maxY, minZ);
final boolean maxXmaxYmaxZ = planetModel.pointOutside(maxX, maxY, maxZ);
final GeoPoint[] minXEdges;
if (minX - worldMinX >= -Vector.MINIMUM_RESOLUTION && minX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
minXminYminZ && minXminYmaxZ && minXmaxYminZ && minXmaxYmaxZ) {
final GeoPoint intPoint = minXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
if (intPoint != null) {
minXEdges = new GeoPoint[]{intPoint};
} else {
minXEdges = EMPTY_POINTS;
}
} else {
minXEdges = EMPTY_POINTS;
}
final GeoPoint[] maxXEdges;
if (maxX - worldMinX >= -Vector.MINIMUM_RESOLUTION && maxX - worldMaxX <= Vector.MINIMUM_RESOLUTION &&
minY < 0.0 && maxY > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
maxXminYminZ && maxXminYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
final GeoPoint intPoint = maxXPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
if (intPoint != null) {
maxXEdges = new GeoPoint[]{intPoint};
} else {
maxXEdges = EMPTY_POINTS;
}
} else {
maxXEdges = EMPTY_POINTS;
}
final GeoPoint[] minYEdges;
if (minY - worldMinY >= -Vector.MINIMUM_RESOLUTION && minY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
minXminYminZ && minXminYmaxZ && maxXminYminZ && maxXminYmaxZ) {
final GeoPoint intPoint = minYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
if (intPoint != null) {
minYEdges = new GeoPoint[]{intPoint};
} else {
minYEdges = EMPTY_POINTS;
}
} else {
minYEdges = EMPTY_POINTS;
}
final GeoPoint[] maxYEdges;
if (maxY - worldMinY >= -Vector.MINIMUM_RESOLUTION && maxY - worldMaxY <= Vector.MINIMUM_RESOLUTION &&
minX < 0.0 && maxX > 0.0 && minZ < 0.0 && maxZ > 0.0 &&
minXmaxYminZ && minXmaxYmaxZ && maxXmaxYminZ && maxXmaxYmaxZ) {
final GeoPoint intPoint = maxYPlane.getSampleIntersectionPoint(planetModel, yVerticalPlane);
if (intPoint != null) {
maxYEdges = new GeoPoint[]{intPoint};
} else {
maxYEdges = EMPTY_POINTS;
}
} else {
maxYEdges = EMPTY_POINTS;
}
final GeoPoint[] minZEdges;
if (minZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && minZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
minXminYminZ && minXmaxYminZ && maxXminYminZ && maxXmaxYminZ) {
final GeoPoint intPoint = minZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
if (intPoint != null) {
minZEdges = new GeoPoint[]{intPoint};
} else {
minZEdges = EMPTY_POINTS;
}
} else {
minZEdges = EMPTY_POINTS;
}
final GeoPoint[] maxZEdges;
if (maxZ - worldMinZ >= -Vector.MINIMUM_RESOLUTION && maxZ - worldMaxZ <= Vector.MINIMUM_RESOLUTION &&
minX < 0.0 && maxX > 0.0 && minY < 0.0 && maxY > 0.0 &&
minXminYmaxZ && minXmaxYmaxZ && maxXminYmaxZ && maxXmaxYmaxZ) {
final GeoPoint intPoint = maxZPlane.getSampleIntersectionPoint(planetModel, xVerticalPlane);
if (intPoint != null) {
maxZEdges = new GeoPoint[]{intPoint};
} else {
maxZEdges = EMPTY_POINTS;
}
} else {
maxZEdges = EMPTY_POINTS;
}
minXPlaneIntersects = notableMinXPoints.length + minXEdges.length > 0;
maxXPlaneIntersects = notableMaxXPoints.length + maxXEdges.length > 0;
minYPlaneIntersects = notableMinYPoints.length + minYEdges.length > 0;
maxYPlaneIntersects = notableMaxYPoints.length + maxYEdges.length > 0;
minZPlaneIntersects = notableMinZPoints.length + minZEdges.length > 0;
maxZPlaneIntersects = notableMaxZPoints.length + maxZEdges.length > 0;
this.edgePoints = glueTogether(minXminY, minXmaxY, minXminZ, minXmaxZ,
maxXminY, maxXmaxY, maxXminZ, maxXmaxZ,
minYminZ, minYmaxZ, maxYminZ, maxYmaxZ,
minXEdges, maxXEdges, minYEdges, maxYEdges, minZEdges, maxZEdges);
}
}
public StandardXYZSolid(final PlanetModel planetModel, final InputStream inputStream) throws IOException {
this(planetModel,
SerializableObject.readDouble(inputStream),
SerializableObject.readDouble(inputStream),
SerializableObject.readDouble(inputStream),
SerializableObject.readDouble(inputStream),
SerializableObject.readDouble(inputStream),
SerializableObject.readDouble(inputStream));
}
@Override
public void write(final OutputStream outputStream) throws IOException {
SerializableObject.writeDouble(outputStream, minX);
SerializableObject.writeDouble(outputStream, maxX);
SerializableObject.writeDouble(outputStream, minY);
SerializableObject.writeDouble(outputStream, maxY);
SerializableObject.writeDouble(outputStream, minZ);
SerializableObject.writeDouble(outputStream, maxZ);
}
@Override
protected GeoPoint[] getEdgePoints() {
return edgePoints;
}
@Override
public boolean isWithin(final double x, final double y, final double z) {
if (isWholeWorld) {
return true;
}
return minXPlane.isWithin(x, y, z) &&
maxXPlane.isWithin(x, y, z) &&
minYPlane.isWithin(x, y, z) &&
maxYPlane.isWithin(x, y, z) &&
minZPlane.isWithin(x, y, z) &&
maxZPlane.isWithin(x, y, z);
}
@Override
public int getRelationship(final GeoShape path) {
if (isWholeWorld) {
if (path.getEdgePoints().length > 0)
return WITHIN;
return OVERLAPS;
}
final int insideRectangle = isShapeInsideArea(path);
if (insideRectangle == SOME_INSIDE) {
return OVERLAPS;
}
final int insideShape = isAreaInsideShape(path);
if (insideShape == SOME_INSIDE) {
return OVERLAPS;
}
if (insideRectangle == ALL_INSIDE && insideShape == ALL_INSIDE) {
return OVERLAPS;
}
if ((minXPlaneIntersects && path.intersects(minXPlane, notableMinXPoints, maxXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane)) ||
(maxXPlaneIntersects && path.intersects(maxXPlane, notableMaxXPoints, minXPlane, minYPlane, maxYPlane, minZPlane, maxZPlane)) ||
(minYPlaneIntersects && path.intersects(minYPlane, notableMinYPoints, maxYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane)) ||
(maxYPlaneIntersects && path.intersects(maxYPlane, notableMaxYPoints, minYPlane, minXPlane, maxXPlane, minZPlane, maxZPlane)) ||
(minZPlaneIntersects && path.intersects(minZPlane, notableMinZPoints, maxZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane)) ||
(maxZPlaneIntersects && path.intersects(maxZPlane, notableMaxZPoints, minZPlane, minXPlane, maxXPlane, minYPlane, maxYPlane))) {
return OVERLAPS;
}
if (insideRectangle == ALL_INSIDE) {
return WITHIN;
}
if (insideShape == ALL_INSIDE) {
return CONTAINS;
}
return DISJOINT;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof StandardXYZSolid))
return false;
StandardXYZSolid other = (StandardXYZSolid) o;
if (!super.equals(other) ||
other.isWholeWorld != isWholeWorld) {
return false;
}
if (!isWholeWorld) {
return other.minXPlane.equals(minXPlane) &&
other.maxXPlane.equals(maxXPlane) &&
other.minYPlane.equals(minYPlane) &&
other.maxYPlane.equals(maxYPlane) &&
other.minZPlane.equals(minZPlane) &&
other.maxZPlane.equals(maxZPlane);
}
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (isWholeWorld?1:0);
if (!isWholeWorld) {
result = 31 * result + minXPlane.hashCode();
result = 31 * result + maxXPlane.hashCode();
result = 31 * result + minYPlane.hashCode();
result = 31 * result + maxYPlane.hashCode();
result = 31 * result + minZPlane.hashCode();
result = 31 * result + maxZPlane.hashCode();
}
return result;
}
@Override
public String toString() {
return "StandardXYZSolid: {planetmodel="+planetModel+", isWholeWorld="+isWholeWorld+", minXplane="+minXPlane+", maxXplane="+maxXPlane+", minYplane="+minYPlane+", maxYplane="+maxYPlane+", minZplane="+minZPlane+", maxZplane="+maxZPlane+"}";
}
}