jpountz commented on a change in pull request #587: LUCENE-8707: Add 
LatLonShape and XYShape distance query
URL: https://github.com/apache/lucene-solr/pull/587#discussion_r358246538
 
 

 ##########
 File path: lucene/sandbox/src/java/org/apache/lucene/geo/WGS84Circle2D.java
 ##########
 @@ -0,0 +1,285 @@
+/*
+ * 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.geo;
+
+import org.apache.lucene.index.PointValues.Relation;
+import org.apache.lucene.util.SloppyMath;
+
+
+/**
+ * 2D circle implementation containing geo spatial logic.
+ *
+ * @lucene.internal
+ */
+public class WGS84Circle2D implements Component2D {
+  final Rectangle rectangle;
+  final boolean crossesDateline;
+  final double centerLat;
+  final double centerLon;
+  final double sortKey;
+  final double axisLat;
+
+  private WGS84Circle2D(double centerLon, double centerLat, double distance) {
+    this.centerLat = centerLat;
+    this.centerLon = centerLon;
+    this.rectangle = Rectangle.fromPointDistance(centerLat, centerLon, 
distance);
+    this.sortKey = GeoUtils.distanceQuerySortKey(distance);
+    this.axisLat = Rectangle.axisLat(centerLat, distance);
+    this.crossesDateline = rectangle.minLon > rectangle.maxLon;
+  }
+
+  @Override
+  public double getMinX() {
+    return rectangle.minLon;
+  }
+
+  @Override
+  public double getMaxX() {
+    return rectangle.maxLon;
+  }
+
+  @Override
+  public double getMinY() {
+    return rectangle.minLat;
+  }
+
+  @Override
+  public double getMaxY() {
+    return rectangle.maxLat;
+  }
+
+  @Override
+  public boolean contains(double x, double y) {
+    return SloppyMath.haversinSortKey(y, x, this.centerLat, this.centerLon) <= 
sortKey;
+  }
+
+  @Override
+  public Relation relate(double minX, double maxX, double minY, double maxY) {
+    if (disjoint(minX, maxX, minY, maxY)) {
+      return Relation.CELL_OUTSIDE_QUERY;
+    }
+    if (within(minX, maxX, minY, maxY)) {
+      return Relation.CELL_CROSSES_QUERY;
+    }
+    return GeoUtils.relate(minY, maxY, minX, maxX, centerLat, centerLon, 
sortKey, axisLat);
+  }
+
+  @Override
+  public Relation relateTriangle(double minX, double maxX, double minY, double 
maxY, double ax, double ay, double bx, double by, double cx, double cy) {
+    if (disjoint(minX, maxX, minY, maxY)) {
+      return Relation.CELL_OUTSIDE_QUERY;
+    }
+    if (ax == bx && bx == cx && ay == by && by == cy) {
+      // indexed "triangle" is a point: shortcut by checking contains
+      return contains(ax, ay) ? Relation.CELL_INSIDE_QUERY : 
Relation.CELL_OUTSIDE_QUERY;
+    } else if (ax == cx && ay == cy) {
+      // indexed "triangle" is a line segment: shortcut by calling appropriate 
method
+      return relateIndexedLineSegment(ax, ay, bx, by);
+    } else if (ax == bx && ay == by) {
+      // indexed "triangle" is a line segment: shortcut by calling appropriate 
method
+      return relateIndexedLineSegment(bx, by, cx, cy);
+    } else if (bx == cx && by == cy) {
+      // indexed "triangle" is a line segment: shortcut by calling appropriate 
method
+      return relateIndexedLineSegment(cx, cy, ax, ay);
+    }
+    // indexed "triangle" is a triangle:
+    return relateIndexedTriangle(minX, maxX, minY, maxY, ax, ay, bx, by, cx, 
cy);
+  }
+
+  @Override
+  public WithinRelation withinTriangle(double minX, double maxX, double minY, 
double maxY, double ax, double ay, boolean ab, double bx, double by, boolean 
bc, double cx, double cy, boolean ca) {
+    // short cut, lines and points cannot contain this type of shape
+    if ((ax == bx && ay == by) || (ax == cx && ay == cy) || (bx == cx && by == 
cy)) {
+      return WithinRelation.DISJOINT;
+    }
+
+    if (disjoint(minX, maxX, minY, maxY)) {
+      return WithinRelation.DISJOINT;
+    }
+
+    // if any of the points is inside the polygon, the polygon cannot be 
within this indexed
+    // shape because points belong to the original indexed shape.
+    if (contains(ax, ay) || contains(bx, by) || contains(cx, cy)) {
+      return WithinRelation.NOTWITHIN;
+    }
+
+    WithinRelation relation = WithinRelation.DISJOINT;
+    // if any of the edges intersects an the edge belongs to the shape then it 
cannot be within.
+    // if it only intersects edges that do not belong to the shape, then it is 
a candidate
+    // we skip edges at the dateline to support shapes crossing it
+    if (intersectsLine(ax, ay, bx, by)) {
+      if (ab == true) {
+        return WithinRelation.NOTWITHIN;
+      } else {
+        relation = WithinRelation.CANDIDATE;
+      }
+    }
+
+    if (intersectsLine(bx, by, cx, cy)) {
+      if (bc == true) {
+        return WithinRelation.NOTWITHIN;
+      } else {
+        relation = WithinRelation.CANDIDATE;
+      }
+    }
+    if (intersectsLine(cx, cy, ax, ay)) {
+      if (ca == true) {
+        return WithinRelation.NOTWITHIN;
+      } else {
+        relation = WithinRelation.CANDIDATE;
+      }
+    }
+
+    // if any of the edges crosses and edge that does not belong to the shape
+    // then it is a candidate for within
+    if (relation == WithinRelation.CANDIDATE) {
+      return WithinRelation.CANDIDATE;
+    }
+
+    // Check if shape is within the triangle
+    if (Component2D.pointInTriangle(minX, maxX, minY, maxY, centerLon, 
centerLat, ax, ay, bx, by, cx, cy) == true) {
+      return WithinRelation.CANDIDATE;
+    }
+    return relation;
+  }
+
+  /** relates an indexed line segment (a "flat triangle") with the polygon */
+  private Relation relateIndexedLineSegment(double a2x, double a2y, double 
b2x, double b2y) {
+    // check endpoints of the line segment
+    int numCorners = 0;
+    if (contains(a2x, a2y)) {
+      ++numCorners;
+    }
+    if (contains(b2x, b2y)) {
+      ++numCorners;
+    }
+
+    if (numCorners == 2) {
+      return Relation.CELL_INSIDE_QUERY;
+    } else if (numCorners == 0) {
+      if (intersectsLine(a2x, a2y, b2x, b2y)) {
+        return Relation.CELL_CROSSES_QUERY;
+      }
+      return Relation.CELL_OUTSIDE_QUERY;
+    }
+    return Relation.CELL_CROSSES_QUERY;
+  }
+
+  /** relates an indexed triangle with the polygon */
+  private Relation relateIndexedTriangle(double minX, double maxX, double 
minY, double maxY,
+                                         double ax, double ay, double bx, 
double by, double cx, double cy) {
+    // check each corner: if < 3 && > 0 are present, its cheaper than 
crossesSlowly
+    int numCorners = numberOfTriangleCorners(ax, ay, bx, by, cx, cy);
+    if (numCorners == 3) {
+      return Relation.CELL_INSIDE_QUERY;
+    } else if (numCorners == 0) {
+      if (Component2D.pointInTriangle(minX, maxX, minY, maxY, centerLon, 
centerLat, ax, ay, bx, by, cx, cy) == true) {
+        return Relation.CELL_CROSSES_QUERY;
+      }
+      if (intersectsLine(ax, ay, bx, by) || intersectsLine(bx, by, cx, cy) || 
intersectsLine(cx, cy, ax, ay)) {
+        return Relation.CELL_CROSSES_QUERY;
+      }
+      return Relation.CELL_OUTSIDE_QUERY;
+    }
+    return Relation.CELL_CROSSES_QUERY;
+  }
+
+  private int numberOfTriangleCorners(double ax, double ay, double bx, double 
by, double cx, double cy) {
+    int containsCount = 0;
+    if (contains(ax, ay)) {
+      containsCount++;
+    }
+    if (contains(bx, by)) {
+      containsCount++;
+    }
+    if (containsCount == 1) {
+      return containsCount;
+    }
 
 Review comment:
   Can you add a comment, otherwise this early exit condition looks weird in 
isolation.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@lucene.apache.org
For additional commands, e-mail: issues-h...@lucene.apache.org

Reply via email to