blob: b4c5d06ec992d54bf84888ae34f9a0cb768092ee [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.spatial3d.geom;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Fast implementation of a polygon representing S2 geometry cell. There are no checks validating that
* points are convex therefore users must be provide four points in CCW or the logic will fail.
*
* @lucene.internal
*/
class GeoS2Shape extends GeoBasePolygon {
/** The first point */
protected final GeoPoint point1;
/** The second point */
protected final GeoPoint point2;
/** The third point */
protected final GeoPoint point3;
/** The fourth point */
protected final GeoPoint point4;
/** The first plane */
protected final SidedPlane plane1;
/** The second plane */
protected final SidedPlane plane2;
/** The third plane */
protected final SidedPlane plane3;
/** The fourth plane */
protected final SidedPlane plane4;
/** Notable points for the first plane */
protected final GeoPoint[] plane1Points;
/** Notable points for second plane */
protected final GeoPoint[] plane2Points;
/** Notable points for third plane */
protected final GeoPoint[] plane3Points;
/** Notable points for fourth plane */
protected final GeoPoint[] plane4Points;
/** Edge point for this S2 cell */
protected final GeoPoint[] edgePoints;
/**
* It builds from 4 points given in CCW. It must be convex or logic will fail.
*
*@param planetModel is the planet model.
*@param point1 the first point.
*@param point2 the second point.
*@param point3 the third point.
*@param point4 the four point.
*/
public GeoS2Shape(final PlanetModel planetModel, GeoPoint point1, GeoPoint point2, GeoPoint point3, GeoPoint point4) {
super(planetModel);
this.point1 = point1;
this.point2 = point2;
this.point3 = point3;
this.point4 = point4;
// Now build the four planes
this.plane1 = new SidedPlane(point4, point1, point2);
this.plane2 = new SidedPlane(point1, point2, point3);
this.plane3 = new SidedPlane(point2, point3, point4);
this.plane4 = new SidedPlane(point3, point4, point1);
//collect the notable points for the planes
this.plane1Points = new GeoPoint[]{point1, point2};
this.plane2Points = new GeoPoint[]{point2, point3};
this.plane3Points = new GeoPoint[]{point3, point4};
this.plane4Points = new GeoPoint[]{point4, point1};
this.edgePoints = new GeoPoint[]{point1};
}
/**
* Constructor for deserialization.
* @param planetModel is the planet model.
* @param inputStream is the input stream.
*/
public GeoS2Shape(final PlanetModel planetModel, final InputStream inputStream) throws IOException {
this(planetModel,
(GeoPoint) SerializableObject.readObject(inputStream),
(GeoPoint) SerializableObject.readObject(inputStream),
(GeoPoint) SerializableObject.readObject(inputStream),
(GeoPoint) SerializableObject.readObject(inputStream));
}
@Override
public void write(final OutputStream outputStream) throws IOException {
SerializableObject.writeObject(outputStream, point1);
SerializableObject.writeObject(outputStream, point2);
SerializableObject.writeObject(outputStream, point3);
SerializableObject.writeObject(outputStream, point4);
}
@Override
public boolean isWithin(final double x, final double y, final double z) {
return plane1.isWithin(x, y, z) &&
plane2.isWithin(x, y, z) &&
plane3.isWithin(x, y, z) &&
plane4.isWithin(x, y, z);
}
@Override
public GeoPoint[] getEdgePoints() {
return edgePoints;
}
@Override
public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
return p.intersects(planetModel, plane1, notablePoints, plane1Points, bounds, plane2, plane4) ||
p.intersects(planetModel, plane2, notablePoints, plane2Points, bounds, plane3, plane1) ||
p.intersects(planetModel, plane3, notablePoints, plane3Points, bounds, plane4, plane2) ||
p.intersects(planetModel, plane4, notablePoints, plane4Points, bounds, plane1, plane3);
}
@Override
public boolean intersects(GeoShape geoShape) {
return geoShape.intersects(plane1, plane1Points, plane2, plane4) ||
geoShape.intersects(plane2, plane2Points, plane3, plane1) ||
geoShape.intersects(plane3, plane3Points, plane4, plane2) ||
geoShape.intersects(plane4, plane4Points, plane1, plane3);
}
@Override
public void getBounds(Bounds bounds) {
super.getBounds(bounds);
bounds.addPlane(planetModel, plane1, plane2, plane4)
.addPlane(planetModel, plane2, plane3, plane1)
.addPlane(planetModel, plane3, plane4, plane2)
.addPlane(planetModel, plane4, plane1, plane3)
.addPoint(point1).addPoint(point2).addPoint(point3).addPoint(point4);
}
@Override
public double outsideDistance(DistanceStyle distanceStyle, double x, double y, double z) {
final double planeDistance1 = distanceStyle.computeDistance(planetModel, plane1, x,y,z, plane2, plane4);
final double planeDistance2 = distanceStyle.computeDistance(planetModel, plane2, x,y,z, plane3, plane1);
final double planeDistance3 = distanceStyle.computeDistance(planetModel, plane3, x,y,z, plane4, plane2);
final double planeDistance4 = distanceStyle.computeDistance(planetModel, plane4, x,y,z, plane1, plane3);
final double pointDistance1 = distanceStyle.computeDistance(point1, x,y,z);
final double pointDistance2 = distanceStyle.computeDistance(point2, x,y,z);
final double pointDistance3 = distanceStyle.computeDistance(point3, x,y,z);
final double pointDistance4 = distanceStyle.computeDistance(point4, x,y,z);
return Math.min(
Math.min(
Math.min(planeDistance1, planeDistance2),
Math.min(planeDistance3, planeDistance4)),
Math.min(
Math.min(pointDistance1, pointDistance2),
Math.min(pointDistance3, pointDistance4)));
}
@Override
public boolean equals(Object o) {
if (!(o instanceof GeoS2Shape))
return false;
GeoS2Shape other = (GeoS2Shape) o;
return super.equals(other) && other.point1.equals(point1)
&& other.point2.equals(point2) && other.point3.equals(point3)
&& other.point4.equals(point4);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + point1.hashCode();
result = 31 * result + point2.hashCode();
result = 31 * result + point3.hashCode();
result = 31 * result + point4.hashCode();
return result;
}
@Override
public String toString() {
return "GeoS2Shape: {planetmodel="+planetModel+", point1=" + point1 +", point2=" + point2 +", point3=" + point3 +", point4=" + point4+ "}";
}
}