| /* |
| * 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.spatial.spatial4j; |
| |
| import org.apache.lucene.spatial3d.geom.GeoArea; |
| import org.apache.lucene.spatial3d.geom.GeoAreaFactory; |
| import org.apache.lucene.spatial3d.geom.GeoAreaShape; |
| import org.apache.lucene.spatial3d.geom.GeoBBox; |
| import org.apache.lucene.spatial3d.geom.GeoBBoxFactory; |
| import org.apache.lucene.spatial3d.geom.GeoPoint; |
| import org.apache.lucene.spatial3d.geom.LatLonBounds; |
| import org.locationtech.spatial4j.context.SpatialContext; |
| import org.locationtech.spatial4j.distance.DistanceUtils; |
| import org.locationtech.spatial4j.shape.Point; |
| import org.locationtech.spatial4j.shape.Rectangle; |
| import org.locationtech.spatial4j.shape.Shape; |
| import org.locationtech.spatial4j.shape.SpatialRelation; |
| |
| /** |
| * A Spatial4j Shape wrapping a {@link GeoAreaShape} ("Geo3D") -- a 3D planar geometry |
| * based Spatial4j Shape implementation. |
| * Geo3D implements shapes on the surface of a sphere or ellipsoid. |
| * |
| * @param <T> is the type of {@link GeoAreaShape} |
| * @lucene.experimental |
| */ |
| |
| public class Geo3dShape<T extends GeoAreaShape> implements Shape { |
| |
| protected final SpatialContext spatialcontext; |
| |
| protected T shape; |
| protected volatile Rectangle boundingBox = null; // lazy initialized |
| protected volatile Point center = null; // lazy initialized |
| |
| public Geo3dShape(final T shape, final SpatialContext spatialcontext) { |
| this.spatialcontext = spatialcontext; |
| this.shape = shape; |
| } |
| |
| @Override |
| public SpatialRelation relate(Shape other) { |
| int relationship; |
| if (other instanceof Geo3dShape<?>) { |
| relationship = relate((Geo3dShape<?>) other); |
| } else if (other instanceof Rectangle) { |
| relationship = relate((Rectangle) other); |
| } else if (other instanceof Point) { |
| relationship = relate((Point) other); |
| } else { |
| throw new RuntimeException("Unimplemented shape relationship determination: " + other.getClass()); |
| } |
| |
| switch (relationship) { |
| case GeoArea.DISJOINT: |
| return SpatialRelation.DISJOINT; |
| case GeoArea.OVERLAPS: |
| return (other instanceof Point ? SpatialRelation.CONTAINS : SpatialRelation.INTERSECTS); |
| case GeoArea.CONTAINS: |
| return (other instanceof Point ? SpatialRelation.CONTAINS : SpatialRelation.WITHIN); |
| case GeoArea.WITHIN: |
| return SpatialRelation.CONTAINS; |
| } |
| |
| throw new RuntimeException("Undetermined shape relationship: " + relationship); |
| } |
| |
| private int relate(Geo3dShape<?> s) { |
| return shape.getRelationship(s.shape); |
| } |
| |
| private int relate(Rectangle r) { |
| // Construct the right kind of GeoArea first |
| GeoArea geoArea = GeoAreaFactory.makeGeoArea(shape.getPlanetModel(), |
| r.getMaxY() * DistanceUtils.DEGREES_TO_RADIANS, |
| r.getMinY() * DistanceUtils.DEGREES_TO_RADIANS, |
| r.getMinX() * DistanceUtils.DEGREES_TO_RADIANS, |
| r.getMaxX() * DistanceUtils.DEGREES_TO_RADIANS); |
| |
| return geoArea.getRelationship(shape); |
| } |
| |
| private int relate(Point p) { |
| GeoPoint point = new GeoPoint(shape.getPlanetModel(), |
| p.getY() * DistanceUtils.DEGREES_TO_RADIANS, |
| p.getX() * DistanceUtils.DEGREES_TO_RADIANS); |
| |
| if (shape.isWithin(point)) { |
| return GeoArea.WITHIN; |
| } |
| return GeoArea.DISJOINT; |
| } |
| |
| @Override |
| public Rectangle getBoundingBox() { |
| Rectangle bbox = this.boundingBox;//volatile read once |
| if (bbox == null) { |
| LatLonBounds bounds = new LatLonBounds(); |
| shape.getBounds(bounds); |
| GeoBBox geoBBox = GeoBBoxFactory.makeGeoBBox(shape.getPlanetModel(), bounds); |
| bbox = new Geo3dRectangleShape(geoBBox, spatialcontext); |
| this.boundingBox = bbox; |
| } |
| return bbox; |
| } |
| |
| @Override |
| public boolean hasArea() { |
| return true; |
| } |
| |
| @Override |
| public double getArea(SpatialContext spatialContext) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public Point getCenter() { |
| Point center = this.center;//volatile read once |
| if (center == null) { |
| center = getBoundingBox().getCenter(); |
| this.center = center; |
| } |
| return center; |
| } |
| |
| @Override |
| public Shape getBuffered(double distance, SpatialContext spatialContext) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return false; |
| } |
| |
| @Override |
| public SpatialContext getContext() { |
| return spatialcontext; |
| } |
| |
| @Override |
| public String toString() { |
| return "Geo3D:" + shape.toString(); |
| } // note: the shape usually prints its planet model |
| |
| @Override |
| public boolean equals(Object o) { |
| if (!(o instanceof Geo3dShape<?>)) |
| return false; |
| final Geo3dShape<?> other = (Geo3dShape<?>) o; |
| return (other.spatialcontext.equals(spatialcontext) && other.shape.equals(shape)); |
| } |
| |
| @Override |
| public int hashCode() { |
| return spatialcontext.hashCode() + shape.hashCode(); |
| } |
| } |