You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by kw...@apache.org on 2016/04/29 02:30:45 UTC

[01/25] lucene-solr:branch_6x: First cut of new class

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6x 21aea6f60 -> 9a06fb4e2


First cut of new class


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/086330f9
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/086330f9
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/086330f9

Branch: refs/heads/branch_6x
Commit: 086330f9d624b791f4cb725a62e3f922e72b684e
Parents: 21aea6f
Author: Karl Wright <Da...@gmail.com>
Authored: Sat Apr 23 03:48:09 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:17:49 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 112 +++++++++++++++++++
 1 file changed, 112 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/086330f9/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
new file mode 100644
index 0000000..7fc53e8
--- /dev/null
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -0,0 +1,112 @@
+/*
+ * 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.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * GeoComplexPolygon objects are structures designed to handle very large numbers of edges.
+ * They perform very well in this case compared to the alternatives, which all have O(N) evaluation
+ * and O(N^2) setup times.  Complex polygons have O(N) setup times and best case O(log(N))
+ * evaluation times.
+ *
+ * The tradeoff is that these objects perform object creation when evaluating intersects() and
+ * isWithin().
+ *
+ * @lucene.internal
+ */
+class GeoComplexPolygon extends GeoBasePolygon {
+  
+  /**
+   * Create a complex polygon from multiple lists of points, and a single point which is known to be in or out of
+   * set.
+   *@param planetModel is the planet model.
+   *@param pointsList is the list of lists of edge points.  The edge points describe edges, and have an implied
+   *  return boundary, so that N edges require N points.  These points have furthermore been filtered so that
+   *  no adjacent points are identical (within the bounds of the definition used by this package).  It is assumed
+   *  that no edges intersect, but the structure can contain both outer rings as well as holes.
+   *@param testPoint is the point whose in/out of setness is known.
+   *@param testPointInSet is true if the test point is considered "within" the polygon.
+   */
+  public GeoComplexPolygon(final PlanetModel planetModel, final List<List<GeoPoint>> pointsList, final GeoPoint testPoint, final boolean testPointInSet) {
+    super(planetModel);
+    // MHL
+  }
+
+  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
+   *@param index is the index.
+   *@return the normalized index.
+   */
+  protected int legalIndex(int index) {
+    while (index >= points.size())
+      index -= points.size();
+    while (index < 0) {
+      index += points.size();
+    }
+    return index;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    // MHL
+    return false;
+  }
+  
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    // MHL
+    return false;
+  }
+
+
+  @Override
+  public void getBounds(Bounds bounds) {
+    super.getBounds(bounds);
+    // MHL
+  }
+
+  @Override
+  protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
+    // MHL
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    // MHL
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    // MHL
+  }
+
+  @Override
+  public String toString() {
+    return "GeoComplexPolygon: {planetmodel=" + planetModel + "}";
+  }
+}
+  


[11/25] lucene-solr:branch_6x: Introduce notion of inside/outside for DualCrossing.

Posted by kw...@apache.org.
Introduce notion of inside/outside for DualCrossing.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/129f6d47
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/129f6d47
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/129f6d47

Branch: refs/heads/branch_6x
Commit: 129f6d4767b0dc91612ae2d22658c302067d9f2a
Parents: 675a30b
Author: Karl Wright <Da...@gmail.com>
Authored: Tue Apr 26 07:46:44 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:23:29 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 123 ++++++++++++-------
 1 file changed, 80 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/129f6d47/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 88db3d6..7e4d01c 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -715,13 +715,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
     private boolean isSecondLeg = false;
     
     private final Plane testPointPlane;
-    private final Plane testPointAbovePlane;
-    private final Plane testPointBelowPlane;
+    private final Plane testPointInsidePlane;
+    private final Plane testPointOutsidePlane;
     private final Plane travelPlane;
-    private final Plane travelAbovePlane;
-    private final Plane travelBelowPlane;
+    private final Plane travelInsidePlane;
+    private final Plane travelOutsidePlane;
     private final Vector thePoint;
     
+    private final GeoPoint intersectionPoint;
+    
     private final SidedPlane testPointCutoffPlane;
     private final SidedPlane checkPointCutoffPlane;
     private final SidedPlane testPointOtherCutoffPlane;
@@ -732,21 +734,56 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public DualCrossingEdgeIterator(final Plane testPointPlane, final Plane testPointAbovePlane, final Plane testPointBelowPlane,
       final Plane travelPlane, final Vector testPoint, final Vector thePoint) {
       this.testPointPlane = testPointPlane;
-      this.testPointAbovePlane = testPointAbovePlane;
-      this.testPointBelowPlane = testPointBelowPlane;
       this.travelPlane = travelPlane;
       this.thePoint = thePoint;
-      this.travelAbovePlane = new Plane(travelPlane, true);
-      this.travelBelowPlane = new Plane(travelPlane, false);
       this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
       this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
       // Now, find the intersection of the check and test point planes.
       final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointPlane, testPointCutoffPlane, checkPointCutoffPlane);
       assert intersectionPoints != null : "couldn't find any intersections";
       assert intersectionPoints.length != 1 : "wrong number of intersection points";
-      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointPlane, intersectionPoints[0]);
-      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
-    
+      this.intersectionPoint = intersectionPoints[0];
+      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointPlane, intersectionPoint);
+      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoint);
+        
+      // Figure out which of the above/below planes are inside vs. outside.  To do this,
+      // we look for the point that is within the bounds of the testPointPlane and travelPlane.  The two sides that intersected there are the inside
+      // borders.
+      final Plane travelAbovePlane = new Plane(travelPlane, true);
+      final Plane travelBelowPlane = new Plane(travelPlane, false);
+      final GeoPoint[] aboveAbove = travelAbovePlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      assert aboveAbove != null : "Above + above should not be coplanar";
+      final GeoPoint[] aboveBelow = travelAbovePlane.findIntersections(planetModel, testPointBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      assert aboveBelow != null : "Above + below should not be coplanar";
+      final GeoPoint[] belowBelow = travelBelowPlane.findIntersections(planetModel, testPointBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      assert belowBelow != null : "Below + below should not be coplanar";
+      final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      assert belowAbove != null : "Below + above should not be coplanar";
+      
+      assert aboveAbove.length + aboveBelow.length + belowBelow.length + belowAbove.length == 1 : "Can be exactly one inside point";
+      
+      if (aboveAbove.length > 0) {
+        travelInsidePlane = travelAbovePlane;
+        testPointInsidePlane = testPointAbovePlane;
+        travelOutsidePlane = travelBelowPlane;
+        testPointOutsidePlane = testPointBelowPlane;
+      } else if (aboveBelow.length > 0) {
+        travelInsidePlane = travelAbovePlane;
+        testPointInsidePlane = testPointBelowPlane;
+        travelOutsidePlane = travelBelowPlane;
+        testPointOutsidePlane = testPointAbovePlane;
+      } else if (belowBelow.length > 0) {
+        travelInsidePlane = travelBelowPlane;
+        testPointInsidePlane = testPointBelowPlane;
+        travelOutsidePlane = travelAbovePlane;
+        testPointOutsidePlane = testPointAbovePlane;
+      } else {
+        travelInsidePlane = travelBelowPlane;
+        testPointInsidePlane = testPointAbovePlane;
+        travelOutsidePlane = travelAbovePlane;
+        testPointOutsidePlane = testPointBelowPlane;
+      }
+        
     }
 
     public void setSecondLeg() {
@@ -776,20 +813,20 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
     private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
       final Plane plane;
-      final Plane abovePlane;
-      final Plane belowPlane;
+      final Plane insidePlane;
+      final Plane outsidePlane;
       final SidedPlane bound1;
       final SidedPlane bound2;
       if (isSecondLeg) {
         plane = travelPlane;
-        abovePlane = travelAbovePlane;
-        belowPlane = travelBelowPlane;
+        insidePlane = travelInsidePlane;
+        outsidePlane = travelOutsidePlane;
         bound1 = checkPointCutoffPlane;
         bound2 = checkPointOtherCutoffPlane;
       } else {
         plane = testPointPlane;
-        abovePlane = testPointAbovePlane;
-        belowPlane = testPointBelowPlane;
+        insidePlane = testPointInsidePlane;
+        outsidePlane = testPointOutsidePlane;
         bound1 = testPointCutoffPlane;
         bound2 = testPointOtherCutoffPlane;
       }
@@ -800,29 +837,29 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // We have to figure out if this crossing should be counted.
         
         // Does the crossing for this edge go up, or down?  Or can't we tell?
-        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] insideIntersections = insidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] outsideIntersections = outsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
         
-        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        assert !(insideIntersections.length > 0 && outsideIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
         
-        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+        if (insideIntersections.length == 0 && outsideIntersections.length == 0) {
           return;
         }
 
-        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+        final boolean edgeCrossesInside = insideIntersections.length > 0;
 
         // This depends on the previous edge that first departs from identicalness.
         Edge assessEdge = edge;
-        GeoPoint[] assessAboveIntersections;
-        GeoPoint[] assessBelowIntersections;
+        GeoPoint[] assessInsideIntersections;
+        GeoPoint[] assessOutsideIntersections;
         while (true) {
           assessEdge = assessEdge.previous;
-          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessInsideIntersections = insidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessOutsideIntersections = outsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
 
-          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+          assert !(assessInsideIntersections.length > 0 && assessOutsideIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
 
-          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+          if (assessInsideIntersections.length == 0 && assessOutsideIntersections.length == 0) {
             continue;
           }
           break;
@@ -853,8 +890,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
         // and make an assessment that way, since a single edge can intersect the plane at more than one point.
         
-        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
-        if (assessEdgeAbove != edgeCrossesAbove) {
+        final boolean assessEdgeInside = assessInsideIntersections.length > 0;
+        if (assessEdgeInside != edgeCrossesInside) {
           crossingCount++;
         }
         
@@ -862,29 +899,29 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // Figure out if the crossing should be counted.
         
         // Does the crossing for this edge go up, or down?  Or can't we tell?
-        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] insideIntersections = insidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] outsideIntersections = outsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
         
-        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        assert !(insideIntersections.length > 0 && outsideIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
         
-        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+        if (insideIntersections.length == 0 && outsideIntersections.length == 0) {
           return;
         }
 
-        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+        final boolean edgeCrossesInside = insideIntersections.length > 0;
 
         // This depends on the previous edge that first departs from identicalness.
         Edge assessEdge = edge;
-        GeoPoint[] assessAboveIntersections;
-        GeoPoint[] assessBelowIntersections;
+        GeoPoint[] assessInsideIntersections;
+        GeoPoint[] assessOutsideIntersections;
         while (true) {
           assessEdge = assessEdge.next;
-          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessInsideIntersections = insidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessOutsideIntersections = outsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
 
-          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+          assert !(assessInsideIntersections.length > 0 && assessOutsideIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
 
-          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+          if (assessInsideIntersections.length == 0 && assessOutsideIntersections.length == 0) {
             continue;
           }
           break;
@@ -901,8 +938,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
         // and make an assessment that way, since a single edge can intersect the plane at more than one point.
 
-        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
-        if (assessEdgeAbove != edgeCrossesAbove) {
+        final boolean assessEdgeInside = assessInsideIntersections.length > 0;
+        if (assessEdgeInside != edgeCrossesInside) {
           crossingCount++;
         }
 


[09/25] lucene-solr:branch_6x: Separate the above and below planes everywhere so we can compute intersections and bounds.

Posted by kw...@apache.org.
Separate the above and below planes everywhere so we can compute intersections and bounds.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f48623de
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f48623de
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f48623de

Branch: refs/heads/branch_6x
Commit: f48623de72c5160e1c2905c1c7d88c9a73f2ec10
Parents: 6bb6b4e
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 15:50:45 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:22:59 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 43 ++++++++++++++------
 1 file changed, 31 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f48623de/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 9b6f670..a3ef6ab 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -43,8 +43,14 @@ class GeoComplexPolygon extends GeoBasePolygon {
   private final GeoPoint testPoint;
   
   private final Plane testPointXZPlane;
+  private final Plane testPointXZAbovePlane;
+  private final Plane testPointXZBelowPlane;
   private final Plane testPointYZPlane;
+  private final Plane testPointYZAbovePlane;
+  private final Plane testPointYZBelowPlane;
   private final Plane testPointXYPlane;
+  private final Plane testPointXYAbovePlane;
+  private final Plane testPointXYBelowPlane;
   
   private final GeoPoint[] edgePoints;
   private final Edge[] shapeStartEdges;
@@ -69,6 +75,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
     this.testPointYZPlane = new Plane(1.0, 0.0, 0.0, -testPoint.x);
     this.testPointXYPlane = new Plane(0.0, 0.0, 1.0, -testPoint.z);
     
+    this.testPointXZAbovePlane = new Plane(testPointXZPlane, true);
+    this.testPointXZBelowPlane = new Plane(testPointXZPlane, false);
+    this.testPointYZAbovePlane = new Plane(testPointYZPlane, true);
+    this.testPointYZBelowPlane = new Plane(testPointYZPlane, false);
+    this.testPointXYAbovePlane = new Plane(testPointXYPlane, true);
+    this.testPointXYBelowPlane = new Plane(testPointXYPlane, false);
+
     this.edgePoints = new GeoPoint[pointsList.size()];
     this.shapeStartEdges = new Edge[pointsList.size()];
     int edgePointIndex = 0;
@@ -122,7 +135,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the XZ plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXZPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXZPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
       if (!yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y)) {
         // Endpoint is on edge
@@ -133,7 +146,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the YZ plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointYZPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointYZPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
       if (!xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x)) {
         // Endpoint is on edge
@@ -144,7 +157,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the XY plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXYPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXYPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
       if (!zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z)) {
         // Endpoint is on edge
@@ -159,6 +172,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // Travel in X and Y
         // We'll do this using the testPointYZPlane, and create a travel plane for the right XZ plane.
         final Plane travelPlane = new Plane(0.0, 1.0, 0.0, -thePoint.y);
+        final Plane travelAbovePlane = new Plane(travelPlane, true);
+        final Plane travelBelowPlane = new Plane(travelPlane, false);
         // We need cutoff planes for both legs.
         final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointYZPlane, testPoint);
         final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
@@ -170,9 +185,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         xTree.traverse(testPointEdgeIterator, testPoint.x, testPoint.x);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y)) {
           // Endpoint is on edge
           return true;
@@ -182,6 +197,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // Travel in X and Z
         // We'll do this using the testPointXYPlane, and create a travel plane for the right YZ plane.
         final Plane travelPlane = new Plane(1.0, 0.0, 0.0, -thePoint.x);
+        final Plane travelAbovePlane = new Plane(travelPlane, true);
+        final Plane travelBelowPlane = new Plane(travelPlane, false);
         // We need cutoff planes for both legs.
         final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXYPlane, testPoint);
         final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
@@ -193,9 +210,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         zTree.traverse(testPointEdgeIterator, testPoint.z, testPoint.z);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x)) {
           // Endpoint is on edge
           return true;
@@ -205,6 +222,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // Travel in Y and Z
         // We'll do this using the testPointXZPlane, and create a travel plane for the right XY plane.
         final Plane travelPlane = new Plane(0.0, 0.0, 1.0, -thePoint.z);
+        final Plane travelAbovePlane = new Plane(travelPlane, true);
+        final Plane travelBelowPlane = new Plane(travelPlane, false);
         // We need cutoff planes for both legs.
         final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXZPlane, testPoint);
         final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
@@ -216,9 +235,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the first leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         yTree.traverse(testPointEdgeIterator, testPoint.y, testPoint.y);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z)) {
           // Endpoint is on edge
           return true;
@@ -589,10 +608,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     public int crossingCount = 0;
     
-    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2, final Vector thePoint) {
+    public CrossingEdgeIterator(final Plane plane, final Plane abovePlane, final Plane belowPlane, final Membership bound1, final Membership bound2, final Vector thePoint) {
       this.plane = plane;
-      this.abovePlane = new Plane(plane, true);
-      this.belowPlane = new Plane(plane, false);
+      this.abovePlane = abovePlane;
+      this.belowPlane = belowPlane;
       this.bound1 = bound1;
       this.bound2 = bound2;
       this.thePoint = thePoint;


[23/25] lucene-solr:branch_6x: Finish debugging simple case

Posted by kw...@apache.org.
Finish debugging simple case


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/bad7eb52
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/bad7eb52
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/bad7eb52

Branch: refs/heads/branch_6x
Commit: bad7eb5280494e697ef0a2ee20a619ae0a846ac6
Parents: fbb9845
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 19:20:03 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:26:38 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 217 ++++++++++---------
 .../lucene/spatial3d/geom/GeoPolygonTest.java   |   3 -
 2 files changed, 117 insertions(+), 103 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bad7eb52/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index c218776..661953a 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -40,15 +40,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
   private final boolean testPointInSet;
   private final GeoPoint testPoint;
   
-  private final Plane testPointXZPlane;
-  private final Plane testPointXZAbovePlane;
-  private final Plane testPointXZBelowPlane;
-  private final Plane testPointYZPlane;
-  private final Plane testPointYZAbovePlane;
-  private final Plane testPointYZBelowPlane;
-  private final Plane testPointXYPlane;
-  private final Plane testPointXYAbovePlane;
-  private final Plane testPointXYBelowPlane;
+  private final Plane testPointFixedYPlane;
+  private final Plane testPointFixedYAbovePlane;
+  private final Plane testPointFixedYBelowPlane;
+  private final Plane testPointFixedXPlane;
+  private final Plane testPointFixedXAbovePlane;
+  private final Plane testPointFixedXBelowPlane;
+  private final Plane testPointFixedZPlane;
+  private final Plane testPointFixedZAbovePlane;
+  private final Plane testPointFixedZBelowPlane;
   
   private final GeoPoint[] edgePoints;
   private final Edge[] shapeStartEdges;
@@ -69,16 +69,16 @@ class GeoComplexPolygon extends GeoBasePolygon {
     this.testPointInSet = testPointInSet;
     this.testPoint = testPoint;
     
-    this.testPointXZPlane = new Plane(0.0, 1.0, 0.0, -testPoint.y);
-    this.testPointYZPlane = new Plane(1.0, 0.0, 0.0, -testPoint.x);
-    this.testPointXYPlane = new Plane(0.0, 0.0, 1.0, -testPoint.z);
+    this.testPointFixedYPlane = new Plane(0.0, 1.0, 0.0, -testPoint.y);
+    this.testPointFixedXPlane = new Plane(1.0, 0.0, 0.0, -testPoint.x);
+    this.testPointFixedZPlane = new Plane(0.0, 0.0, 1.0, -testPoint.z);
     
-    this.testPointXZAbovePlane = new Plane(testPointXZPlane, true);
-    this.testPointXZBelowPlane = new Plane(testPointXZPlane, false);
-    this.testPointYZAbovePlane = new Plane(testPointYZPlane, true);
-    this.testPointYZBelowPlane = new Plane(testPointYZPlane, false);
-    this.testPointXYAbovePlane = new Plane(testPointXYPlane, true);
-    this.testPointXYBelowPlane = new Plane(testPointXYPlane, false);
+    this.testPointFixedYAbovePlane = new Plane(testPointFixedYPlane, true);
+    this.testPointFixedYBelowPlane = new Plane(testPointFixedYPlane, false);
+    this.testPointFixedXAbovePlane = new Plane(testPointFixedXPlane, true);
+    this.testPointFixedXBelowPlane = new Plane(testPointFixedXPlane, false);
+    this.testPointFixedZAbovePlane = new Plane(testPointFixedZPlane, true);
+    this.testPointFixedZBelowPlane = new Plane(testPointFixedZPlane, false);
 
     this.edgePoints = new GeoPoint[pointsList.size()];
     this.shapeStartEdges = new Edge[pointsList.size()];
@@ -124,27 +124,27 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     // If we're right on top of any of the test planes, we navigate solely on that plane.
-    if (testPointXZPlane.evaluateIsZero(thePoint)) {
+    if (testPointFixedYPlane.evaluateIsZero(thePoint)) {
       // Use the XZ plane exclusively.
-      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPoint, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointFixedYPlane, testPointFixedYAbovePlane, testPointFixedYBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
       if (!yTree.traverse(crossingEdgeIterator, testPoint.y)) {
         // Endpoint is on edge
         return true;
       }
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
-    } else if (testPointYZPlane.evaluateIsZero(thePoint)) {
+    } else if (testPointFixedXPlane.evaluateIsZero(thePoint)) {
       // Use the YZ plane exclusively.
-      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPoint, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointFixedXPlane, testPointFixedXAbovePlane, testPointFixedXBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
       if (!xTree.traverse(crossingEdgeIterator, testPoint.x)) {
         // Endpoint is on edge
         return true;
       }
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
-    } else if (testPointXYPlane.evaluateIsZero(thePoint)) {
+    } else if (testPointFixedZPlane.evaluateIsZero(thePoint)) {
       // Use the XY plane exclusively.
-      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPoint, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointFixedZPlane, testPointFixedZAbovePlane, testPointFixedZBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
       if (!zTree.traverse(crossingEdgeIterator, testPoint.z)) {
         // Endpoint is on edge
@@ -153,20 +153,18 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else {
       
-      System.err.println("isWithin() for check point "+thePoint+", test point "+testPoint);
-      
       // We need to use two planes to get there.  We don't know which two planes will do it but we can figure it out.
       final Plane travelPlaneFixedX = new Plane(1.0, 0.0, 0.0, -thePoint.x);
       final Plane travelPlaneFixedY = new Plane(0.0, 1.0, 0.0, -thePoint.y);
       final Plane travelPlaneFixedZ = new Plane(0.0, 0.0, 1.0, -thePoint.z);
 
       // Find the intersection points for each one of these and the complementary test point planes.
-      final GeoPoint[] XZIntersectionsYZ = travelPlaneFixedX.findIntersections(planetModel, testPointYZPlane);
-      final GeoPoint[] XZIntersectionsXY = travelPlaneFixedX.findIntersections(planetModel, testPointXYPlane);
-      final GeoPoint[] YZIntersectionsXZ = travelPlaneFixedY.findIntersections(planetModel, testPointXZPlane);
-      final GeoPoint[] YZIntersectionsXY = travelPlaneFixedY.findIntersections(planetModel, testPointXYPlane);
-      final GeoPoint[] XYIntersectionsYZ = travelPlaneFixedZ.findIntersections(planetModel, testPointYZPlane);
-      final GeoPoint[] XYIntersectionsXZ = travelPlaneFixedZ.findIntersections(planetModel, testPointXZPlane);
+      final GeoPoint[] XIntersectionsY = travelPlaneFixedX.findIntersections(planetModel, testPointFixedYPlane);
+      final GeoPoint[] XIntersectionsZ = travelPlaneFixedX.findIntersections(planetModel, testPointFixedZPlane);
+      final GeoPoint[] YIntersectionsX = travelPlaneFixedY.findIntersections(planetModel, testPointFixedXPlane);
+      final GeoPoint[] YIntersectionsZ = travelPlaneFixedY.findIntersections(planetModel, testPointFixedZPlane);
+      final GeoPoint[] ZIntersectionsX = travelPlaneFixedZ.findIntersections(planetModel, testPointFixedXPlane);
+      final GeoPoint[] ZIntersectionsY = travelPlaneFixedZ.findIntersections(planetModel, testPointFixedYPlane);
 
       // There will be multiple intersection points found.  We choose the one that has the lowest total distance, as measured in delta X, delta Y, and delta Z.
       double bestDistance = Double.MAX_VALUE;
@@ -180,107 +178,106 @@ class GeoComplexPolygon extends GeoBasePolygon {
       Tree secondLegTree = null;
       GeoPoint intersectionPoint = null;
       
-      for (final GeoPoint p : XZIntersectionsYZ) {
-        // Travel would be in XZ plane (fixed y) then in YZ (fixed x)
-        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.x - p.x);
+      for (final GeoPoint p : XIntersectionsY) {
+        // Travel would be in YZ plane (fixed x) then in XZ (fixed y)
+        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.y - p.y);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.y;
           secondLegValue = thePoint.x;
-          firstLegPlane = testPointXZPlane;
-          firstLegAbovePlane = testPointXZAbovePlane;
-          firstLegBelowPlane = testPointXZBelowPlane;
+          firstLegPlane = testPointFixedYPlane;
+          firstLegAbovePlane = testPointFixedYAbovePlane;
+          firstLegBelowPlane = testPointFixedYBelowPlane;
           secondLegPlane = travelPlaneFixedX;
           firstLegTree = yTree;
           secondLegTree = xTree;
           intersectionPoint = p;
         }
       }
-      for (final GeoPoint p : XZIntersectionsXY) {
-        // Travel would be in XZ plane (fixed y) then in XY (fixed z)
-        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.z - p.z);
+      for (final GeoPoint p : XIntersectionsZ) {
+        // Travel would be in YZ plane (fixed x) then in XY (fixed z)
+        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.z - p.z);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
-          firstLegValue = testPoint.y;
-          secondLegValue = thePoint.z;
-          firstLegPlane = testPointXZPlane;
-          firstLegAbovePlane = testPointXZAbovePlane;
-          firstLegBelowPlane = testPointXZBelowPlane;
-          secondLegPlane = travelPlaneFixedZ;
-          firstLegTree = yTree;
-          secondLegTree = zTree;
+          firstLegValue = testPoint.z;
+          secondLegValue = thePoint.x;
+          firstLegPlane = testPointFixedZPlane;
+          firstLegAbovePlane = testPointFixedZAbovePlane;
+          firstLegBelowPlane = testPointFixedZBelowPlane;
+          secondLegPlane = travelPlaneFixedX;
+          firstLegTree = zTree;
+          secondLegTree = xTree;
           intersectionPoint = p;
         }
       }
-      for (final GeoPoint p : YZIntersectionsXZ) {
-        // Travel would be in YZ plane (fixed x) then in XZ (fixed y)
-        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.y - p.y);
+      for (final GeoPoint p : YIntersectionsX) {
+        // Travel would be in XZ plane (fixed y) then in YZ (fixed x)
+        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.x - p.x);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.x;
           secondLegValue = thePoint.y;
-          firstLegPlane = testPointYZPlane;
-          firstLegAbovePlane = testPointYZAbovePlane;
-          firstLegBelowPlane = testPointYZBelowPlane;
+          firstLegPlane = testPointFixedXPlane;
+          firstLegAbovePlane = testPointFixedXAbovePlane;
+          firstLegBelowPlane = testPointFixedXBelowPlane;
           secondLegPlane = travelPlaneFixedY;
           firstLegTree = xTree;
           secondLegTree = yTree;
           intersectionPoint = p;
         }
       }
-      for (final GeoPoint p : YZIntersectionsXY) {
-        // Travel would be in YZ plane (fixed x) then in XY (fixed z)
-        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.z - p.z);
+      for (final GeoPoint p : YIntersectionsZ) {
+        // Travel would be in XZ plane (fixed y) then in XY (fixed z)
+        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.z - p.z);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
-          firstLegValue = testPoint.x;
-          secondLegValue = thePoint.z;
-          firstLegPlane = testPointYZPlane;
-          firstLegAbovePlane = testPointYZAbovePlane;
-          firstLegBelowPlane = testPointYZBelowPlane;
-          secondLegPlane = travelPlaneFixedZ;
-          firstLegTree = xTree;
-          secondLegTree = zTree;
+          firstLegValue = testPoint.z;
+          secondLegValue = thePoint.y;
+          firstLegPlane = testPointFixedZPlane;
+          firstLegAbovePlane = testPointFixedZAbovePlane;
+          firstLegBelowPlane = testPointFixedZBelowPlane;
+          secondLegPlane = travelPlaneFixedY;
+          firstLegTree = zTree;
+          secondLegTree = yTree;
           intersectionPoint = p;
         }
       }
-      for (final GeoPoint p : XYIntersectionsYZ) {
+      for (final GeoPoint p : ZIntersectionsX) {
         // Travel would be in XY plane (fixed z) then in YZ (fixed x)
         final double newDistance = Math.abs(testPoint.z - p.z) + Math.abs(thePoint.x - p.x);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
-          firstLegValue = testPoint.z;
-          secondLegValue = thePoint.x;
-          firstLegPlane = testPointXYPlane;
-          firstLegAbovePlane = testPointXYAbovePlane;
-          firstLegBelowPlane = testPointXYBelowPlane;
-          secondLegPlane = travelPlaneFixedX;
-          firstLegTree = zTree;
-          secondLegTree = xTree;
+          firstLegValue = testPoint.x;
+          secondLegValue = thePoint.z;
+          firstLegPlane = testPointFixedXPlane;
+          firstLegAbovePlane = testPointFixedXAbovePlane;
+          firstLegBelowPlane = testPointFixedXBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
+          firstLegTree = xTree;
+          secondLegTree = zTree;
           intersectionPoint = p;
         }
       }
-      for (final GeoPoint p : XYIntersectionsXZ) {
+      for (final GeoPoint p : ZIntersectionsY) {
         // Travel would be in XY plane (fixed z) then in XZ (fixed y)
         final double newDistance = Math.abs(testPoint.z - p.z) + Math.abs(thePoint.y - p.y);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
-          firstLegValue = testPoint.z;
-          secondLegValue = thePoint.y;
-          firstLegPlane = testPointXYPlane;
-          firstLegAbovePlane = testPointXYAbovePlane;
-          firstLegBelowPlane = testPointXYBelowPlane;
-          secondLegPlane = travelPlaneFixedY;
-          firstLegTree = zTree;
-          secondLegTree = yTree;
+          firstLegValue = testPoint.y;
+          secondLegValue = thePoint.z;
+          firstLegPlane = testPointFixedYPlane;
+          firstLegAbovePlane = testPointFixedYAbovePlane;
+          firstLegBelowPlane = testPointFixedYBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
+          firstLegTree = yTree;
+          secondLegTree = zTree;
           intersectionPoint = p;
         }
       }
 
+      assert bestDistance > 0.0 : "Best distance should not be zero unless on single plane";
       assert bestDistance < Double.MAX_VALUE : "Couldn't find an intersection point of any kind";
       
-      System.err.println("Best distance: "+bestDistance);
-      
       final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(firstLegPlane, firstLegAbovePlane, firstLegBelowPlane, secondLegPlane, testPoint, thePoint, intersectionPoint);
       if (!firstLegTree.traverse(edgeIterator, firstLegValue)) {
         return true;
@@ -392,7 +389,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.planeBounds.addPoint(startPoint);
       this.planeBounds.addPoint(endPoint);
       this.plane.recordBounds(pm, this.planeBounds, this.startPlane, this.endPlane);
-      System.err.println("Recording edge "+this+" from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
+      //System.err.println("Recording edge "+this+" from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
     }
   }
   
@@ -632,12 +629,14 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public ZTree() {
     }
     
+    /*
     @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double value) {
       System.err.println("Traversing in Z, value= "+value+"...");
       return super.traverse(edgeIterator, value);
     }
-
+    */
+    
     @Override
     protected double getMinimum(final Edge edge) {
       return edge.planeBounds.getMinimumZ();
@@ -657,11 +656,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public YTree() {
     }
 
+    /*
     @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double value) {
       System.err.println("Traversing in Y, value= "+value+"...");
       return super.traverse(edgeIterator, value);
     }
+    */
     
     @Override
     protected double getMinimum(final Edge edge) {
@@ -682,11 +683,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public XTree() {
     }
     
+    /*
     @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double value) {
       System.err.println("Traversing in X, value= "+value+"...");
       return super.traverse(edgeIterator, value);
     }
+    */
     
     @Override
     protected double getMinimum(final Edge edge) {
@@ -909,6 +912,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.thePoint = thePoint;
       this.intersectionPoint = intersectionPoint;
       
+      //System.err.println("Intersection point = "+intersectionPoint);
+        
+      assert travelPlane.evaluateIsZero(intersectionPoint) : "intersection point must be on travel plane";
+      assert testPointPlane.evaluateIsZero(intersectionPoint) : "intersection point must be on test point plane";
+        
       assert !testPoint.isNumericallyIdentical(intersectionPoint) : "test point is the same as intersection point";
       assert !thePoint.isNumericallyIdentical(intersectionPoint) : "check point is same is intersection point";
 
@@ -981,10 +989,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     @Override
     public boolean matches(final Edge edge) {
-      System.err.println("Processing edge "+edge+", startpoint="+edge.startPoint+" endpoint="+edge.endPoint);
+      //System.err.println("Processing edge "+edge+", startpoint="+edge.startPoint+" endpoint="+edge.endPoint);
       // Early exit if the point is on the edge.
       if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
-        System.err.println(" Check point is on edge: isWithin = true");
+        //System.err.println(" Check point is on edge: isWithin = true");
         return false;
       }
       // If the intersection point lies on this edge, we should still be able to consider crossing points only.
@@ -992,10 +1000,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // for at least one of the two planes in order to be a legitimate crossing of the combined path.
       final GeoPoint[] crossingPoints;
       if (isSecondLeg) {
-        System.err.println(" check point plane = "+travelPlane);
+        //System.err.println(" check point plane = "+travelPlane);
         crossingPoints = travelPlane.findCrossings(planetModel, edge.plane, checkPointCutoffPlane, checkPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
       } else {
-        System.err.println(" test point plane = "+testPointPlane);
+        //System.err.println(" test point plane = "+testPointPlane);
         crossingPoints = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
       }
       if (crossingPoints != null) {
@@ -1003,15 +1011,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
         for (final GeoPoint crossingPoint : crossingPoints) {
           countCrossingPoint(crossingPoint, edge);
         }
-        System.err.println(" All crossing points processed");
+        //System.err.println(" All crossing points processed");
       } else {
-        System.err.println(" No crossing points!");
+        //System.err.println(" No crossing points!");
       }
       return true;
     }
 
     private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
-      System.err.println(" Crossing point "+crossingPoint);
+      //System.err.println(" Crossing point "+crossingPoint);
       // We consider crossing points only in this method.
       // Unlike the linear case, there are additional cases when:
       // (1) The crossing point and the intersection point are the same, but are not the endpoint of an edge;
@@ -1025,14 +1033,14 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // In either case, we have to be sure to count each edge only once, since it might appear in both the
       // first leg and the second.  If the first leg can process it, it should, and the second should skip it.
       if (crossingPoint.isNumericallyIdentical(intersectionPoint)) {
-        System.err.println(" Crosses intersection point.");
+        //System.err.println(" Crosses intersection point.");
         if (isSecondLeg) {
           // See whether this edge would have been processed in the first leg; if so, we skip it.
           final GeoPoint[] firstLegCrossings = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
           for (final GeoPoint firstLegCrossing : firstLegCrossings) {
             if (firstLegCrossing.isNumericallyIdentical(intersectionPoint)) {
               // We already processed it, so we're done here.
-              System.err.println("  Already processed on previous leg: exit");
+              //System.err.println("  Already processed on previous leg: exit");
               return;
             }
           }
@@ -1061,7 +1069,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
         
       if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
-        System.err.println(" Crossing point = edge.startPoint");
+        //System.err.println(" Crossing point = edge.startPoint");
         // We have to figure out if this crossing should be counted.
           
         // Does the crossing for this edge go up, or down?  Or can't we tell?
@@ -1073,6 +1081,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
           
         if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
+          //System.err.println(" No inside or outside crossings found");
           return;
         }
 
@@ -1117,6 +1126,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
             // Found it!
             // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
             // Since we're the latter point, we exit here in that case.
+            //System.err.println(" Earlier point fired, so this one shouldn't");
             return;
           }
         }
@@ -1127,11 +1137,14 @@ class GeoComplexPolygon extends GeoBasePolygon {
           
         final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
         if (assessEdgeInside != edgeCrossesInside) {
+          //System.err.println(" Incrementing crossing count");
           crossingCount++;
+        } else {
+          //System.err.println(" Entered and exited on same side");
         }
           
       } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
-        System.err.println(" Crossing point = edge.endPoint");
+        //System.err.println(" Crossing point = edge.endPoint");
         // Figure out if the crossing should be counted.
           
         // Does the crossing for this edge go up, or down?  Or can't we tell?
@@ -1144,6 +1157,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         //assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't go both up and down: insideTestPointPlaneIntersections: "+insideTestPointPlaneIntersections.length+" insideTravelPlaneIntersections: "+insideTravelPlaneIntersections.length+" outsideTestPointPlaneIntersections: "+outsideTestPointPlaneIntersections.length+" outsideTravelPlaneIntersections: "+outsideTravelPlaneIntersections.length;
           
         if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
+          //System.err.println(" No inside or outside crossings found");
           return;
         }
 
@@ -1183,10 +1197,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
         final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
         if (assessEdgeInside != edgeCrossesInside) {
+          //System.err.println(" Incrementing crossing count");
           crossingCount++;
+        } else {
+          //System.err.println(" Entered and exited on same side");
         }
       } else {
-        System.err.println(" Not a special case: incrementing crossing count");
+        //System.err.println(" Not a special case: incrementing crossing count");
         // Not a special case, so we can safely count a crossing.
         crossingCount++;
       }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bad7eb52/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index 53fc246..b325e43 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -189,9 +189,6 @@ public class GeoPolygonTest {
     shapes.add(new GeoPolygonFactory.PolygonDescription(points));
     
     c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
-    assertFalse(c.isWithin(gp));
-
     // Sample some points within
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
     assertTrue(c.isWithin(gp));


[10/25] lucene-solr:branch_6x: Have two separate crossing counters; one for dual leg, one for single.

Posted by kw...@apache.org.
Have two separate crossing counters; one for dual leg, one for single.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/675a30b8
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/675a30b8
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/675a30b8

Branch: refs/heads/branch_6x
Commit: 675a30b8f7c407f5a7b228fa7a4a93cc3b29842b
Parents: f48623d
Author: Karl Wright <Da...@gmail.com>
Authored: Tue Apr 26 02:46:03 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:23:14 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 306 ++++++++++++++-----
 1 file changed, 234 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/675a30b8/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index a3ef6ab..88db3d6 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -133,9 +133,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     // If we're right on top of any of the test planes, we navigate solely on that plane.
     if (testPointXZPlane.evaluateIsZero(thePoint)) {
       // Use the XZ plane exclusively.
-      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXZPlane, testPoint);
-      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXZPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
       if (!yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y)) {
         // Endpoint is on edge
@@ -144,9 +142,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else if (testPointYZPlane.evaluateIsZero(thePoint)) {
       // Use the YZ plane exclusively.
-      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointYZPlane, testPoint);
-      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointYZPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
       if (!xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x)) {
         // Endpoint is on edge
@@ -155,9 +151,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else if (testPointXYPlane.evaluateIsZero(thePoint)) {
       // Use the XY plane exclusively.
-      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXYPlane, testPoint);
-      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXYPlane, thePoint);
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPointCutoff, checkPointCutoff, thePoint);
+      final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
       if (!zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z)) {
         // Endpoint is on edge
@@ -172,77 +166,41 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // Travel in X and Y
         // We'll do this using the testPointYZPlane, and create a travel plane for the right XZ plane.
         final Plane travelPlane = new Plane(0.0, 1.0, 0.0, -thePoint.y);
-        final Plane travelAbovePlane = new Plane(travelPlane, true);
-        final Plane travelBelowPlane = new Plane(travelPlane, false);
-        // We need cutoff planes for both legs.
-        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointYZPlane, testPoint);
-        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
-        // Now, find the intersection of the check and test point planes.
-        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointYZPlane, testPointCutoffPlane, checkPointCutoffPlane);
-        assert intersectionPoints != null : "couldn't find any intersections";
-        assert intersectionPoints.length != 1 : "wrong number of intersection points";
-        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointYZPlane, intersectionPoints[0]);
-        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
-        // Note: we need to handle the cases where end point of the leg sits on an edge!
-        // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
-        xTree.traverse(testPointEdgeIterator, testPoint.x, testPoint.x);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
-        if (!yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y)) {
-          // Endpoint is on edge
+        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, travelPlane, testPoint, thePoint);
+        if (!xTree.traverse(edgeIterator, testPoint.x, testPoint.x)) {
           return true;
         }
-        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
+        edgeIterator.setSecondLeg();
+        if (!yTree.traverse(edgeIterator, thePoint.y, thePoint.y)) {
+          return true;
+        }
+        return ((edgeIterator.crossingCount  & 1) == 0)?testPointInSet:!testPointInSet;
       } else if (xDelta + zDelta <= xDelta + yDelta && xDelta + zDelta <= zDelta + yDelta) {
         // Travel in X and Z
         // We'll do this using the testPointXYPlane, and create a travel plane for the right YZ plane.
         final Plane travelPlane = new Plane(1.0, 0.0, 0.0, -thePoint.x);
-        final Plane travelAbovePlane = new Plane(travelPlane, true);
-        final Plane travelBelowPlane = new Plane(travelPlane, false);
-        // We need cutoff planes for both legs.
-        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXYPlane, testPoint);
-        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
-        // Now, find the intersection of the check and test point planes.
-        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointXYPlane, testPointCutoffPlane, checkPointCutoffPlane);
-        assert intersectionPoints != null : "couldn't find any intersections";
-        assert intersectionPoints.length != 1 : "wrong number of intersection points";
-        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointXYPlane, intersectionPoints[0]);
-        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
-        // Note: we need to handle the cases where end point of the leg sits on an edge!
-        // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
-        zTree.traverse(testPointEdgeIterator, testPoint.z, testPoint.z);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
-        if (!xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x)) {
-          // Endpoint is on edge
+        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, travelPlane, testPoint, thePoint);
+        if (!zTree.traverse(edgeIterator, testPoint.z, testPoint.z)) {
           return true;
         }
-        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
+        edgeIterator.setSecondLeg();
+        if (!xTree.traverse(edgeIterator, thePoint.x, thePoint.x)) {
+          return true;
+        }
+        return ((edgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
       } else if (yDelta + zDelta <= xDelta + yDelta && yDelta + zDelta <= xDelta + zDelta) {
         // Travel in Y and Z
         // We'll do this using the testPointXZPlane, and create a travel plane for the right XY plane.
         final Plane travelPlane = new Plane(0.0, 0.0, 1.0, -thePoint.z);
-        final Plane travelAbovePlane = new Plane(travelPlane, true);
-        final Plane travelBelowPlane = new Plane(travelPlane, false);
-        // We need cutoff planes for both legs.
-        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXZPlane, testPoint);
-        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
-        // Now, find the intersection of the check and test point planes.
-        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointXZPlane, testPointCutoffPlane, checkPointCutoffPlane);
-        assert intersectionPoints != null : "couldn't find any intersections";
-        assert intersectionPoints.length != 1 : "wrong number of intersection points";
-        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointXZPlane, intersectionPoints[0]);
-        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
-        // Note: we need to handle the cases where end point of the first leg sits on an edge!
-        // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
-        yTree.traverse(testPointEdgeIterator, testPoint.y, testPoint.y);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, travelAbovePlane, travelBelowPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
-        if (!zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z)) {
-          // Endpoint is on edge
+        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, travelPlane, testPoint, thePoint);
+        if (!yTree.traverse(edgeIterator, testPoint.y, testPoint.y)) {
+          return true;
+        }
+        edgeIterator.setSecondLeg();
+        if (!zTree.traverse(edgeIterator, thePoint.z, thePoint.z)) {
           return true;
         }
-        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
+        return ((edgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
       }
     }
     return false;
@@ -597,7 +555,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
   
   /** Count the number of verifiable edge crossings.
    */
-  private class CrossingEdgeIterator implements EdgeIterator {
+  private class LinearCrossingEdgeIterator implements EdgeIterator {
     
     private final Plane plane;
     private final Plane abovePlane;
@@ -608,12 +566,12 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     public int crossingCount = 0;
     
-    public CrossingEdgeIterator(final Plane plane, final Plane abovePlane, final Plane belowPlane, final Membership bound1, final Membership bound2, final Vector thePoint) {
+    public LinearCrossingEdgeIterator(final Plane plane, final Plane abovePlane, final Plane belowPlane, final Vector testPoint, final Vector thePoint) {
       this.plane = plane;
       this.abovePlane = abovePlane;
       this.belowPlane = belowPlane;
-      this.bound1 = bound1;
-      this.bound2 = bound2;
+      this.bound1 = new SidedPlane(thePoint, plane, testPoint);
+      this.bound2 = new SidedPlane(testPoint, plane, thePoint);
       this.thePoint = thePoint;
     }
     
@@ -627,13 +585,217 @@ class GeoComplexPolygon extends GeoBasePolygon {
       if (crossingPoints != null) {
         // We need to handle the endpoint case, which is quite tricky.
         for (final GeoPoint crossingPoint : crossingPoints) {
-          countCrossingPoint(crossingPoint, plane, edge);
+          countCrossingPoint(crossingPoint, edge);
+        }
+      }
+      return true;
+    }
+
+    private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
+      if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
+        // We have to figure out if this crossing should be counted.
+        
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        
+        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        
+        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+          return;
+        }
+
+        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessAboveIntersections;
+        GeoPoint[] assessBelowIntersections;
+        while (true) {
+          assessEdge = assessEdge.previous;
+          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+            continue;
+          }
+          break;
+        }
+        
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        
+        // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
+        // a decision whether to count or not based on that.
+        
+        // Compute the crossing points of this other edge.
+        final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
+        
+        // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
+        // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
+        for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
+          if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
+            // Found it!
+            // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
+            // Since we're the latter point, we exit here in that case.
+            return;
+          }
+        }
+        
+        // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+        
+        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
+        if (assessEdgeAbove != edgeCrossesAbove) {
+          crossingCount++;
+        }
+        
+      } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
+        // Figure out if the crossing should be counted.
+        
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        
+        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        
+        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+          return;
+        }
+
+        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessAboveIntersections;
+        GeoPoint[] assessBelowIntersections;
+        while (true) {
+          assessEdge = assessEdge.next;
+          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+            continue;
+          }
+          break;
+        }
+        
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        
+        // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
+        // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
+        
+        // We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+
+        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
+        if (assessEdgeAbove != edgeCrossesAbove) {
+          crossingCount++;
+        }
+
+      } else {
+        crossingCount++;
+      }
+    }
+  }
+  
+  /** Count the number of verifiable edge crossings for a dual-leg journey.
+   */
+  private class DualCrossingEdgeIterator implements EdgeIterator {
+    
+    private boolean isSecondLeg = false;
+    
+    private final Plane testPointPlane;
+    private final Plane testPointAbovePlane;
+    private final Plane testPointBelowPlane;
+    private final Plane travelPlane;
+    private final Plane travelAbovePlane;
+    private final Plane travelBelowPlane;
+    private final Vector thePoint;
+    
+    private final SidedPlane testPointCutoffPlane;
+    private final SidedPlane checkPointCutoffPlane;
+    private final SidedPlane testPointOtherCutoffPlane;
+    private final SidedPlane checkPointOtherCutoffPlane;
+
+    public int crossingCount = 0;
+
+    public DualCrossingEdgeIterator(final Plane testPointPlane, final Plane testPointAbovePlane, final Plane testPointBelowPlane,
+      final Plane travelPlane, final Vector testPoint, final Vector thePoint) {
+      this.testPointPlane = testPointPlane;
+      this.testPointAbovePlane = testPointAbovePlane;
+      this.testPointBelowPlane = testPointBelowPlane;
+      this.travelPlane = travelPlane;
+      this.thePoint = thePoint;
+      this.travelAbovePlane = new Plane(travelPlane, true);
+      this.travelBelowPlane = new Plane(travelPlane, false);
+      this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
+      this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
+      // Now, find the intersection of the check and test point planes.
+      final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointPlane, testPointCutoffPlane, checkPointCutoffPlane);
+      assert intersectionPoints != null : "couldn't find any intersections";
+      assert intersectionPoints.length != 1 : "wrong number of intersection points";
+      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointPlane, intersectionPoints[0]);
+      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
+    
+    }
+
+    public void setSecondLeg() {
+      isSecondLeg = true;
+    }
+    
+    @Override
+    public boolean matches(final Edge edge) {
+      // Early exit if the point is on the edge.
+      if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
+        return false;
+      }
+      final GeoPoint[] crossingPoints;
+      if (isSecondLeg) {
+        crossingPoints = travelPlane.findCrossings(planetModel, edge.plane, checkPointCutoffPlane, checkPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
+      } else {
+        crossingPoints = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
+      }
+      if (crossingPoints != null) {
+        // We need to handle the endpoint case, which is quite tricky.
+        for (final GeoPoint crossingPoint : crossingPoints) {
+          countCrossingPoint(crossingPoint, edge);
         }
       }
       return true;
     }
 
-    private void countCrossingPoint(final GeoPoint crossingPoint, final Plane plane, final Edge edge) {
+    private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
+      final Plane plane;
+      final Plane abovePlane;
+      final Plane belowPlane;
+      final SidedPlane bound1;
+      final SidedPlane bound2;
+      if (isSecondLeg) {
+        plane = travelPlane;
+        abovePlane = travelAbovePlane;
+        belowPlane = travelBelowPlane;
+        bound1 = checkPointCutoffPlane;
+        bound2 = checkPointOtherCutoffPlane;
+      } else {
+        plane = testPointPlane;
+        abovePlane = testPointAbovePlane;
+        belowPlane = testPointBelowPlane;
+        bound1 = testPointCutoffPlane;
+        bound2 = testPointOtherCutoffPlane;
+      }
+      
+      // MHL - this code below is temporary code copied from LinearCrossing above
+      
       if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
         // We have to figure out if this crossing should be counted.
         


[13/25] lucene-solr:branch_6x: Add GeoPolygonFactory support for the new shape.

Posted by kw...@apache.org.
Add GeoPolygonFactory support for the new shape.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/9688932c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/9688932c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/9688932c

Branch: refs/heads/branch_6x
Commit: 9688932c32e564036d7b3e9a5b4230c5df11fb1d
Parents: 65dc8ed
Author: Karl Wright <Da...@gmail.com>
Authored: Tue Apr 26 08:56:53 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:24:03 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoPolygonFactory.java       | 109 ++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9688932c/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
index fea5b89..ff658c6 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -115,7 +115,114 @@ public class GeoPolygonFactory {
     }
     throw new IllegalArgumentException("cannot find a point that is inside the polygon "+filteredPointList);
   }
+  
+  /** Use this class to specify a polygon with associated holes.
+   */
+  public static class PolygonDescription {
+    /** The list of points */
+    public final List<? extends GeoPoint> points;
+    /** The list of holes */
+    public final List<? extends PolygonDescription> holes;
+    
+    /** Instantiate the polygon description.
+     * @param points is the list of points.
+     * @param holes is the list of holes.
+     */
+    public PolygonDescription(final List<? extends GeoPoint> points, final List<? extends PolygonDescription> holes) {
+      this.points = points;
+      this.holes = holes;
+    }
+    
+  }
+  
+  /** Create a large GeoPolygon.  This is one which has more than 100 sides and/or may have resolution problems
+   * with very closely spaced points, which often occurs when the polygon was constructed to approximate curves.  No tiling
+   * is done, and intersections and membership are optimized for having large numbers of sides.
+   *
+   * This method does very little checking for legality.  It expects the incoming shapes to not intersect
+   * each other.  The shapes can be disjoint or nested.  If the shapes listed are nested, then we are describing holes.
+   * There is no limit to the depth of holes.  However, if a shape is nested within another it must be explicitly
+   * described as being a child of the other shape.
+   *
+   * Membership in any given shape is described by the clockwise/counterclockwise direction of the points.  The
+   * clockwise direction indicates that a point inside is "in-set", while a counter-clockwise direction implies that
+   * a point inside is "out-of-set".
+   * 
+   * @param planetModel is the planet model.
+   * @param shapesList is the list of polygons we should be making.
+   * @return the GeoPolygon, or null if it cannot be constructed.
+   */
+  public static GeoPolygon makeLargeGeoPolygon(final PlanetModel planetModel,
+    final List<PolygonDescription> shapesList) {
+      
+    // We're going to be building a single-level list of shapes in the end, with a single point that we know to be inside/outside, which is
+    // not on an edge.
+    
+    final List<List<GeoPoint>> pointsList = new ArrayList<>();
     
+    List<GeoPoint> testPointShape = null;
+    for (final PolygonDescription shape : shapesList) {
+      // Convert this shape and its holes to a general list of shapes.  We also need to identify exactly one
+      // legal, non-degenerate shape with no children that we can use to find a test point.  We also optimize
+      // to choose as small as possible a polygon for determining the in-set-ness of the test point.
+      testPointShape = convertPolygon(pointsList, shape, testPointShape);
+    }
+    
+    // If there's no polygon we can use to determine a test point, we throw up.
+    if (testPointShape == null) {
+      throw new IllegalArgumentException("couldn't find a non-degenerate polygon for in-set determination");
+    }
+    
+    // Create a random number generator.  Effectively this furnishes us with a repeatable sequence
+    // of points to use for poles.
+    final Random generator = new Random(1234);
+    for (int counter = 0; counter < 1000000; counter++) {
+      // Pick the next random pole
+      final GeoPoint pole = pickPole(generator, planetModel, testPointShape);
+      // Is it inside or outside?
+      final Boolean isPoleInside = isInsidePolygon(pole, testPointShape);
+      if (isPoleInside != null) {
+        // Legal pole
+        return new GeoComplexPolygon(planetModel, pointsList, pole, isPoleInside);
+      }
+      // If pole choice was illegal, try another one
+    }
+    throw new IllegalArgumentException("cannot find a point that is inside the polygon "+testPointShape);
+
+  }
+
+  /** Convert a polygon description to a list of shapes.  Also locate an optimal shape for evaluating a test point.
+   * @param pointsList is the structure to add new polygons to.
+   * @param shape is the current polygon description.
+   * @param testPointShape is the current best choice for a low-level polygon to evaluate.
+   * @return an updated best-choice for a test point polygon, and update the points list.
+   */
+  private static List<GeoPoint> convertPolygon(final List<List<GeoPoint>> pointsList, final PolygonDescription shape, List<GeoPoint> testPointShape) {
+    // First, remove duplicate points.  If degenerate, just ignore the shape.
+    final List<GeoPoint> filteredPoints = filterPoints(shape.points);
+    if (filteredPoints == null) {
+      return testPointShape;
+    }
+    
+    // Non-degenerate.  Check if this is a candidate for in-set determination.
+    if (shape.holes.size() == 0) {
+      // This shape is a candidate for a test point.
+      if (testPointShape == null || testPointShape.size() > filteredPoints.size()) {
+        testPointShape = filteredPoints;
+      }
+    }
+    
+    pointsList.add(filteredPoints);
+    
+    // Now, do all holes too
+    for (final PolygonDescription hole : shape.holes) {
+      testPointShape = convertPolygon(pointsList, hole, testPointShape);
+    }
+    
+    // Done; return the updated test point shape.
+    return testPointShape;
+  }
+  
   /**
    * Create a GeoPolygon using the specified points and holes and a test point.
    *
@@ -171,7 +278,7 @@ public class GeoPolygonFactory {
    * @param input with input list of points
    * @return the filtered list, or null if we can't get a legit polygon from the input.
    */
-  static List<GeoPoint> filterPoints(final List<GeoPoint> input) {
+  static List<GeoPoint> filterPoints(final List<? extends GeoPoint> input) {
     
     final List<GeoPoint> noIdenticalPoints = new ArrayList<>(input.size());
     


[21/25] lucene-solr:branch_6x: Lots of fixes

Posted by kw...@apache.org.
Lots of fixes


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/1a3bf830
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/1a3bf830
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/1a3bf830

Branch: refs/heads/branch_6x
Commit: 1a3bf8305510507ad72fffdb6dca00f6386fd1ae
Parents: aa7adc1
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 13:14:35 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:26:10 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 92 ++++++++++++++------
 .../lucene/spatial3d/geom/GeoPolygonTest.java   |  6 +-
 2 files changed, 67 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/1a3bf830/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 3eff223..914b000 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -153,6 +153,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else {
       
+      System.err.println("isWithin() for check point "+thePoint+", test point "+testPoint);
+      
       // We need to use two planes to get there.  We don't know which two planes will do it but we can figure it out.
       final Plane travelPlaneFixedX = new Plane(1.0, 0.0, 0.0, -thePoint.x);
       final Plane travelPlaneFixedY = new Plane(0.0, 1.0, 0.0, -thePoint.y);
@@ -185,12 +187,12 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.y;
           secondLegValue = thePoint.x;
-          firstLegPlane = testPointYZPlane;
-          firstLegAbovePlane = testPointYZAbovePlane;
-          firstLegBelowPlane = testPointYZBelowPlane;
+          firstLegPlane = testPointXZPlane;
+          firstLegAbovePlane = testPointXZAbovePlane;
+          firstLegBelowPlane = testPointXZBelowPlane;
           secondLegPlane = travelPlaneFixedX;
-          firstLegTree = xTree;
-          secondLegTree = yTree;
+          firstLegTree = yTree;
+          secondLegTree = xTree;
           intersectionPoint = p;
         }
       }
@@ -201,10 +203,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.y;
           secondLegValue = thePoint.z;
-          firstLegPlane = testPointXYPlane;
-          firstLegAbovePlane = testPointXYAbovePlane;
-          firstLegBelowPlane = testPointXYBelowPlane;
-          secondLegPlane = travelPlaneFixedX;
+          firstLegPlane = testPointXZPlane;
+          firstLegAbovePlane = testPointXZAbovePlane;
+          firstLegBelowPlane = testPointXZBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
           firstLegTree = yTree;
           secondLegTree = zTree;
           intersectionPoint = p;
@@ -217,9 +219,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.x;
           secondLegValue = thePoint.y;
-          firstLegPlane = testPointXZPlane;
-          firstLegAbovePlane = testPointXZAbovePlane;
-          firstLegBelowPlane = testPointXZBelowPlane;
+          firstLegPlane = testPointYZPlane;
+          firstLegAbovePlane = testPointYZAbovePlane;
+          firstLegBelowPlane = testPointYZBelowPlane;
           secondLegPlane = travelPlaneFixedY;
           firstLegTree = xTree;
           secondLegTree = yTree;
@@ -233,10 +235,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.x;
           secondLegValue = thePoint.z;
-          firstLegPlane = testPointXYPlane;
-          firstLegAbovePlane = testPointXYAbovePlane;
-          firstLegBelowPlane = testPointXYBelowPlane;
-          secondLegPlane = travelPlaneFixedX;
+          firstLegPlane = testPointYZPlane;
+          firstLegAbovePlane = testPointYZAbovePlane;
+          firstLegBelowPlane = testPointYZBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
           firstLegTree = xTree;
           secondLegTree = zTree;
           intersectionPoint = p;
@@ -249,10 +251,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.z;
           secondLegValue = thePoint.x;
-          firstLegPlane = testPointYZPlane;
-          firstLegAbovePlane = testPointYZAbovePlane;
-          firstLegBelowPlane = testPointYZBelowPlane;
-          secondLegPlane = travelPlaneFixedZ;
+          firstLegPlane = testPointXYPlane;
+          firstLegAbovePlane = testPointXYAbovePlane;
+          firstLegBelowPlane = testPointXYBelowPlane;
+          secondLegPlane = travelPlaneFixedX;
           firstLegTree = zTree;
           secondLegTree = xTree;
           intersectionPoint = p;
@@ -265,10 +267,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
           bestDistance = newDistance;
           firstLegValue = testPoint.z;
           secondLegValue = thePoint.y;
-          firstLegPlane = testPointXZPlane;
-          firstLegAbovePlane = testPointXZAbovePlane;
-          firstLegBelowPlane = testPointXZBelowPlane;
-          secondLegPlane = travelPlaneFixedZ;
+          firstLegPlane = testPointXYPlane;
+          firstLegAbovePlane = testPointXYAbovePlane;
+          firstLegBelowPlane = testPointXYBelowPlane;
+          secondLegPlane = travelPlaneFixedY;
           firstLegTree = zTree;
           secondLegTree = yTree;
           intersectionPoint = p;
@@ -388,7 +390,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.planeBounds.addPoint(startPoint);
       this.planeBounds.addPoint(endPoint);
       this.plane.recordBounds(pm, this.planeBounds, this.startPlane, this.endPlane);
-      System.err.println("Recording edge from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
+      System.err.println("Recording edge "+this+" from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
     }
   }
   
@@ -473,8 +475,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
     protected Node addEdge(final Node node, final Edge newEdge, final double minimumValue, final double maximumValue) {
       if (node == null) {
         // Create and return a new node
-        return new Node(newEdge, minimumValue, maximumValue);
+        final Node rval = new Node(newEdge, minimumValue, maximumValue);
+        //System.err.println("Creating new node "+rval+" for edge "+newEdge+" in tree "+this);
+        return rval;
       }
+      //System.err.println("Adding edge "+newEdge+" into node "+node+" in tree "+this);
       // Compare with what's here
       int result = compareForAdd(node.minimumValue, node.maximumValue, minimumValue, maximumValue);
       switch (result) {
@@ -482,30 +487,36 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // The node is contained in the range provided.  We need to create a new node and insert
         // it into the "within" chain.
         final Node rval = new Node(newEdge, minimumValue, maximumValue);
-        rval.within = node.within;
+        //System.err.println(" Inserting new node "+rval+" at head of current 'within' chain in tree "+this);
+        rval.within = node;
         return rval;
       case WITHIN:
         // The new edge is within the node provided
+        //System.err.println(" Adding edge into 'within' chain in tree "+this);
         node.within = addEdge(node.within, newEdge, minimumValue, maximumValue);
         return node;
       case OVERLAPS_MINIMUM:
         // The new edge overlaps the minimum value, but not the maximum value.
         // Here we need to create TWO entries: one for the lesser side, and one for the within chain.
+        //System.err.println(" Inserting edge into BOTH lesser chain and within chain in tree "+this);
         final double lesserMaximum = Math.nextDown(node.minimumValue);
         node.lesser = addEdge(node.lesser, newEdge, minimumValue, lesserMaximum);
         return addEdge(node, newEdge, node.minimumValue, maximumValue);
       case OVERLAPS_MAXIMUM:
         // The new edge overlaps the maximum value, but not the minimum value.
         // Need to create two entries, one on the greater side, and one back into the current node.
+        //System.err.println(" Inserting edge into BOTH greater chain and within chain in tree "+this);
         final double greaterMinimum = Math.nextUp(node.maximumValue);
         node.greater = addEdge(node.greater, newEdge, greaterMinimum, maximumValue);
         return addEdge(node, newEdge, minimumValue, node.maximumValue);
       case LESS:
         // The new edge is clearly less than the current node.
+        //System.err.println(" Edge goes into the lesser chain in tree "+this);
         node.lesser = addEdge(node.lesser, newEdge, minimumValue, maximumValue);
         return node;
       case GREATER:
         // The new edge is clearly greater than the current node.
+        //System.err.println(" Edge goes into the greater chain in tree "+this);
         node.greater = addEdge(node.greater, newEdge, minimumValue, maximumValue);
         return node;
       default:
@@ -520,14 +531,18 @@ class GeoComplexPolygon extends GeoBasePolygon {
      * @return false if the traversal was aborted before completion.
      */
     public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      //System.err.println("Traversing tree, value = "+value);
       // Since there is one distinct value we are looking for, we can just do a straight descent through the nodes.
       Node currentNode = rootNode;
       while (currentNode != null) {
         if (value < currentNode.minimumValue) {
+          //System.err.println(" value is less than "+currentNode.minimumValue);
           currentNode = currentNode.lesser;
         } else if (value > currentNode.maximumValue) {
+          //System.err.println(" value is greater than "+currentNode.maximumValue);
           currentNode = currentNode.greater;
         } else {
+          //System.err.println(" value within "+currentNode.minimumValue+" to "+currentNode.maximumValue);
           // We're within the bounds of the node.  Call the iterator, and descend
           if (!edgeIterator.matches(currentNode.edge)) {
             return false;
@@ -535,6 +550,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
           currentNode = currentNode.within;
         }
       }
+      //System.err.println("Done with tree");
       return true;
     }
     
@@ -615,6 +631,12 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     @Override
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      System.err.println("Traversing in Z, value= "+value+"...");
+      return super.traverse(edgeIterator, value);
+    }
+
+    @Override
     protected double getMinimum(final Edge edge) {
       return edge.planeBounds.getMinimumZ();
     }
@@ -632,6 +654,12 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     public YTree() {
     }
+
+    @Override
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      System.err.println("Traversing in Y, value= "+value+"...");
+      return super.traverse(edgeIterator, value);
+    }
     
     @Override
     protected double getMinimum(final Edge edge) {
@@ -653,6 +681,12 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     @Override
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      System.err.println("Traversing in X, value= "+value+"...");
+      return super.traverse(edgeIterator, value);
+    }
+    
+    @Override
     protected double getMinimum(final Edge edge) {
       return edge.planeBounds.getMinimumX();
     }
@@ -935,7 +969,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     @Override
     public boolean matches(final Edge edge) {
-      System.err.println("Processing edge "+edge);
+      System.err.println("Processing edge "+edge+", startpoint="+edge.startPoint+" endpoint="+edge.endPoint);
       // Early exit if the point is on the edge.
       if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
         System.err.println(" Check point is on edge: isWithin = true");
@@ -946,8 +980,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // for at least one of the two planes in order to be a legitimate crossing of the combined path.
       final GeoPoint[] crossingPoints;
       if (isSecondLeg) {
+        System.err.println(" check point plane = "+travelPlane);
         crossingPoints = travelPlane.findCrossings(planetModel, edge.plane, checkPointCutoffPlane, checkPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
       } else {
+        System.err.println(" test point plane = "+testPointPlane);
         crossingPoints = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
       }
       if (crossingPoints != null) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/1a3bf830/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index 7a152b9..53fc246 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -189,8 +189,8 @@ public class GeoPolygonTest {
     shapes.add(new GeoPolygonFactory.PolygonDescription(points));
     
     c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
-    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp)); //??? fails
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
 
     // Sample some points within
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
@@ -205,7 +205,7 @@ public class GeoPolygonTest {
     assertTrue(c.isWithin(gp));
     // Sample some nearby points outside
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
-    assertFalse(c.isWithin(gp)); //??? fails
+    assertFalse(c.isWithin(gp));
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
     assertFalse(c.isWithin(gp));
     gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);


[06/25] lucene-solr:branch_6x: Complete the logic for following a path, except for the path endpoint on edge condition.

Posted by kw...@apache.org.
Complete the logic for following a path, except for the path endpoint on edge condition.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/09ba7bf4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/09ba7bf4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/09ba7bf4

Branch: refs/heads/branch_6x
Commit: 09ba7bf47ccce1110205484af238c02550a24687
Parents: 85b557f
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 12:16:56 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:22:13 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 150 ++++++++++++++-----
 1 file changed, 112 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/09ba7bf4/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 02ce02c..122a6eb 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -40,7 +40,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
   private final ZTree ztree = new ZTree();
   
   private final boolean testPointInSet;
-  private final Plane testPointZPlane;
+  
+  private final Plane testPointXZPlane;
+  private final Plane testPointYZPlane;
+  private final Plane testPointXYPlane;
+  
   private final GeoPoint[] edgePoints;
   private final Edge[] shapeStartEdges;
   
@@ -58,11 +62,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
   public GeoComplexPolygon(final PlanetModel planetModel, final List<List<GeoPoint>> pointsList, final GeoPoint testPoint, final boolean testPointInSet) {
     super(planetModel);
     this.testPointInSet = testPointInSet;
-    Plane p = Plane.constructNormalizedZPlane(testPoint.x, testPoint.y);
-    if (p == null) {
-      p = new Plane(1.0, 0.0, 0.0, 0.0);
-    }
-    this.testPointZPlane = p;
+    
+    this.testPointXZPlane = new Plane(0.0, 1.0, 0.0, -testPoint.y);
+    this.testPointYZPlane = new Plane(1.0, 0.0, 0.0, -testPoint.x);
+    this.testPointXYPlane = new Plane(0.0, 0.0, 1.0, -testPoint.z);
+    
     this.edgePoints = new GeoPoint[pointsList.size()];
     this.shapeStartEdges = new Edge[pointsList.size()];
     int edgePointIndex = 0;
@@ -114,42 +118,112 @@ class GeoComplexPolygon extends GeoBasePolygon {
   
   @Override
   public boolean isWithin(final Vector thePoint) {
-    // Construct a horizontal plane that goes through the provided z value.  This, along with the
-    // testPointZPlane, will provide a way of counting intersections between this point and the test point.
-    // We use z exclusively for this logic at the moment but we may in the future choose x or y based on which
-    // is bigger.
+    // If we're right on top of the point, we know the answer.
     if (testPoint.isNumericallyIdentical(thePoint)) {
-      return true;
+      return testPointInSet;
     }
-    if (testPointZPlane.evaluateIsZero(thePoint)) {
-      // The point we are assessing goes through only one plane.
-      // Compute cutoff planes
-      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointZPlane, testPoint);
-      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointZPlane, thePoint);
-
-      // Count crossings
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointZPlane, testPointCutoff, checkPointCutoff);
-      
-      // Compute bounds for this part of testZPlane
-      final XYZBounds testZPlaneBounds = new XYZBounds();
-      testPointZPlane.recordBounds(planetModel, testZPlaneBounds, testPointCutoff, checkPointCutoff);
+    
+    // Choose our navigation route!
+    final double xDelta = Math.abs(thePoint.x - testPoint.x);
+    final double yDelta = Math.abs(thePoint.y - testPoint.y);
+    final double zDelta = Math.abs(thePoint.z - testPoint.z);
+    
+    // If we're right on top of any of the test planes, we navigate solely on that plane.
+    if (testPointXZPlane.evaluateIsZero(thePoint)) {
+      // Use the XZ plane exclusively.
+      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXZPlane, testPoint);
+      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXZPlane, thePoint);
+      // Note: need to detect condition where edge endpoint is the check point!
+      // MHL
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoff, checkPointCutoff);
+      // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
+      yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y);
+      return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
+    } else if (testPointYZPlane.evaluateIsZero(thePoint)) {
+      // Use the YZ plane exclusively.
+      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointYZPlane, testPoint);
+      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointYZPlane, thePoint);
+      // Note: need to detect condition where edge endpoint is the check point!
+      // MHL
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoff, checkPointCutoff);
+      // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
+      xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x);
+      return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
+    } else if (testPointXYPlane.evaluateIsZero(thePoint)) {
+      // Use the XY plane exclusively.
+      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXYPlane, testPoint);
+      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXYPlane, thePoint);
+      // Note: need to detect condition where edge endpoint is the check point!
+      // MHL
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoff, checkPointCutoff);
+      // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
+      zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z);
+      return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
+    } else {
       
-      // Pick which tree to use
-      final double xDelta = testZPlaneBounds.getMaximumX() - testZPlaneBounds.getMinimumX();
-      final double yDelta = testZPlaneBounds.getMaximumY() - testZPlaneBounds.getMinimumY();
-      if (xDelta <= yDelta) {
-        xTree.traverse(crossingEdgeIterator, testZPlaneBounds.getMinimumX(), testZPlaneBounds.getMaximumX());
-      } else if (yDelta <= xDelta) {
-        yTree.traverse(crossingEdgeIterator, testZPlaneBounds.getMinimumY(), testZPlaneBounds.getMaximumY());
+      // We need to use two planes to get there.  We can use any two planes, and order doesn't matter.
+      // The best to pick are the ones with the shortest overall distance.
+      if (xDelta + yDelta <= xDelta + zDelta && xDelta + yDelta <= yDelta + zDelta) {
+        // Travel in X and Y
+        // We'll do this using the testPointYZPlane, and create a travel plane for the right XZ plane.
+        final Plane travelPlane = new Plane(0.0, 1.0, 0.0, -thePoint.y);
+        // We need cutoff planes for both legs.
+        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointYZPlane, testPoint);
+        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
+        // Now, find the intersection of the check and test point planes.
+        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointYZPlane, testPointCutoffPlane, checkPointCutoffPlane);
+        assert intersectionPoints != null : "couldn't find any intersections";
+        assert intersectionPoints.length != 1 : "wrong number of intersection points";
+        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointYZPlane, intersectionPoints[0]);
+        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
+        // Note: we need to handle the cases where end point of the leg sits on an edge!
+        // MHL
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        xTree.traverse(testPointEdgeIterator, testPoint.x, testPoint.x);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+        yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y);
+        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
+      } else if (xDelta + zDelta <= xDelta + yDelta && xDelta + zDelta <= zDelta + yDelta) {
+        // Travel in X and Z
+        // We'll do this using the testPointXYPlane, and create a travel plane for the right YZ plane.
+        final Plane travelPlane = new Plane(1.0, 0.0, 0.0, -thePoint.x);
+        // We need cutoff planes for both legs.
+        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXYPlane, testPoint);
+        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
+        // Now, find the intersection of the check and test point planes.
+        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointXYPlane, testPointCutoffPlane, checkPointCutoffPlane);
+        assert intersectionPoints != null : "couldn't find any intersections";
+        assert intersectionPoints.length != 1 : "wrong number of intersection points";
+        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointXYPlane, intersectionPoints[0]);
+        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
+        // Note: we need to handle the cases where end point of the leg sits on an edge!
+        // MHL
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        zTree.traverse(testPointEdgeIterator, testPoint.z, testPoint.z);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+        xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x);
+        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
+      } else if (yDelta + zDelta <= xDelta + yDelta && yDelta + zDelta <= xDelta + zDelta) {
+        // Travel in Y and Z
+        // We'll do this using the testPointXZPlane, and create a travel plane for the right XY plane.
+        final Plane travelPlane = new Plane(0.0, 0.0, 1.0, -thePoint.z);
+        // We need cutoff planes for both legs.
+        final SidedPlane testPointCutoffPlane = new SidedPlane(thePoint, testPointXZPlane, testPoint);
+        final SidedPlane checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
+        // Now, find the intersection of the check and test point planes.
+        final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointXZPlane, testPointCutoffPlane, checkPointCutoffPlane);
+        assert intersectionPoints != null : "couldn't find any intersections";
+        assert intersectionPoints.length != 1 : "wrong number of intersection points";
+        final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointXZPlane, intersectionPoints[0]);
+        final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
+        // Note: we need to handle the cases where end point of the leg sits on an edge!
+        // MHL
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        yTree.traverse(testPointEdgeIterator, testPoint.y, testPoint.y);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+        zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z);
+        return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
       }
-      return ((crossingEdgeIterator.getCrossingCount() & 0x00000001) == 0)?testPointInSet:!testPointInSet;
-    } else {
-      // The point requires two planes
-      final Plane xyPlane = new Plane(planetModel, z);
-      // We need to plan a path from the test point to the point to be evaluated.
-      // This requires finding the intersection point between the xyPlane and the testPointZPlane
-      // that is closest to our point.
-      // MHL
     }
     return false;
   }


[03/25] lucene-solr:branch_6x: More work on GeoComplexPolygon

Posted by kw...@apache.org.
More work on GeoComplexPolygon


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/2491ad4a
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/2491ad4a
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/2491ad4a

Branch: refs/heads/branch_6x
Commit: 2491ad4a0d653e1fe7f1672cdb37b2bbf31088ec
Parents: 266a9a9
Author: Karl Wright <Da...@gmail.com>
Authored: Sun Apr 24 17:44:40 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:21:24 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 305 ++++++++++++++++++-
 1 file changed, 303 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2491ad4a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 3071fc8..df89f55 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -35,6 +35,15 @@ import java.util.Map;
  */
 class GeoComplexPolygon extends GeoBasePolygon {
   
+  private final XTree xtree = new XTree();
+  private final YTree ytree = new YTree();
+  private final ZTree ztree = new ZTree();
+  
+  private final boolean testPointInSet;
+  private final Plane testPointVerticalPlane;
+  private final GeoPoint[] edgePoints;
+  private final Edge[] shapeStartEdges;
+  
   /**
    * Create a complex polygon from multiple lists of points, and a single point which is known to be in or out of
    * set.
@@ -48,7 +57,41 @@ class GeoComplexPolygon extends GeoBasePolygon {
    */
   public GeoComplexPolygon(final PlanetModel planetModel, final List<List<GeoPoint>> pointsList, final GeoPoint testPoint, final boolean testPointInSet) {
     super(planetModel);
-    // MHL
+    this.testPointInSet = testPointInSet;
+    Plane p = Plane.constructNormalizedZPlane(testPoint.x, testPoint.y);
+    if (p == null) {
+      p = new Plane(1.0, 0.0, 0.0, 0.0);
+    }
+    this.testPointVerticalPlane = p;
+    this.edgePoints = new GeoPoint[pointsList.size()];
+    this.shapeStartEdges = new Edge[pointsList.size()];
+    int edgePointIndex = 0;
+    for (final List<GeoPoint> shapePoints : pointsList) {
+      GeoPoint lastGeoPoint = pointsList.get(shapePoints.size()-1);
+      edgePoints[edgePointIndex] = lastGeoPoint;
+      Edge lastEdge = null;
+      Edge firstEdge = null;
+      for (final GeoPoint thisGeoPoint : shapePoints) {
+        final Edge edge = new Edge(planetModel, lastGeoPoint, thisGeoPoint);
+        xtree.add(edge);
+        ytree.add(edge);
+        ztree.add(edge);
+        // Now, link
+        if (firstEdge == null) {
+          firstEdge = edge;
+        }
+        if (lastEdge != null) {
+          lastEdge.next = edge;
+          edge.previous = lastEdge;
+        }
+        lastEdge = edge;
+        lastGeoPoint = thisGeoPoint;
+      }
+      firstEdge.previous = lastEdge;
+      lastEdge.next = firstEdge;
+      shapeStartEdges[edgePointIndex] = firstEdge;
+      edgePointIndex++;
+    }
   }
 
   /** Compute a legal point index from a possibly illegal one, that may have wrapped.
@@ -85,12 +128,22 @@ class GeoComplexPolygon extends GeoBasePolygon {
   @Override
   public void getBounds(Bounds bounds) {
     super.getBounds(bounds);
-    // MHL
+    for (final Edge startEdge : shapeStartEdges) {
+      Edge currentEdge = startEdge;
+      while (true) {
+        currentEdge.plane.recordBounds(this.planetModel, currentEdge.startPlane, currentEdge.edgePlane);
+        currentEdge = currentEdge.next;
+        if (currentEdge == startEdge) {
+          break;
+        }
+      }
+    }
   }
 
   @Override
   protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
     // MHL
+    return 0.0;
   }
 
   /**
@@ -104,6 +157,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public final SidedPlane endPlane;
     public final Plane plane;
     public final XYZBounds planeBounds;
+    public Edge previous = null;
+    public Edge next = null;
     
     public Edge(final PlanetModel pm, final GeoPoint startPoint, final GeoPoint endPoint) {
       this.startPoint = startPoint;
@@ -116,6 +171,252 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
   }
   
+  /**
+   * Iterator execution interface, for tree traversal.  Pass an object implementing this interface
+   * into the traversal method of a tree, and each edge that matches will cause this object to be
+   * called.
+   */
+  private static interface EdgeIterator {
+    /**
+     * @param edge is the edge that matched.
+     * @return true if the iteration should continue, false otherwise.
+     */
+    public boolean matches(final Edge edge);
+  }
+  
+  /**
+   * Comparison interface for tree traversal.  An object implementing this interface
+   * gets to decide the relationship between the Edge object and the criteria being considered.
+   */
+  private static interface TraverseComparator {
+    
+    /**
+     * Compare an edge.
+     * @param edge is the edge to compare.
+     * @param value is the value to compare.
+     * @return -1 if "less" than this one, 0 if overlaps, or 1 if "greater".
+     */
+    public int compare(final Edge edge, final double value);
+    
+  }
+
+  /**
+   * Comparison interface for tree addition.  An object implementing this interface
+   * gets to decide the relationship between the Edge object and the criteria being considered.
+   */
+  private static interface AddComparator {
+    
+    /**
+     * Compare an edge.
+     * @param edge is the edge to compare.
+     * @param addEdge is the edge being added.
+     * @return -1 if "less" than this one, 0 if overlaps, or 1 if "greater".
+     */
+    public int compare(final Edge edge, final Edge addEdge);
+    
+  }
+  
+  /**
+   * An instance of this class represents a node in a tree.  The tree is designed to be given
+   * a value and from that to iterate over a list of edges.
+   * In order to do this efficiently, each new edge is dropped into the tree using its minimum and
+   * maximum value.  If the new edge's value does not overlap the range, then it gets added
+   * either to the lesser side or the greater side, accordingly.  If it does overlap, then the
+   * "overlapping" chain is instead traversed.
+   *
+   * This class is generic and can be used for any definition of "value".
+   *
+   */
+  private static class Node {
+    public final Edge edge;
+    public Node lesser = null;
+    public Node greater = null;
+    public Node overlaps = null;
+    
+    public Node(final Edge edge) {
+      this.edge = edge;
+    }
+    
+    public void add(final Edge newEdge, final AddComparator edgeComparator) {
+      Node currentNode = this;
+      while (true) {
+        final int result = edgeComparator.compare(edge, newEdge);
+        if (result < 0) {
+          if (lesser == null) {
+            lesser = new Node(newEdge);
+            return;
+          }
+          currentNode = lesser;
+        } else if (result > 0) {
+          if (greater == null) {
+            greater = new Node(newEdge);
+            return;
+          }
+          currentNode = greater;
+        } else {
+          if (overlaps == null) {
+            overlaps = new Node(newEdge);
+            return;
+          }
+          currentNode = overlaps;
+        }
+      }
+    }
+    
+    public boolean traverse(final EdgeIterator edgeIterator, final TraverseComparator edgeComparator, final double value) {
+      Node currentNode = this;
+      while (currentNode != null) {
+        final int result = edgeComparator.compare(currentNode.edge, value);
+        if (result < 0) {
+          currentNode = lesser;
+        } else if (result > 0) {
+          currentNode = greater;
+        } else {
+          if (!edgeIterator.matches(edge)) {
+            return false;
+          }
+          currentNode = overlaps;
+        }
+      }
+      return true;
+    }
+  }
+  
+  /** This is the z-tree.
+   */
+  private static class ZTree implements TraverseComparator, AddComparator {
+    public Node rootNode = null;
+    
+    public ZTree() {
+    }
+    
+    public void add(final Edge edge) {
+      if (rootNode == null) {
+        rootNode = new Node(edge);
+      } else {
+        rootNode.add(edge, this);
+      }
+    }
+    
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      if (rootNode == null) {
+        return true;
+      }
+      return rootNode.traverse(edgeIterator, this, value);
+    }
+    
+    @Override
+    public int compare(final Edge edge, final Edge addEdge) {
+      if (edge.planeBounds.getMaximumZ() < addEdge.planeBounds.getMinimumZ()) {
+        return 1;
+      } else if (edge.planeBounds.getMinimumZ() > addEdge.planeBounds.getMaximumZ()) {
+        return -1;
+      }
+      return 0;
+    }
+    
+    @Override
+    public int compare(final Edge edge, final double value) {
+      if (edge.planeBounds.getMinimumZ() > value) {
+        return -1;
+      } else if (edge.planeBounds.getMaximumZ() < value) {
+        return 1;
+      }
+      return 0;
+    }
+    
+  }
+  
+  /** This is the y-tree.
+   */
+  private static class YTree implements TraverseComparator, AddComparator {
+    public Node rootNode = null;
+    
+    public YTree() {
+    }
+    
+    public void add(final Edge edge) {
+      if (rootNode == null) {
+        rootNode = new Node(edge);
+      } else {
+        rootNode.add(edge, this);
+      }
+    }
+    
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      if (rootNode == null) {
+        return true;
+      }
+      return rootNode.traverse(edgeIterator, this, value);
+    }
+    
+    @Override
+    public int compare(final Edge edge, final Edge addEdge) {
+      if (edge.planeBounds.getMaximumY() < addEdge.planeBounds.getMinimumY()) {
+        return 1;
+      } else if (edge.planeBounds.getMinimumY() > addEdge.planeBounds.getMaximumY()) {
+        return -1;
+      }
+      return 0;
+    }
+    
+    @Override
+    public int compare(final Edge edge, final double value) {
+      if (edge.planeBounds.getMinimumY() > value) {
+        return -1;
+      } else if (edge.planeBounds.getMaximumY() < value) {
+        return 1;
+      }
+      return 0;
+    }
+    
+  }
+
+  /** This is the x-tree.
+   */
+  private static class XTree implements TraverseComparator, AddComparator {
+    public Node rootNode = null;
+    
+    public XTree() {
+    }
+    
+    public void add(final Edge edge) {
+      if (rootNode == null) {
+        rootNode = new Node(edge);
+      } else {
+        rootNode.add(edge, this);
+      }
+    }
+    
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      if (rootNode == null) {
+        return true;
+      }
+      return rootNode.traverse(edgeIterator, this, value);
+    }
+    
+    @Override
+    public int compare(final Edge edge, final Edge addEdge) {
+      if (edge.planeBounds.getMaximumX() < addEdge.planeBounds.getMinimumX()) {
+        return 1;
+      } else if (edge.planeBounds.getMinimumX() > addEdge.planeBounds.getMaximumX()) {
+        return -1;
+      }
+      return 0;
+    }
+    
+    @Override
+    public int compare(final Edge edge, final double value) {
+      if (edge.planeBounds.getMinimumX() > value) {
+        return -1;
+      } else if (edge.planeBounds.getMaximumX() < value) {
+        return 1;
+      }
+      return 0;
+    }
+    
+  }
+
   @Override
   public boolean equals(Object o) {
     // MHL


[18/25] lucene-solr:branch_6x: Fix initialization bugs that prevented the code from working.

Posted by kw...@apache.org.
Fix initialization bugs that prevented the code from working.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/31f3d1f2
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/31f3d1f2
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/31f3d1f2

Branch: refs/heads/branch_6x
Commit: 31f3d1f2094c2c3b4da2a8fad2f31baff0b99a4f
Parents: f56e931
Author: Karl Wright <Da...@gmail.com>
Authored: Wed Apr 27 17:19:30 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:25:22 2016 -0400

----------------------------------------------------------------------
 .../org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java  | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/31f3d1f2/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index d8c8e75..3a89ee5 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -864,9 +864,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
         
       this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
       this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
-        
-      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointPlane, intersectionPoint);
-      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoint);
+
+      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, travelPlane, -(travelPlane.x * intersectionPoint.x + travelPlane.y * intersectionPoint.y + travelPlane.z * intersectionPoint.z));
+      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, testPointPlane, -(testPointPlane.x * intersectionPoint.x + testPointPlane.y * intersectionPoint.y + testPointPlane.z * intersectionPoint.z));
         
       // Figure out which of the above/below planes are inside vs. outside.  To do this,
       // we look for the point that is within the bounds of the testPointPlane and travelPlane.  The two sides that intersected there are the inside
@@ -882,7 +882,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
       assert belowAbove != null : "Below + above should not be coplanar";
       
-      assert aboveAbove.length + aboveBelow.length + belowBelow.length + belowAbove.length == 1 : "Can be exactly one inside point";
+      assert aboveAbove.length + aboveBelow.length + belowBelow.length + belowAbove.length == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" ab=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
       
       final GeoPoint insideIntersection;
       if (aboveAbove.length > 0) {


[07/25] lucene-solr:branch_6x: Handle the case where the last leg lands on an edge.

Posted by kw...@apache.org.
Handle the case where the last leg lands on an edge.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/754ee141
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/754ee141
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/754ee141

Branch: refs/heads/branch_6x
Commit: 754ee141c5c0bbe954fcd5c0efe8e08242715381
Parents: 09ba7bf
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 13:05:12 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:22:29 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 58 +++++++++++++-------
 1 file changed, 38 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/754ee141/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 122a6eb..229f9f4 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -133,31 +133,34 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the XZ plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXZPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXZPlane, thePoint);
-      // Note: need to detect condition where edge endpoint is the check point!
-      // MHL
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoff, checkPointCutoff);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
-      yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y);
+      if (!yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y)) {
+        // Endpoint is on edge
+        return true;
+      }
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else if (testPointYZPlane.evaluateIsZero(thePoint)) {
       // Use the YZ plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointYZPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointYZPlane, thePoint);
-      // Note: need to detect condition where edge endpoint is the check point!
-      // MHL
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoff, checkPointCutoff);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
-      xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x);
+      if (!xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x)) {
+        // Endpoint is on edge
+        return true;
+      }
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else if (testPointXYPlane.evaluateIsZero(thePoint)) {
       // Use the XY plane exclusively.
       final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointXYPlane, testPoint);
       final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointXYPlane, thePoint);
-      // Note: need to detect condition where edge endpoint is the check point!
-      // MHL
-      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoff, checkPointCutoff);
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoff, checkPointCutoff, thePoint);
       // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
-      zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z);
+      if (!zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z)) {
+        // Endpoint is on edge
+        return true;
+      }
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else {
       
@@ -180,8 +183,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // MHL
         final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
         xTree.traverse(testPointEdgeIterator, testPoint.x, testPoint.x);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
-        yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        if (!yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y)) {
+          // Endpoint is on edge
+          return true;
+        }
         return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
       } else if (xDelta + zDelta <= xDelta + yDelta && xDelta + zDelta <= zDelta + yDelta) {
         // Travel in X and Z
@@ -200,8 +206,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
         // MHL
         final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
         zTree.traverse(testPointEdgeIterator, testPoint.z, testPoint.z);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
-        xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        if (!xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x)) {
+          // Endpoint is on edge
+          return true;
+        }
         return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
       } else if (yDelta + zDelta <= xDelta + yDelta && yDelta + zDelta <= xDelta + zDelta) {
         // Travel in Y and Z
@@ -216,12 +225,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
         assert intersectionPoints.length != 1 : "wrong number of intersection points";
         final SidedPlane testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointXZPlane, intersectionPoints[0]);
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
-        // Note: we need to handle the cases where end point of the leg sits on an edge!
+        // Note: we need to handle the cases where end point of the first leg sits on an edge!
         // MHL
         final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
         yTree.traverse(testPointEdgeIterator, testPoint.y, testPoint.y);
-        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
-        zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z);
+        final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
+        if (!zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z)) {
+          // Endpoint is on edge
+          return true;
+        }
         return (((testPointEdgeIterator.crossingCount + checkPointEdgeIterator.crossingCount) & 1) == 0)?testPointInSet:!testPointInSet;
       }
     }
@@ -584,19 +596,25 @@ class GeoComplexPolygon extends GeoBasePolygon {
     private final Plane belowPlane;
     private final Membership bound1;
     private final Membership bound2;
+    private final GeoPoint thePoint;
     
     public int crossingCount = 0;
     
-    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2) {
+    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2, final GeoPoint thePoint) {
       this.plane = plane;
       this.abovePlane = new Plane(plane, true);
       this.belowPlane = new Plane(plane, false);
       this.bound1 = bound1;
       this.bound2 = bound2;
+      this.thePoint = thePoint;
     }
     
     @Override
     public boolean matches(final Edge edge) {
+      // Early exit if the point is on the edge.
+      if (edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
+        return false;
+      }
       final GeoPoint[] crossingPoints = plane.findCrossings(planetModel, edge.plane, bound1, bound2, edge.startPlane, edge.endPlane);
       if (crossingPoints != null) {
         // We need to handle the endpoint case, which is quite tricky.


[22/25] lucene-solr:branch_6x: Improve path determination code

Posted by kw...@apache.org.
Improve path determination code


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/fbb98451
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/fbb98451
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/fbb98451

Branch: refs/heads/branch_6x
Commit: fbb98451972c53a541f3d446719a5d059a74a932
Parents: 1a3bf83
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 15:09:48 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:26:24 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 48 +++++++++++++-------
 1 file changed, 31 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/fbb98451/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 914b000..c218776 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -182,7 +182,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       
       for (final GeoPoint p : XZIntersectionsYZ) {
         // Travel would be in XZ plane (fixed y) then in YZ (fixed x)
-        final double newDistance = Math.abs(thePoint.x - p.x) + Math.abs(testPoint.y - p.y);
+        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.x - p.x);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.y;
@@ -198,7 +198,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       for (final GeoPoint p : XZIntersectionsXY) {
         // Travel would be in XZ plane (fixed y) then in XY (fixed z)
-        final double newDistance = Math.abs(thePoint.z - p.z) + Math.abs(testPoint.y - p.y);
+        final double newDistance = Math.abs(testPoint.y - p.y) + Math.abs(thePoint.z - p.z);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.y;
@@ -214,7 +214,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       for (final GeoPoint p : YZIntersectionsXZ) {
         // Travel would be in YZ plane (fixed x) then in XZ (fixed y)
-        final double newDistance = Math.abs(thePoint.y - p.y) + Math.abs(testPoint.x - p.x);
+        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.y - p.y);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.x;
@@ -230,7 +230,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       for (final GeoPoint p : YZIntersectionsXY) {
         // Travel would be in YZ plane (fixed x) then in XY (fixed z)
-        final double newDistance = Math.abs(thePoint.z - p.z) + Math.abs(testPoint.x - p.x);
+        final double newDistance = Math.abs(testPoint.x - p.x) + Math.abs(thePoint.z - p.z);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.x;
@@ -246,7 +246,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       for (final GeoPoint p : XYIntersectionsYZ) {
         // Travel would be in XY plane (fixed z) then in YZ (fixed x)
-        final double newDistance = Math.abs(thePoint.x - p.x) + Math.abs(testPoint.z - p.z);
+        final double newDistance = Math.abs(testPoint.z - p.z) + Math.abs(thePoint.x - p.x);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.z;
@@ -262,7 +262,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       for (final GeoPoint p : XYIntersectionsXZ) {
         // Travel would be in XY plane (fixed z) then in XZ (fixed y)
-        final double newDistance = Math.abs(thePoint.y - p.y) + Math.abs(testPoint.z - p.z);
+        final double newDistance = Math.abs(testPoint.z - p.z) + Math.abs(thePoint.y - p.y);
         if (newDistance < bestDistance) {
           bestDistance = newDistance;
           firstLegValue = testPoint.z;
@@ -279,6 +279,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
       assert bestDistance < Double.MAX_VALUE : "Couldn't find an intersection point of any kind";
       
+      System.err.println("Best distance: "+bestDistance);
+      
       final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(firstLegPlane, firstLegAbovePlane, firstLegBelowPlane, secondLegPlane, testPoint, thePoint, intersectionPoint);
       if (!firstLegTree.traverse(edgeIterator, firstLegValue)) {
         return true;
@@ -906,27 +908,37 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.travelPlane = travelPlane;
       this.thePoint = thePoint;
       this.intersectionPoint = intersectionPoint;
-        
-      this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
-      this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
+      
+      assert !testPoint.isNumericallyIdentical(intersectionPoint) : "test point is the same as intersection point";
+      assert !thePoint.isNumericallyIdentical(intersectionPoint) : "check point is same is intersection point";
+
+      this.testPointCutoffPlane = new SidedPlane(intersectionPoint, testPointPlane, testPoint);
+      this.checkPointCutoffPlane = new SidedPlane(intersectionPoint, travelPlane, thePoint);
 
       // Convert travel plane to a sided plane
       this.testPointOtherCutoffPlane = new SidedPlane(testPoint, travelPlane, travelPlane.D);
       // Convert testPoint plane to a sided plane
       this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPointPlane.D);
-        
+
+      // Sanity check
+      assert testPointCutoffPlane.isWithin(intersectionPoint) : "intersection must be within testPointCutoffPlane";
+      assert testPointOtherCutoffPlane.isWithin(intersectionPoint) : "intersection must be within testPointOtherCutoffPlane";
+      assert checkPointCutoffPlane.isWithin(intersectionPoint) : "intersection must be within checkPointCutoffPlane";
+      assert checkPointOtherCutoffPlane.isWithin(intersectionPoint) : "intersection must be within checkPointOtherCutoffPlane";
+      
       // Figure out which of the above/below planes are inside vs. outside.  To do this,
       // we look for the point that is within the bounds of the testPointPlane and travelPlane.  The two sides that intersected there are the inside
       // borders.
       final Plane travelAbovePlane = new Plane(travelPlane, true);
       final Plane travelBelowPlane = new Plane(travelPlane, false);
-      final GeoPoint[] aboveAbove = travelAbovePlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      
+      final GeoPoint[] aboveAbove = travelAbovePlane.findIntersections(planetModel, testPointAbovePlane, testPointOtherCutoffPlane, checkPointOtherCutoffPlane);
       assert aboveAbove != null : "Above + above should not be coplanar";
-      final GeoPoint[] aboveBelow = travelAbovePlane.findIntersections(planetModel, testPointBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      final GeoPoint[] aboveBelow = travelAbovePlane.findIntersections(planetModel, testPointBelowPlane, testPointOtherCutoffPlane, checkPointOtherCutoffPlane);
       assert aboveBelow != null : "Above + below should not be coplanar";
-      final GeoPoint[] belowBelow = travelBelowPlane.findIntersections(planetModel, testPointBelowPlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      final GeoPoint[] belowBelow = travelBelowPlane.findIntersections(planetModel, testPointBelowPlane, testPointOtherCutoffPlane, checkPointOtherCutoffPlane);
       assert belowBelow != null : "Below + below should not be coplanar";
-      final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
+      final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, testPointOtherCutoffPlane, checkPointOtherCutoffPlane);
       assert belowAbove != null : "Below + above should not be coplanar";
 
       assert ((aboveAbove.length > 0)?1:0) + ((aboveBelow.length > 0)?1:0) + ((belowBelow.length > 0)?1:0) + ((belowAbove.length > 0)?1:0) == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" ab=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
@@ -1079,7 +1091,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
           assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
           assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
 
-          assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+          // An edge can cross both outside and inside, because of the corner.  But it can be considered to cross the inside ONLY if it crosses either of the inside edges.
+          //assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
 
           if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
             continue;
@@ -1126,8 +1139,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
         final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
         final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-          
-        assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        
+        // An edge can cross both outside and inside, because of the corner.  But it can be considered to cross the inside ONLY if it crosses either of the inside edges.
+        //assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't go both up and down: insideTestPointPlaneIntersections: "+insideTestPointPlaneIntersections.length+" insideTravelPlaneIntersections: "+insideTravelPlaneIntersections.length+" outsideTestPointPlaneIntersections: "+outsideTestPointPlaneIntersections.length+" outsideTravelPlaneIntersections: "+outsideTravelPlaneIntersections.length;
           
         if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
           return;


[12/25] lucene-solr:branch_6x: Separate point filtering from edge filtering.

Posted by kw...@apache.org.
Separate point filtering from edge filtering.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/65dc8ed2
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/65dc8ed2
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/65dc8ed2

Branch: refs/heads/branch_6x
Commit: 65dc8ed2aedddc80ff9b8fced0a5d20d6b0e93ef
Parents: 129f6d4
Author: Karl Wright <Da...@gmail.com>
Authored: Tue Apr 26 08:03:02 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:23:45 2016 -0400

----------------------------------------------------------------------
 .../lucene/spatial3d/geom/GeoPolygonFactory.java   | 17 +++++++++++++----
 .../lucene/spatial3d/geom/GeoPolygonTest.java      |  8 ++++----
 2 files changed, 17 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/65dc8ed2/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
index 609c864..fea5b89 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -90,7 +90,7 @@ public class GeoPolygonFactory {
     // First, exercise a sanity filter on the provided pointList, and remove identical points, linear points, and backtracks
     //System.err.println(" filtering "+pointList.size()+" points...");
     //final long startTime = System.currentTimeMillis();
-    final List<GeoPoint> filteredPointList = filterPoints(pointList, leniencyValue);
+    final List<GeoPoint> filteredPointList = filterEdges(filterPoints(pointList), leniencyValue);
     //System.err.println("  ...done in "+(System.currentTimeMillis()-startTime)+"ms ("+((filteredPointList==null)?"degenerate":(filteredPointList.size()+" points"))+")");
     if (filteredPointList == null) {
       return null;
@@ -167,12 +167,11 @@ public class GeoPolygonFactory {
     }
   }
 
-  /** Filter duplicate points and coplanar points.
+  /** Filter duplicate points.
    * @param input with input list of points
-   * @param leniencyValue is the allowed distance of a point from the plane for cleanup of overly detailed polygons
    * @return the filtered list, or null if we can't get a legit polygon from the input.
    */
-  static List<GeoPoint> filterPoints(final List<GeoPoint> input, final double leniencyValue) {
+  static List<GeoPoint> filterPoints(final List<GeoPoint> input) {
     
     final List<GeoPoint> noIdenticalPoints = new ArrayList<>(input.size());
     
@@ -214,6 +213,16 @@ public class GeoPolygonFactory {
       return null;
     }
     
+    return noIdenticalPoints;
+  }
+  
+  /** Filter coplanar points.
+   * @param noIdenticalPoints with input list of points
+   * @param leniencyValue is the allowed distance of a point from the plane for cleanup of overly detailed polygons
+   * @return the filtered list, or null if we can't get a legit polygon from the input.
+   */
+  static List<GeoPoint> filterEdges(final List<GeoPoint> noIdenticalPoints, final double leniencyValue) {
+  
     // Now, do the depth-first search needed to find a path that has no coplanarities in it.
     // This is, unfortunately, not easy, because coplanarity is not transitive as you walk around the polygon.
     // If point C is not coplanar with edge A-B, there is no guarantee that A is not coplanar with B-C.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/65dc8ed2/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index ce43c5b..d76ae4e 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -44,7 +44,7 @@ public class GeoPolygonTest {
       originalPoints.add(point2);
       originalPoints.add(point2);
       originalPoints.add(point3);
-      final List<GeoPoint> filteredPoints =GeoPolygonFactory.filterPoints(originalPoints, 0.0);
+      final List<GeoPoint> filteredPoints = GeoPolygonFactory.filterEdges(GeoPolygonFactory.filterPoints(originalPoints), 0.0);
       assertEquals(3, filteredPoints.size());
       assertEquals(point1, filteredPoints.get(0));
       assertEquals(point2, filteredPoints.get(1));
@@ -57,7 +57,7 @@ public class GeoPolygonTest {
       originalPoints.add(point1);
       originalPoints.add(point3);
       originalPoints.add(point2);
-      final List<GeoPoint> filteredPoints =GeoPolygonFactory.filterPoints(originalPoints, 0.0);
+      final List<GeoPoint> filteredPoints = GeoPolygonFactory.filterEdges(GeoPolygonFactory.filterPoints(originalPoints), 0.0);
       assertEquals(3, filteredPoints.size());
       assertEquals(point2, filteredPoints.get(0));
       assertEquals(point1, filteredPoints.get(1));
@@ -71,7 +71,7 @@ public class GeoPolygonTest {
       originalPoints.add(point3);
       originalPoints.add(point4);
       originalPoints.add(point5);
-      final List<GeoPoint> filteredPoints =GeoPolygonFactory.filterPoints(originalPoints, 0.0);
+      final List<GeoPoint> filteredPoints = GeoPolygonFactory.filterEdges(GeoPolygonFactory.filterPoints(originalPoints), 0.0);
       assertEquals(3, filteredPoints.size());
       assertEquals(point1, filteredPoints.get(0));
       assertEquals(point3, filteredPoints.get(1));
@@ -85,7 +85,7 @@ public class GeoPolygonTest {
       originalPoints.add(point3);
       originalPoints.add(point4);
       System.err.println("Before: "+originalPoints);
-      final List<GeoPoint> filteredPoints =GeoPolygonFactory.filterPoints(originalPoints, 0.0);
+      final List<GeoPoint> filteredPoints = GeoPolygonFactory.filterEdges(GeoPolygonFactory.filterPoints(originalPoints), 0.0);
       System.err.println("After: "+filteredPoints);
       assertEquals(3, filteredPoints.size());
       assertEquals(point5, filteredPoints.get(0));


[19/25] lucene-solr:branch_6x: Use more accurate version of inside cutoff planes.

Posted by kw...@apache.org.
Use more accurate version of inside cutoff planes.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/5545e9ed
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/5545e9ed
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/5545e9ed

Branch: refs/heads/branch_6x
Commit: 5545e9edf18ac33c058fc0c819ecfd187c81ffaa
Parents: 31f3d1f
Author: Karl Wright <Da...@gmail.com>
Authored: Wed Apr 27 20:09:06 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:25:43 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 14 ++++---
 .../lucene/spatial3d/geom/GeoPolygonTest.java   | 44 ++++++++++++++++++++
 2 files changed, 52 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5545e9ed/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 3a89ee5..06d6dba 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -865,8 +865,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
       this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
 
-      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, travelPlane, -(travelPlane.x * intersectionPoint.x + travelPlane.y * intersectionPoint.y + travelPlane.z * intersectionPoint.z));
-      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, testPointPlane, -(testPointPlane.x * intersectionPoint.x + testPointPlane.y * intersectionPoint.y + testPointPlane.z * intersectionPoint.z));
+      // Convert travel plane to a sided plane
+      this.testPointOtherCutoffPlane = new SidedPlane(testPoint, travelPlane, travelPlane.D);
+      // Convert testPoint plane to a sided plane
+      this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPointPlane.D);
         
       // Figure out which of the above/below planes are inside vs. outside.  To do this,
       // we look for the point that is within the bounds of the testPointPlane and travelPlane.  The two sides that intersected there are the inside
@@ -881,8 +883,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       assert belowBelow != null : "Below + below should not be coplanar";
       final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, testPointCutoffPlane, testPointOtherCutoffPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane);
       assert belowAbove != null : "Below + above should not be coplanar";
-      
-      assert aboveAbove.length + aboveBelow.length + belowBelow.length + belowAbove.length == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" ab=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
+
+      assert ((aboveAbove.length > 0)?1:0) + ((aboveBelow.length > 0)?1:0) + ((belowBelow.length > 0)?1:0) + ((belowAbove.length > 0)?1:0) == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" ab=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
       
       final GeoPoint insideIntersection;
       if (aboveAbove.length > 0) {
@@ -911,8 +913,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
         insideIntersection = belowAbove[0];
       }
       
-      insideTravelCutoffPlane = new SidedPlane(thePoint, travelInsidePlane, insideIntersection);
-      insideTestPointCutoffPlane = new SidedPlane(testPoint, testPointInsidePlane, insideIntersection);
+      insideTravelCutoffPlane = new SidedPlane(thePoint, testPointInsidePlane, testPointInsidePlane.D);
+      insideTestPointCutoffPlane = new SidedPlane(testPoint, travelInsidePlane, travelInsidePlane.D);
 
     }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/5545e9ed/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index a196495..7a152b9 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -134,6 +134,12 @@ public class GeoPolygonTest {
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
     assertTrue(c.isWithin(gp));
 
+    shapes = new ArrayList<>();
+    shapes.add(new GeoPolygonFactory.PolygonDescription(points));
+    
+    c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
+    assertTrue(c.isWithin(gp));
+
   }
 
   @Test
@@ -141,6 +147,7 @@ public class GeoPolygonTest {
     GeoPolygon c;
     GeoPoint gp;
     List<GeoPoint> points;
+    List<GeoPolygonFactory.PolygonDescription> shapes;
 
     points = new ArrayList<GeoPoint>();
     points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
@@ -177,6 +184,43 @@ public class GeoPolygonTest {
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
     assertFalse(c.isWithin(gp));
 
+    // Now, same thing for large polygon
+    shapes = new ArrayList<>();
+    shapes.add(new GeoPolygonFactory.PolygonDescription(points));
+    
+    c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp)); //??? fails
+
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.65);
+    assertFalse(c.isWithin(gp)); //??? fails
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
+    // Next bunch of small polygon points
     points = new ArrayList<GeoPoint>();
     points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));
     points.add(new GeoPoint(PlanetModel.SPHERE, 0.1, -0.5));


[16/25] lucene-solr:branch_6x: Flesh out remaining methods

Posted by kw...@apache.org.
Flesh out remaining methods


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f9a4a08c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f9a4a08c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f9a4a08c

Branch: refs/heads/branch_6x
Commit: f9a4a08ce003f3d30af9332158cf386db22866ef
Parents: 3a0dbbe
Author: Karl Wright <Da...@gmail.com>
Authored: Wed Apr 27 08:26:03 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:24:53 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 31 +++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f9a4a08c/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 9b0fd1f..47ca961 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -254,8 +254,25 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
   @Override
   protected double outsideDistance(final DistanceStyle distanceStyle, final double x, final double y, final double z) {
-    // MHL
-    return 0.0;
+    double minimumDistance = Double.MAX_VALUE;
+    for (final Edge shapeStartEdge : shapeStartEdges) {
+      Edge shapeEdge = shapeStartEdge;
+      while (true) {
+        final double newDist = distanceStyle.computeDistance(shapeEdge.startPoint, x, y, z);
+        if (newDist < minimumDistance) {
+          minimumDistance = newDist;
+        }
+        final double newPlaneDist = distanceStyle.computeDistance(planetModel, shapeEdge.plane, x, y, z, shapeEdge.startPlane, shapeEdge.endPlane);
+        if (newPlaneDist < minimumDistance) {
+          minimumDistance = newPlaneDist;
+        }
+        shapeEdge = shapeEdge.next;
+        if (shapeEdge == shapeStartEdge) {
+          break;
+        }
+      }
+    }
+    return minimumDistance;
   }
 
   /**
@@ -1002,19 +1019,19 @@ class GeoComplexPolygon extends GeoBasePolygon {
   
   @Override
   public boolean equals(Object o) {
-    // MHL
-    return false;
+    // Way too expensive to do this the hard way, so each complex polygon will be considered unique.
+    return this == o;
   }
 
   @Override
   public int hashCode() {
-    // MHL
-    return 0;
+    // Each complex polygon is considered unique.
+    return System.identityHashCode(this);
   }
 
   @Override
   public String toString() {
-    return "GeoComplexPolygon: {planetmodel=" + planetModel + "}";
+    return "GeoComplexPolygon: {planetmodel=" + planetModel + ", number of shapes="+shapeStartEdges.length+", address="+ Integer.toHexString(hashCode())+"}";
   }
 }
   


[17/25] lucene-solr:branch_6x: More robust logic for picking the intersection point and path

Posted by kw...@apache.org.
More robust logic for picking the intersection point and path


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f56e9312
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f56e9312
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f56e9312

Branch: refs/heads/branch_6x
Commit: f56e93128b7d16d475da21c1f283a863c006435c
Parents: f9a4a08
Author: Karl Wright <Da...@gmail.com>
Authored: Wed Apr 27 13:54:28 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:25:07 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 236 +++++++++++++------
 .../spatial3d/geom/GeoPolygonFactory.java       |   7 +
 .../lucene/spatial3d/geom/GeoPolygonTest.java   |   9 +-
 3 files changed, 183 insertions(+), 69 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f56e9312/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 47ca961..d8c8e75 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -35,9 +35,9 @@ import java.util.Map;
  */
 class GeoComplexPolygon extends GeoBasePolygon {
   
-  private final XTree xTree = new XTree();
-  private final YTree yTree = new YTree();
-  private final ZTree zTree = new ZTree();
+  private final Tree xTree = new XTree();
+  private final Tree yTree = new YTree();
+  private final Tree zTree = new ZTree();
   
   private final boolean testPointInSet;
   private final GeoPoint testPoint;
@@ -125,11 +125,6 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return testPointInSet;
     }
     
-    // Choose our navigation route!
-    final double xDelta = Math.abs(thePoint.x - testPoint.x);
-    final double yDelta = Math.abs(thePoint.y - testPoint.y);
-    final double zDelta = Math.abs(thePoint.z - testPoint.z);
-    
     // If we're right on top of any of the test planes, we navigate solely on that plane.
     if (testPointXZPlane.evaluateIsZero(thePoint)) {
       // Use the XZ plane exclusively.
@@ -160,50 +155,141 @@ class GeoComplexPolygon extends GeoBasePolygon {
       return ((crossingEdgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
     } else {
       
-      // We need to use two planes to get there.  We can use any two planes, and order doesn't matter.
-      // The best to pick are the ones with the shortest overall distance.
-      if (xDelta + yDelta <= xDelta + zDelta && xDelta + yDelta <= yDelta + zDelta) {
-        // Travel in X and Y
-        // We'll do this using the testPointYZPlane, and create a travel plane for the right XZ plane.
-        final Plane travelPlane = new Plane(0.0, 1.0, 0.0, -thePoint.y);
-        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, travelPlane, testPoint, thePoint);
-        if (!xTree.traverse(edgeIterator, testPoint.x, testPoint.x)) {
-          return true;
+      // We need to use two planes to get there.  We don't know which two planes will do it but we can figure it out.
+      final Plane travelPlaneFixedX = new Plane(1.0, 0.0, 0.0, -thePoint.x);
+      final Plane travelPlaneFixedY = new Plane(0.0, 1.0, 0.0, -thePoint.y);
+      final Plane travelPlaneFixedZ = new Plane(0.0, 0.0, 1.0, -thePoint.z);
+
+      // Find the intersection points for each one of these and the complementary test point planes.
+      final GeoPoint[] XZIntersectionsYZ = travelPlaneFixedX.findIntersections(planetModel, testPointYZPlane);
+      final GeoPoint[] XZIntersectionsXY = travelPlaneFixedX.findIntersections(planetModel, testPointXYPlane);
+      final GeoPoint[] YZIntersectionsXZ = travelPlaneFixedY.findIntersections(planetModel, testPointXZPlane);
+      final GeoPoint[] YZIntersectionsXY = travelPlaneFixedY.findIntersections(planetModel, testPointXYPlane);
+      final GeoPoint[] XYIntersectionsYZ = travelPlaneFixedZ.findIntersections(planetModel, testPointYZPlane);
+      final GeoPoint[] XYIntersectionsXZ = travelPlaneFixedZ.findIntersections(planetModel, testPointXZPlane);
+
+      // There will be multiple intersection points found.  We choose the one that has the lowest total distance, as measured in delta X, delta Y, and delta Z.
+      double bestDistance = Double.MAX_VALUE;
+      double firstLegValue = 0.0;
+      double secondLegValue = 0.0;
+      Plane firstLegPlane = null;
+      Plane firstLegAbovePlane = null;
+      Plane firstLegBelowPlane = null;
+      Plane secondLegPlane = null;
+      Tree firstLegTree = null;
+      Tree secondLegTree = null;
+      GeoPoint intersectionPoint = null;
+      
+      for (final GeoPoint p : XZIntersectionsYZ) {
+        // Travel would be in XZ plane (fixed y) then in YZ (fixed x)
+        final double newDistance = Math.abs(thePoint.x - p.x) + Math.abs(testPoint.y - p.y);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.y;
+          secondLegValue = thePoint.x;
+          firstLegPlane = testPointYZPlane;
+          firstLegAbovePlane = testPointYZAbovePlane;
+          firstLegBelowPlane = testPointYZBelowPlane;
+          secondLegPlane = travelPlaneFixedX;
+          firstLegTree = xTree;
+          secondLegTree = yTree;
+          intersectionPoint = p;
         }
-        edgeIterator.setSecondLeg();
-        if (!yTree.traverse(edgeIterator, thePoint.y, thePoint.y)) {
-          return true;
+      }
+      for (final GeoPoint p : XZIntersectionsXY) {
+        // Travel would be in XZ plane (fixed y) then in XY (fixed z)
+        final double newDistance = Math.abs(thePoint.z - p.z) + Math.abs(testPoint.y - p.y);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.y;
+          secondLegValue = thePoint.z;
+          firstLegPlane = testPointXYPlane;
+          firstLegAbovePlane = testPointXYAbovePlane;
+          firstLegBelowPlane = testPointXYBelowPlane;
+          secondLegPlane = travelPlaneFixedX;
+          firstLegTree = yTree;
+          secondLegTree = zTree;
+          intersectionPoint = p;
         }
-        return ((edgeIterator.crossingCount  & 1) == 0)?testPointInSet:!testPointInSet;
-      } else if (xDelta + zDelta <= xDelta + yDelta && xDelta + zDelta <= zDelta + yDelta) {
-        // Travel in X and Z
-        // We'll do this using the testPointXYPlane, and create a travel plane for the right YZ plane.
-        final Plane travelPlane = new Plane(1.0, 0.0, 0.0, -thePoint.x);
-        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, travelPlane, testPoint, thePoint);
-        if (!zTree.traverse(edgeIterator, testPoint.z, testPoint.z)) {
-          return true;
+      }
+      for (final GeoPoint p : YZIntersectionsXZ) {
+        // Travel would be in YZ plane (fixed x) then in XZ (fixed y)
+        final double newDistance = Math.abs(thePoint.y - p.y) + Math.abs(testPoint.x - p.x);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.x;
+          secondLegValue = thePoint.y;
+          firstLegPlane = testPointXZPlane;
+          firstLegAbovePlane = testPointXZAbovePlane;
+          firstLegBelowPlane = testPointXZBelowPlane;
+          secondLegPlane = travelPlaneFixedY;
+          firstLegTree = xTree;
+          secondLegTree = yTree;
+          intersectionPoint = p;
         }
-        edgeIterator.setSecondLeg();
-        if (!xTree.traverse(edgeIterator, thePoint.x, thePoint.x)) {
-          return true;
+      }
+      for (final GeoPoint p : YZIntersectionsXY) {
+        // Travel would be in YZ plane (fixed x) then in XY (fixed z)
+        final double newDistance = Math.abs(thePoint.z - p.z) + Math.abs(testPoint.x - p.x);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.x;
+          secondLegValue = thePoint.z;
+          firstLegPlane = testPointXYPlane;
+          firstLegAbovePlane = testPointXYAbovePlane;
+          firstLegBelowPlane = testPointXYBelowPlane;
+          secondLegPlane = travelPlaneFixedX;
+          firstLegTree = xTree;
+          secondLegTree = zTree;
+          intersectionPoint = p;
         }
-        return ((edgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
-      } else if (yDelta + zDelta <= xDelta + yDelta && yDelta + zDelta <= xDelta + zDelta) {
-        // Travel in Y and Z
-        // We'll do this using the testPointXZPlane, and create a travel plane for the right XY plane.
-        final Plane travelPlane = new Plane(0.0, 0.0, 1.0, -thePoint.z);
-        final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, travelPlane, testPoint, thePoint);
-        if (!yTree.traverse(edgeIterator, testPoint.y, testPoint.y)) {
-          return true;
+      }
+      for (final GeoPoint p : XYIntersectionsYZ) {
+        // Travel would be in XY plane (fixed z) then in YZ (fixed x)
+        final double newDistance = Math.abs(thePoint.x - p.x) + Math.abs(testPoint.z - p.z);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.z;
+          secondLegValue = thePoint.x;
+          firstLegPlane = testPointYZPlane;
+          firstLegAbovePlane = testPointYZAbovePlane;
+          firstLegBelowPlane = testPointYZBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
+          firstLegTree = zTree;
+          secondLegTree = xTree;
+          intersectionPoint = p;
         }
-        edgeIterator.setSecondLeg();
-        if (!zTree.traverse(edgeIterator, thePoint.z, thePoint.z)) {
-          return true;
+      }
+      for (final GeoPoint p : XYIntersectionsXZ) {
+        // Travel would be in XY plane (fixed z) then in XZ (fixed y)
+        final double newDistance = Math.abs(thePoint.y - p.y) + Math.abs(testPoint.z - p.z);
+        if (newDistance < bestDistance) {
+          bestDistance = newDistance;
+          firstLegValue = testPoint.z;
+          secondLegValue = thePoint.y;
+          firstLegPlane = testPointXZPlane;
+          firstLegAbovePlane = testPointXZAbovePlane;
+          firstLegBelowPlane = testPointXZBelowPlane;
+          secondLegPlane = travelPlaneFixedZ;
+          firstLegTree = zTree;
+          secondLegTree = yTree;
+          intersectionPoint = p;
         }
-        return ((edgeIterator.crossingCount & 1) == 0)?testPointInSet:!testPointInSet;
       }
+
+      assert bestDistance < Double.MAX_VALUE : "Couldn't find an intersection point of any kind";
+      
+      final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(firstLegPlane, firstLegAbovePlane, firstLegBelowPlane, secondLegPlane, testPoint, thePoint, intersectionPoint);
+      if (!firstLegTree.traverse(edgeIterator, firstLegValue, firstLegValue)) {
+        return true;
+      }
+      edgeIterator.setSecondLeg();
+      if (!secondLegTree.traverse(edgeIterator, secondLegValue, secondLegValue)) {
+        return true;
+      }
+      return ((edgeIterator.crossingCount  & 1) == 0)?testPointInSet:!testPointInSet;
+
     }
-    return false;
   }
   
   @Override
@@ -298,6 +384,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.startPlane =  new SidedPlane(endPoint, plane, startPoint);
       this.endPlane = new SidedPlane(startPoint, plane, endPoint);
       this.planeBounds = new XYZBounds();
+      this.planeBounds.addPoint(startPoint);
+      this.planeBounds.addPoint(endPoint);
       this.plane.recordBounds(pm, this.planeBounds, this.startPlane, this.endPlane);
     }
   }
@@ -372,25 +460,25 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public void add(final Edge newEdge, final AddComparator edgeComparator) {
       Node currentNode = this;
       while (true) {
-        final int result = edgeComparator.compare(edge, newEdge);
+        final int result = edgeComparator.compare(currentNode.edge, newEdge);
         if (result < 0) {
-          if (lesser == null) {
-            lesser = new Node(newEdge);
+          if (currentNode.lesser == null) {
+            currentNode.lesser = new Node(newEdge);
             return;
           }
-          currentNode = lesser;
+          currentNode = currentNode.lesser;
         } else if (result > 0) {
-          if (greater == null) {
-            greater = new Node(newEdge);
+          if (currentNode.greater == null) {
+            currentNode.greater = new Node(newEdge);
             return;
           }
-          currentNode = greater;
+          currentNode = currentNode.greater;
         } else {
-          if (overlaps == null) {
-            overlaps = new Node(newEdge);
+          if (currentNode.overlaps == null) {
+            currentNode.overlaps = new Node(newEdge);
             return;
           }
-          currentNode = overlaps;
+          currentNode = currentNode.overlaps;
         }
       }
     }
@@ -400,28 +488,39 @@ class GeoComplexPolygon extends GeoBasePolygon {
       while (currentNode != null) {
         final int result = edgeComparator.compare(currentNode.edge, minValue, maxValue);
         if (result < 0) {
-          currentNode = lesser;
+          currentNode = currentNode.lesser;
         } else if (result > 0) {
-          currentNode = greater;
+          currentNode = currentNode.greater;
         } else {
-          if (!edgeIterator.matches(edge)) {
+          if (!edgeIterator.matches(currentNode.edge)) {
             return false;
           }
-          currentNode = overlaps;
+          currentNode = currentNode.overlaps;
         }
       }
       return true;
     }
   }
   
+  /** An interface describing a tree.
+   */
+  private static interface Tree {
+    
+    public void add(final Edge edge);
+    
+    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue);
+
+  }
+  
   /** This is the z-tree.
    */
-  private static class ZTree implements TraverseComparator, AddComparator {
+  private static class ZTree implements Tree, TraverseComparator, AddComparator {
     public Node rootNode = null;
     
     public ZTree() {
     }
     
+    @Override
     public void add(final Edge edge) {
       if (rootNode == null) {
         rootNode = new Node(edge);
@@ -430,6 +529,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
+    @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
@@ -461,12 +561,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
   
   /** This is the y-tree.
    */
-  private static class YTree implements TraverseComparator, AddComparator {
+  private static class YTree implements Tree, TraverseComparator, AddComparator {
     public Node rootNode = null;
     
     public YTree() {
     }
     
+    @Override
     public void add(final Edge edge) {
       if (rootNode == null) {
         rootNode = new Node(edge);
@@ -475,6 +576,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
+    @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
@@ -506,12 +608,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
   /** This is the x-tree.
    */
-  private static class XTree implements TraverseComparator, AddComparator {
+  private static class XTree implements Tree, TraverseComparator, AddComparator {
     public Node rootNode = null;
     
     public XTree() {
     }
     
+    @Override
     public void add(final Edge edge) {
       if (rootNode == null) {
         rootNode = new Node(edge);
@@ -520,6 +623,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
+    @Override
     public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
@@ -752,17 +856,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public int crossingCount = 0;
 
     public DualCrossingEdgeIterator(final Plane testPointPlane, final Plane testPointAbovePlane, final Plane testPointBelowPlane,
-      final Plane travelPlane, final Vector testPoint, final Vector thePoint) {
+      final Plane travelPlane, final Vector testPoint, final Vector thePoint, final GeoPoint intersectionPoint) {
       this.testPointPlane = testPointPlane;
       this.travelPlane = travelPlane;
       this.thePoint = thePoint;
+      this.intersectionPoint = intersectionPoint;
+        
       this.testPointCutoffPlane = new SidedPlane(thePoint, testPointPlane, testPoint);
       this.checkPointCutoffPlane = new SidedPlane(testPoint, travelPlane, thePoint);
-      // Now, find the intersection of the check and test point planes.
-      final GeoPoint[] intersectionPoints = travelPlane.findIntersections(planetModel, testPointPlane, testPointCutoffPlane, checkPointCutoffPlane);
-      assert intersectionPoints != null : "couldn't find any intersections";
-      assert intersectionPoints.length != 1 : "wrong number of intersection points";
-      this.intersectionPoint = intersectionPoints[0];
+        
       this.testPointOtherCutoffPlane = new SidedPlane(testPoint, testPointPlane, intersectionPoint);
       this.checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoint);
         

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f56e9312/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
index ff658c6..9b3278c 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -126,6 +126,13 @@ public class GeoPolygonFactory {
     
     /** Instantiate the polygon description.
      * @param points is the list of points.
+     */
+    public PolygonDescription(final List<? extends GeoPoint> points) {
+      this(points, new ArrayList<>());
+    }
+
+    /** Instantiate the polygon description.
+     * @param points is the list of points.
      * @param holes is the list of holes.
      */
     public PolygonDescription(final List<? extends GeoPoint> points, final List<? extends PolygonDescription> holes) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f56e9312/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index d76ae4e..a196495 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -84,9 +84,7 @@ public class GeoPolygonTest {
       originalPoints.add(point1);
       originalPoints.add(point3);
       originalPoints.add(point4);
-      System.err.println("Before: "+originalPoints);
       final List<GeoPoint> filteredPoints = GeoPolygonFactory.filterEdges(GeoPolygonFactory.filterPoints(originalPoints), 0.0);
-      System.err.println("After: "+filteredPoints);
       assertEquals(3, filteredPoints.size());
       assertEquals(point5, filteredPoints.get(0));
       assertEquals(point1, filteredPoints.get(1));
@@ -100,6 +98,7 @@ public class GeoPolygonTest {
     GeoPolygon c;
     GeoPoint gp;
     List<GeoPoint> points;
+    List<GeoPolygonFactory.PolygonDescription> shapes;
 
     // Points go counterclockwise, so 
     points = new ArrayList<GeoPoint>();
@@ -115,6 +114,12 @@ public class GeoPolygonTest {
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
     assertTrue(!c.isWithin(gp));
 
+    shapes = new ArrayList<>();
+    shapes.add(new GeoPolygonFactory.PolygonDescription(points));
+    
+    c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
+    assertTrue(!c.isWithin(gp));
+    
     // Now, go clockwise
     points = new ArrayList<GeoPoint>();
     points.add(new GeoPoint(PlanetModel.SPHERE, 0.0, -0.4));


[24/25] lucene-solr:branch_6x: Add more tests, and catch degenerate case early

Posted by kw...@apache.org.
Add more tests, and catch degenerate case early


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/a73d075b
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/a73d075b
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/a73d075b

Branch: refs/heads/branch_6x
Commit: a73d075bfae77808f8a365cdd3270e1139127808
Parents: bad7eb5
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 19:27:36 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:27:01 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoPolygonFactory.java       |  6 +++-
 .../lucene/spatial3d/geom/GeoPolygonTest.java   | 33 ++++++++++++++++++++
 2 files changed, 38 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a73d075b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
index 9b3278c..91eb339 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -90,7 +90,11 @@ public class GeoPolygonFactory {
     // First, exercise a sanity filter on the provided pointList, and remove identical points, linear points, and backtracks
     //System.err.println(" filtering "+pointList.size()+" points...");
     //final long startTime = System.currentTimeMillis();
-    final List<GeoPoint> filteredPointList = filterEdges(filterPoints(pointList), leniencyValue);
+    final List<GeoPoint> firstFilteredPointList = filterPoints(pointList);
+    if (firstFilteredPointList == null) {
+      return null;
+    }
+    final List<GeoPoint> filteredPointList = filterEdges(firstFilteredPointList, leniencyValue);
     //System.err.println("  ...done in "+(System.currentTimeMillis()-startTime)+"ms ("+((filteredPointList==null)?"degenerate":(filteredPointList.size()+" points"))+")");
     if (filteredPointList == null) {
       return null;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a73d075b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index b325e43..8063cb0 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -264,6 +264,39 @@ public class GeoPolygonTest {
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
     assertFalse(c.isWithin(gp));
 
+    // Now, same thing for large polygon
+    shapes = new ArrayList<>();
+    shapes.add(new GeoPolygonFactory.PolygonDescription(points));
+    
+    c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
+    // Sample some points within
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.55);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.05, -0.5);
+    assertTrue(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.7);
+    assertTrue(c.isWithin(gp));
+    // Sample some nearby points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.35);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, -0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.15, -0.5);
+    assertFalse(c.isWithin(gp));
+    // Random points outside
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, Math.PI * 0.5, 0.0);
+    assertFalse(c.isWithin(gp));
+    gp = new GeoPoint(PlanetModel.SPHERE, 0.0, Math.PI);
+    assertFalse(c.isWithin(gp));
+
   }
 
   @Test


[15/25] lucene-solr:branch_6x: Finish handling for intersection point

Posted by kw...@apache.org.
Finish handling for intersection point


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3a0dbbee
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3a0dbbee
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3a0dbbee

Branch: refs/heads/branch_6x
Commit: 3a0dbbee5ad4ae78a9976ce39005058097d17d9f
Parents: 3e18d93
Author: Karl Wright <Da...@gmail.com>
Authored: Wed Apr 27 07:30:07 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:24:37 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 258 ++++++++++---------
 1 file changed, 134 insertions(+), 124 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3a0dbbee/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index b5c29d6..9b0fd1f 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -834,158 +834,168 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // (a) both inside edges are considered together at all times;
       // (b) both outside edges are considered together at all times;
       // (c) inside edge crossings that are between the other leg's inside and outside edge are ignored.
-      if (crossingPoint.isNumericallyIdentical(intersectionPoint)) {
-        // Intersection point crossing
-        
-        // MHL to deal with intersection point crossing!!
-        
-      } else {
-        // Standard plane crossing, either first leg or second leg
       
-        final Plane plane;
-        final Plane insidePlane;
-        final Plane outsidePlane;
-        final SidedPlane bound1;
-        final SidedPlane bound2;
+      // Intersection point crossings are either simple, or a crossing on an endpoint.
+      // In either case, we have to be sure to count each edge only once, since it might appear in both the
+      // first leg and the second.  If the first leg can process it, it should, and the second should skip it.
+      if (crossingPoint.isNumericallyIdentical(intersectionPoint)) {
         if (isSecondLeg) {
-          plane = travelPlane;
-          insidePlane = travelInsidePlane;
-          outsidePlane = travelOutsidePlane;
-          bound1 = checkPointCutoffPlane;
-          bound2 = checkPointOtherCutoffPlane;
-        } else {
-          plane = testPointPlane;
-          insidePlane = testPointInsidePlane;
-          outsidePlane = testPointOutsidePlane;
-          bound1 = testPointCutoffPlane;
-          bound2 = testPointOtherCutoffPlane;
+          // See whether this edge would have been processed in the first leg; if so, we skip it.
+          final GeoPoint[] firstLegCrossings = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
+          for (final GeoPoint firstLegCrossing : firstLegCrossings) {
+            if (firstLegCrossing.isNumericallyIdentical(intersectionPoint)) {
+              // We already processed it, so we're done here.
+              return;
+            }
+          }
         }
+      }
+        
+      // Plane crossing, either first leg or second leg
+      
+      final Plane plane;
+      final Plane insidePlane;
+      final Plane outsidePlane;
+      final SidedPlane bound1;
+      final SidedPlane bound2;
+      if (isSecondLeg) {
+        plane = travelPlane;
+        insidePlane = travelInsidePlane;
+        outsidePlane = travelOutsidePlane;
+        bound1 = checkPointCutoffPlane;
+        bound2 = checkPointOtherCutoffPlane;
+      } else {
+        plane = testPointPlane;
+        insidePlane = testPointInsidePlane;
+        outsidePlane = testPointOutsidePlane;
+        bound1 = testPointCutoffPlane;
+        bound2 = testPointOtherCutoffPlane;
+      }
         
-        if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
-          // We have to figure out if this crossing should be counted.
+      if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
+        // We have to figure out if this crossing should be counted.
           
-          // Does the crossing for this edge go up, or down?  Or can't we tell?
-          final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
-          final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
-          final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-          final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
+        final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
+        final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
           
-          assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
           
-          if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
-            return;
-          }
+        if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
+          return;
+        }
 
-          final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
-
-          // This depends on the previous edge that first departs from identicalness.
-          Edge assessEdge = edge;
-          GeoPoint[] assessInsideTestPointIntersections;
-          GeoPoint[] assessInsideTravelIntersections;
-          GeoPoint[] assessOutsideTestPointIntersections;
-          GeoPoint[] assessOutsideTravelIntersections;
-          while (true) {
-            assessEdge = assessEdge.previous;
-            assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
-            assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
-            assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-            assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-
-            assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
-
-            if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
-              continue;
-            }
-            break;
+        final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessInsideTestPointIntersections;
+        GeoPoint[] assessInsideTravelIntersections;
+        GeoPoint[] assessOutsideTestPointIntersections;
+        GeoPoint[] assessOutsideTravelIntersections;
+        while (true) {
+          assessEdge = assessEdge.previous;
+          assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
+          assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
+          assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
+            continue;
           }
+          break;
+        }
 
-          // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
-          // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
-          // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
           
-          // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
-          // a decision whether to count or not based on that.
+        // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
+        // a decision whether to count or not based on that.
           
-          // Compute the crossing points of this other edge.
-          final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
+        // Compute the crossing points of this other edge.
+        final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
           
-          // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
-          // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
-          for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
-            if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
-              // Found it!
-              // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
-              // Since we're the latter point, we exit here in that case.
-              return;
-            }
+        // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
+        // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
+        for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
+          if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
+            // Found it!
+            // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
+            // Since we're the latter point, we exit here in that case.
+            return;
           }
+        }
           
-          // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
-          // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
-          // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+        // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
           
-          final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
-          if (assessEdgeInside != edgeCrossesInside) {
-            crossingCount++;
-          }
+        final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
+        if (assessEdgeInside != edgeCrossesInside) {
+          crossingCount++;
+        }
           
-        } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
-          // Figure out if the crossing should be counted.
+      } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
+        // Figure out if the crossing should be counted.
           
-          // Does the crossing for this edge go up, or down?  Or can't we tell?
-          final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
-          final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
-          final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-          final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
+        final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
+        final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
           
-          assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
           
-          if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
-            return;
-          }
+        if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
+          return;
+        }
 
-          final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
-
-          // This depends on the previous edge that first departs from identicalness.
-          Edge assessEdge = edge;
-          GeoPoint[] assessInsideTestPointIntersections;
-          GeoPoint[] assessInsideTravelIntersections;
-          GeoPoint[] assessOutsideTestPointIntersections;
-          GeoPoint[] assessOutsideTravelIntersections;
-          while (true) {
-            assessEdge = assessEdge.next;
-            assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
-            assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
-            assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-            assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-
-            assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
-
-            if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
-              continue;
-            }
-            break;
+        final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessInsideTestPointIntersections;
+        GeoPoint[] assessInsideTravelIntersections;
+        GeoPoint[] assessOutsideTestPointIntersections;
+        GeoPoint[] assessOutsideTravelIntersections;
+        while (true) {
+          assessEdge = assessEdge.next;
+          assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
+          assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
+          assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
+            continue;
           }
+          break;
+        }
           
-          // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
-          // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
-          // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
           
-          // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
-          // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
+        // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
+        // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
           
-          // We need to determine the direction of both edges at the
-          // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
-          // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+        // We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
 
-          final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
-          if (assessEdgeInside != edgeCrossesInside) {
-            crossingCount++;
-          }
-        } else {
-          // Not a special case, so we can safely count a crossing.
+        final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
+        if (assessEdgeInside != edgeCrossesInside) {
           crossingCount++;
         }
+      } else {
+        // Not a special case, so we can safely count a crossing.
+        crossingCount++;
       }
     }
   }


[14/25] lucene-solr:branch_6x: Restructure DualCrossing counter so that the plane inside and outside boundaries are used to detect inside and outside crossings. Also identify the case for special treatment of edges lying on the intersection point.

Posted by kw...@apache.org.
Restructure DualCrossing counter so that the plane inside and outside boundaries are used to detect inside and outside crossings.  Also identify the case for special treatment of edges lying on the intersection point.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3e18d935
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3e18d935
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3e18d935

Branch: refs/heads/branch_6x
Commit: 3e18d9356ea607160b469c89d6321a3e4e8b0d43
Parents: 9688932
Author: Karl Wright <Da...@gmail.com>
Authored: Tue Apr 26 13:49:47 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:24:19 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 285 +++++++++++--------
 1 file changed, 163 insertions(+), 122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3e18d935/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 7e4d01c..b5c29d6 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -729,6 +729,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
     private final SidedPlane testPointOtherCutoffPlane;
     private final SidedPlane checkPointOtherCutoffPlane;
 
+    private final SidedPlane insideTestPointCutoffPlane;
+    private final SidedPlane insideTravelCutoffPlane;
+    
     public int crossingCount = 0;
 
     public DualCrossingEdgeIterator(final Plane testPointPlane, final Plane testPointAbovePlane, final Plane testPointBelowPlane,
@@ -762,28 +765,36 @@ class GeoComplexPolygon extends GeoBasePolygon {
       
       assert aboveAbove.length + aboveBelow.length + belowBelow.length + belowAbove.length == 1 : "Can be exactly one inside point";
       
+      final GeoPoint insideIntersection;
       if (aboveAbove.length > 0) {
         travelInsidePlane = travelAbovePlane;
         testPointInsidePlane = testPointAbovePlane;
         travelOutsidePlane = travelBelowPlane;
         testPointOutsidePlane = testPointBelowPlane;
+        insideIntersection = aboveAbove[0];
       } else if (aboveBelow.length > 0) {
         travelInsidePlane = travelAbovePlane;
         testPointInsidePlane = testPointBelowPlane;
         travelOutsidePlane = travelBelowPlane;
         testPointOutsidePlane = testPointAbovePlane;
+        insideIntersection = aboveBelow[0];
       } else if (belowBelow.length > 0) {
         travelInsidePlane = travelBelowPlane;
         testPointInsidePlane = testPointBelowPlane;
         travelOutsidePlane = travelAbovePlane;
         testPointOutsidePlane = testPointAbovePlane;
+        insideIntersection = belowBelow[0];
       } else {
         travelInsidePlane = travelBelowPlane;
         testPointInsidePlane = testPointAbovePlane;
         travelOutsidePlane = travelAbovePlane;
         testPointOutsidePlane = testPointBelowPlane;
+        insideIntersection = belowAbove[0];
       }
-        
+      
+      insideTravelCutoffPlane = new SidedPlane(thePoint, travelInsidePlane, insideIntersection);
+      insideTestPointCutoffPlane = new SidedPlane(testPoint, testPointInsidePlane, insideIntersection);
+
     }
 
     public void setSecondLeg() {
@@ -796,6 +807,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
       if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
         return false;
       }
+      // If the intersection point lies on this edge, we should still be able to consider crossing points only.
+      // Even if an intersection point is eliminated because it's not a crossing of one plane, it will have to be a crossing
+      // for at least one of the two planes in order to be a legitimate crossing of the combined path.
       final GeoPoint[] crossingPoints;
       if (isSecondLeg) {
         crossingPoints = travelPlane.findCrossings(planetModel, edge.plane, checkPointCutoffPlane, checkPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
@@ -812,139 +826,166 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
 
     private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
-      final Plane plane;
-      final Plane insidePlane;
-      final Plane outsidePlane;
-      final SidedPlane bound1;
-      final SidedPlane bound2;
-      if (isSecondLeg) {
-        plane = travelPlane;
-        insidePlane = travelInsidePlane;
-        outsidePlane = travelOutsidePlane;
-        bound1 = checkPointCutoffPlane;
-        bound2 = checkPointOtherCutoffPlane;
+      // We consider crossing points only in this method.
+      // Unlike the linear case, there are additional cases when:
+      // (1) The crossing point and the intersection point are the same, but are not the endpoint of an edge;
+      // (2) The crossing point and the intersection point are the same, and they *are* the endpoint of an edge.
+      // The other logical difference is that crossings of all kinds have to be considered so that:
+      // (a) both inside edges are considered together at all times;
+      // (b) both outside edges are considered together at all times;
+      // (c) inside edge crossings that are between the other leg's inside and outside edge are ignored.
+      if (crossingPoint.isNumericallyIdentical(intersectionPoint)) {
+        // Intersection point crossing
+        
+        // MHL to deal with intersection point crossing!!
+        
       } else {
-        plane = testPointPlane;
-        insidePlane = testPointInsidePlane;
-        outsidePlane = testPointOutsidePlane;
-        bound1 = testPointCutoffPlane;
-        bound2 = testPointOtherCutoffPlane;
-      }
-      
-      // MHL - this code below is temporary code copied from LinearCrossing above
+        // Standard plane crossing, either first leg or second leg
       
-      if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
-        // We have to figure out if this crossing should be counted.
-        
-        // Does the crossing for this edge go up, or down?  Or can't we tell?
-        final GeoPoint[] insideIntersections = insidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        final GeoPoint[] outsideIntersections = outsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        
-        assert !(insideIntersections.length > 0 && outsideIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
-        
-        if (insideIntersections.length == 0 && outsideIntersections.length == 0) {
-          return;
-        }
-
-        final boolean edgeCrossesInside = insideIntersections.length > 0;
-
-        // This depends on the previous edge that first departs from identicalness.
-        Edge assessEdge = edge;
-        GeoPoint[] assessInsideIntersections;
-        GeoPoint[] assessOutsideIntersections;
-        while (true) {
-          assessEdge = assessEdge.previous;
-          assessInsideIntersections = insidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-          assessOutsideIntersections = outsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-
-          assert !(assessInsideIntersections.length > 0 && assessOutsideIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
-
-          if (assessInsideIntersections.length == 0 && assessOutsideIntersections.length == 0) {
-            continue;
-          }
-          break;
+        final Plane plane;
+        final Plane insidePlane;
+        final Plane outsidePlane;
+        final SidedPlane bound1;
+        final SidedPlane bound2;
+        if (isSecondLeg) {
+          plane = travelPlane;
+          insidePlane = travelInsidePlane;
+          outsidePlane = travelOutsidePlane;
+          bound1 = checkPointCutoffPlane;
+          bound2 = checkPointOtherCutoffPlane;
+        } else {
+          plane = testPointPlane;
+          insidePlane = testPointInsidePlane;
+          outsidePlane = testPointOutsidePlane;
+          bound1 = testPointCutoffPlane;
+          bound2 = testPointOtherCutoffPlane;
         }
         
-        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
-        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
-        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
-        
-        // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
-        // a decision whether to count or not based on that.
-        
-        // Compute the crossing points of this other edge.
-        final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
-        
-        // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
-        // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
-        for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
-          if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
-            // Found it!
-            // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
-            // Since we're the latter point, we exit here in that case.
+        if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
+          // We have to figure out if this crossing should be counted.
+          
+          // Does the crossing for this edge go up, or down?  Or can't we tell?
+          final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
+          final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
+          final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+          final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+          
+          assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+          
+          if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
             return;
           }
-        }
-        
-        // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
-        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
-        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
-        
-        final boolean assessEdgeInside = assessInsideIntersections.length > 0;
-        if (assessEdgeInside != edgeCrossesInside) {
-          crossingCount++;
-        }
-        
-      } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
-        // Figure out if the crossing should be counted.
-        
-        // Does the crossing for this edge go up, or down?  Or can't we tell?
-        final GeoPoint[] insideIntersections = insidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        final GeoPoint[] outsideIntersections = outsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
-        
-        assert !(insideIntersections.length > 0 && outsideIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
-        
-        if (insideIntersections.length == 0 && outsideIntersections.length == 0) {
-          return;
-        }
-
-        final boolean edgeCrossesInside = insideIntersections.length > 0;
 
-        // This depends on the previous edge that first departs from identicalness.
-        Edge assessEdge = edge;
-        GeoPoint[] assessInsideIntersections;
-        GeoPoint[] assessOutsideIntersections;
-        while (true) {
-          assessEdge = assessEdge.next;
-          assessInsideIntersections = insidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-          assessOutsideIntersections = outsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
-
-          assert !(assessInsideIntersections.length > 0 && assessOutsideIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+          final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
+
+          // This depends on the previous edge that first departs from identicalness.
+          Edge assessEdge = edge;
+          GeoPoint[] assessInsideTestPointIntersections;
+          GeoPoint[] assessInsideTravelIntersections;
+          GeoPoint[] assessOutsideTestPointIntersections;
+          GeoPoint[] assessOutsideTravelIntersections;
+          while (true) {
+            assessEdge = assessEdge.previous;
+            assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
+            assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
+            assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+            assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+            assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+            if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
+              continue;
+            }
+            break;
+          }
 
-          if (assessInsideIntersections.length == 0 && assessOutsideIntersections.length == 0) {
-            continue;
+          // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+          // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+          // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+          
+          // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
+          // a decision whether to count or not based on that.
+          
+          // Compute the crossing points of this other edge.
+          final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
+          
+          // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
+          // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
+          for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
+            if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
+              // Found it!
+              // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
+              // Since we're the latter point, we exit here in that case.
+              return;
+            }
+          }
+          
+          // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
+          // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+          // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+          
+          final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
+          if (assessEdgeInside != edgeCrossesInside) {
+            crossingCount++;
+          }
+          
+        } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
+          // Figure out if the crossing should be counted.
+          
+          // Does the crossing for this edge go up, or down?  Or can't we tell?
+          final GeoPoint[] insideTestPointPlaneIntersections = testPointInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTestPointCutoffPlane);
+          final GeoPoint[] insideTravelPlaneIntersections = travelInsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane, insideTravelCutoffPlane);
+          final GeoPoint[] outsideTestPointPlaneIntersections = testPointOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+          final GeoPoint[] outsideTravelPlaneIntersections = travelOutsidePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+          
+          assert !(insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+          
+          if (insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length == 0 && outsideTestPointPlaneIntersections.length + outsideTravelPlaneIntersections.length == 0) {
+            return;
           }
-          break;
-        }
-        
-        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
-        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
-        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
-        
-        // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
-        // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
-        
-        // We need to determine the direction of both edges at the
-        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
-        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
 
-        final boolean assessEdgeInside = assessInsideIntersections.length > 0;
-        if (assessEdgeInside != edgeCrossesInside) {
+          final boolean edgeCrossesInside = insideTestPointPlaneIntersections.length + insideTravelPlaneIntersections.length > 0;
+
+          // This depends on the previous edge that first departs from identicalness.
+          Edge assessEdge = edge;
+          GeoPoint[] assessInsideTestPointIntersections;
+          GeoPoint[] assessInsideTravelIntersections;
+          GeoPoint[] assessOutsideTestPointIntersections;
+          GeoPoint[] assessOutsideTravelIntersections;
+          while (true) {
+            assessEdge = assessEdge.next;
+            assessInsideTestPointIntersections = testPointInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTestPointCutoffPlane);
+            assessInsideTravelIntersections = travelInsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane, insideTravelCutoffPlane);
+            assessOutsideTestPointIntersections = testPointOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+            assessOutsideTravelIntersections = travelOutsidePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+            assert !(assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+            if (assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length == 0 && assessOutsideTestPointIntersections.length + assessOutsideTravelIntersections.length == 0) {
+              continue;
+            }
+            break;
+          }
+          
+          // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+          // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+          // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+          
+          // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
+          // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
+          
+          // We need to determine the direction of both edges at the
+          // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+          // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+
+          final boolean assessEdgeInside = assessInsideTestPointIntersections.length + assessInsideTravelIntersections.length > 0;
+          if (assessEdgeInside != edgeCrossesInside) {
+            crossingCount++;
+          }
+        } else {
+          // Not a special case, so we can safely count a crossing.
           crossingCount++;
         }
-
-      } else {
-        crossingCount++;
       }
     }
   }


[05/25] lucene-solr:branch_6x: Flesh out logic for handling vertex on plane case.

Posted by kw...@apache.org.
Flesh out logic for handling vertex on plane case.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/85b557f7
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/85b557f7
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/85b557f7

Branch: refs/heads/branch_6x
Commit: 85b557f7273e804ab78cb2caa97d7dd098f3c40e
Parents: ab7342c
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 10:15:11 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:21:58 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 194 ++++++++++++++++++-
 .../org/apache/lucene/spatial3d/geom/Plane.java |  20 +-
 2 files changed, 210 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85b557f7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 9ffbcc7..02ce02c 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -40,7 +40,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
   private final ZTree ztree = new ZTree();
   
   private final boolean testPointInSet;
-  private final Plane testPointVerticalPlane;
+  private final Plane testPointZPlane;
   private final GeoPoint[] edgePoints;
   private final Edge[] shapeStartEdges;
   
@@ -62,7 +62,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     if (p == null) {
       p = new Plane(1.0, 0.0, 0.0, 0.0);
     }
-    this.testPointVerticalPlane = p;
+    this.testPointZPlane = p;
     this.edgePoints = new GeoPoint[pointsList.size()];
     this.shapeStartEdges = new Edge[pointsList.size()];
     int edgePointIndex = 0;
@@ -109,7 +109,48 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
   @Override
   public boolean isWithin(final double x, final double y, final double z) {
-    // MHL
+    return isWithin(new Vector(x, y, z));
+  }
+  
+  @Override
+  public boolean isWithin(final Vector thePoint) {
+    // Construct a horizontal plane that goes through the provided z value.  This, along with the
+    // testPointZPlane, will provide a way of counting intersections between this point and the test point.
+    // We use z exclusively for this logic at the moment but we may in the future choose x or y based on which
+    // is bigger.
+    if (testPoint.isNumericallyIdentical(thePoint)) {
+      return true;
+    }
+    if (testPointZPlane.evaluateIsZero(thePoint)) {
+      // The point we are assessing goes through only one plane.
+      // Compute cutoff planes
+      final SidedPlane testPointCutoff =  new SidedPlane(thePoint, testPointZPlane, testPoint);
+      final SidedPlane checkPointCutoff = new SidedPlane(testPoint, testPointZPlane, thePoint);
+
+      // Count crossings
+      final CrossingEdgeIterator crossingEdgeIterator = new CrossingEdgeIterator(testPointZPlane, testPointCutoff, checkPointCutoff);
+      
+      // Compute bounds for this part of testZPlane
+      final XYZBounds testZPlaneBounds = new XYZBounds();
+      testPointZPlane.recordBounds(planetModel, testZPlaneBounds, testPointCutoff, checkPointCutoff);
+      
+      // Pick which tree to use
+      final double xDelta = testZPlaneBounds.getMaximumX() - testZPlaneBounds.getMinimumX();
+      final double yDelta = testZPlaneBounds.getMaximumY() - testZPlaneBounds.getMinimumY();
+      if (xDelta <= yDelta) {
+        xTree.traverse(crossingEdgeIterator, testZPlaneBounds.getMinimumX(), testZPlaneBounds.getMaximumX());
+      } else if (yDelta <= xDelta) {
+        yTree.traverse(crossingEdgeIterator, testZPlaneBounds.getMinimumY(), testZPlaneBounds.getMaximumY());
+      }
+      return ((crossingEdgeIterator.getCrossingCount() & 0x00000001) == 0)?testPointInSet:!testPointInSet;
+    } else {
+      // The point requires two planes
+      final Plane xyPlane = new Plane(planetModel, z);
+      // We need to plan a path from the test point to the point to be evaluated.
+      // This requires finding the intersection point between the xyPlane and the testPointZPlane
+      // that is closest to our point.
+      // MHL
+    }
     return false;
   }
   
@@ -460,6 +501,153 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
   }
   
+  /** Count the number of verifiable edge crossings.
+   */
+  private class CrossingEdgeIterator implements EdgeIterator {
+    
+    private final Plane plane;
+    private final Plane abovePlane;
+    private final Plane belowPlane;
+    private final Membership bound1;
+    private final Membership bound2;
+    
+    public int crossingCount = 0;
+    
+    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2) {
+      this.plane = plane;
+      this.abovePlane = new Plane(plane, true);
+      this.belowPlane = new Plane(plane, false);
+      this.bound1 = bound1;
+      this.bound2 = bound2;
+    }
+    
+    @Override
+    public boolean matches(final Edge edge) {
+      final GeoPoint[] crossingPoints = plane.findCrossings(planetModel, edge.plane, bound1, bound2, edge.startPlane, edge.endPlane);
+      if (crossingPoints != null) {
+        // We need to handle the endpoint case, which is quite tricky.
+        for (final GeoPoint crossingPoint : crossingPoints) {
+          countCrossingPoint(crossingPoint, plane, edge);
+        }
+      }
+      return true;
+    }
+
+    private void countCrossingPoint(final GeoPoint crossingPoint, final Plane plane, final Edge edge) {
+      if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
+        // We have to figure out if this crossing should be counted.
+        
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        
+        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        
+        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+          return;
+
+        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessAboveIntersections;
+        GeoPoint[] assessBelowIntersections;
+        while (true) {
+          assessEdge = assessEdge.previous;
+          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+            continue;
+          }
+          break;
+        }
+        
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        
+        // To handle the latter situation, we need to know if the other edge will be looked at also, and then we can make
+        // a decision whether to count or not based on that.
+        
+        // Compute the crossing points of this other edge.
+        final GeoPoint[] otherCrossingPoints = plane.findCrossings(planetModel, assessEdge.plane, bound1, bound2, assessEdge.startPlane, assessEdge.endPlane);
+        
+        // Look for a matching endpoint.  If the other endpoint doesn't show up, it is either out of bounds (in which case the
+        // transition won't be counted for that edge), or it is not a crossing for that edge (so, same conclusion).
+        for (final GeoPoint otherCrossingPoint : otherCrossingPoints) {
+          if (otherCrossingPoint.isNumericallyIdentical(assessEdge.endPoint)) {
+            // Found it!
+            // Both edges will try to contribute to the crossing count.  By convention, we'll only include the earlier one.
+            // Since we're the latter point, we exit here in that case.
+            return;
+          }
+        }
+        
+        // Both edges will not count the same point, so we can proceed.  We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+        
+        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
+        if (assessEdgeAbove != edgeCrossesAbove) {
+          crossingCount++;
+        }
+        
+      } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
+        // Figure out if the crossing should be counted.
+        
+        // Does the crossing for this edge go up, or down?  Or can't we tell?
+        final GeoPoint[] aboveIntersections = abovePlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        final GeoPoint[] belowIntersections = belowPlane.findIntersections(planetModel, edge.plane, edge.startPlane, edge.endPlane);
+        
+        assert !(aboveIntersections.length > 0 && belowIntersections.length > 0) : "edge that ends in a crossing can't both up and down";
+        
+        if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
+          return;
+
+        final boolean edgeCrossesAbove = aboveIntersections.length > 0;
+
+        // This depends on the previous edge that first departs from identicalness.
+        Edge assessEdge = edge;
+        GeoPoint[] assessAboveIntersections;
+        GeoPoint[] assessBelowIntersections;
+        while (true) {
+          assessEdge = assessEdge.next;
+          assessAboveIntersections = abovePlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+          assessBelowIntersections = belowPlane.findIntersections(planetModel, assessEdge.plane, assessEdge.startPlane, assessEdge.endPlane);
+
+          assert !(assessAboveIntersections.length > 0 && assessBelowIntersections.length > 0) : "assess edge that ends in a crossing can't both up and down";
+
+          if (assessAboveIntersections.length == 0 && assessBelowIntersections.length == 0) {
+            continue;
+          }
+          break;
+        }
+        
+        // Basically, we now want to assess whether both edges that come together at this endpoint leave the plane in opposite
+        // directions.  If they do, then we should count it as a crossing; if not, we should not.  We also have to remember that
+        // each edge we look at can also be looked at again if it, too, seems to cross the plane.
+        
+        // By definition, we're the earlier plane in this case, so any crossing we detect we must count, by convention.  It is unnecessary
+        // to consider what the other edge does, because when we get to it, it will look back and figure out what we did for this one.
+        
+        // We need to determine the direction of both edges at the
+        // point where they hit the plane.  This may be complicated by the 3D geometry; it may not be safe just to look at the endpoints of the edges
+        // and make an assessment that way, since a single edge can intersect the plane at more than one point.
+
+        final boolean assessEdgeAbove = assessAboveIntersections.length > 0;
+        if (assessEdgeAbove != edgeCrossesAbove) {
+          crossingCount++;
+        }
+
+      } else {
+        crossingCount++;
+      }
+    }
+  }
+  
   @Override
   public boolean equals(Object o) {
     // MHL

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/85b557f7/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
index a205ca9..66d093b 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -94,6 +94,24 @@ public class Plane extends Vector {
     this.D = D;
   }
 
+  /** Construct a plane that is parallel to the one provided, but which is just barely numerically
+   * distinguishable from it, in the direction desired.
+   * @param basePlane is the starting plane.
+   * @param above is set to true if the desired plane is in the positive direction from the base plane,
+   *   or false in the negative direction.
+   */
+  public Plane(final Plane basePlane, final boolean above) {
+    this(basePlane.x, basePlane.y, basePlane.z, outsideEnvelope(basePlane.D, above));
+  }
+  
+  private double outsideEnvelope(final double value, boolean above) {
+    if (above) {
+      return Math.nextUp(value + MINIMUM_RESOLUTION);
+    } else {
+      return Math.nextDown(value - MINIMUM_RESOLUTION);
+    }
+  }
+  
   /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
    * If none of the points can determine the plane, return null.
    * @param planePoints is a set of points to choose from.  The best one for constructing the most precise plane is picked.
@@ -191,7 +209,7 @@ public class Plane extends Vector {
     final double denom = 1.0 / Math.sqrt(y*y + z*z);
     return new Plane(0.0, z * denom, -y * denom, DValue);
   }
-  
+
   /**
    * Evaluate the plane equation for a given point, as represented
    * by a vector.


[04/25] lucene-solr:branch_6x: Flesh out the additional method needed in Plane, as well as intersection logic.

Posted by kw...@apache.org.
Flesh out the additional method needed in Plane, as well as intersection logic.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/ab7342ca
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/ab7342ca
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/ab7342ca

Branch: refs/heads/branch_6x
Commit: ab7342caba50b9c3a870ff00de376caf43e7a719
Parents: 2491ad4
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 02:40:31 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:21:42 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       |  86 +++++++++---
 .../org/apache/lucene/spatial3d/geom/Plane.java | 139 ++++++++++++++++++-
 2 files changed, 202 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ab7342ca/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index df89f55..9ffbcc7 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -120,8 +120,27 @@ class GeoComplexPolygon extends GeoBasePolygon {
 
   @Override
   public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
-    // MHL
-    return false;
+    // Create the intersector
+    final EdgeIterator intersector = new IntersectorEdgeIterator(p, notablePoints, bounds);
+    // First, compute the bounds for the the plane
+    final XYZBounds xyzBounds = new XYZBounds();
+    p.recordBounds(xyzBounds);
+    // Figure out which tree likely works best
+    final double xDelta = xyzBounds.getMaximumX() - xyzBounds.getMinimumX();
+    final double yDelta = xyzBounds.getMaximumY() - xyzBounds.getMinimumY();
+    final double zDelta = xyzBounds.getMaximumZ() - xyzBounds.getMinimumZ();
+    // Select the smallest range
+    if (xDelta <= yDelta && xDelta <= zDelta) {
+      // Drill down in x
+      return !xtree.traverse(intersector, xyzBounds.getMinimumX(), xyzBounds.getMaximumX());
+    } else if (yDelta <= xDelta && yDelta <= zDelta) {
+      // Drill down in y
+      return !ytree.traverse(intersector, xyzBounds.getMinimumY(), xyzBounds.getMaximumY());
+    } else if (zDelta <= xDelta && zDelta <= yDelta) {
+      // Drill down in z
+      return !ztree.traverse(intersector, xyzBounds.getMinimumZ(), xyzBounds.getMaximumZ());
+    }
+    return true;
   }
 
 
@@ -153,6 +172,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
   private static class Edge {
     public final GeoPoint startPoint;
     public final GeoPoint endPoint;
+    public final GeoPoint[] notablePoints;
     public final SidedPlane startPlane;
     public final SidedPlane endPlane;
     public final Plane plane;
@@ -163,6 +183,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     public Edge(final PlanetModel pm, final GeoPoint startPoint, final GeoPoint endPoint) {
       this.startPoint = startPoint;
       this.endPoint = endPoint;
+      this.notablePoints = new GeoPoint[]{startPoint, endPoint};
       this.plane = new Plane(startPoint, endPoint);
       this.startPlane =  new SidedPlane(endPoint, plane, startPoint);
       this.endPlane = new SidedPlane(startPoint, plane, endPoint);
@@ -193,10 +214,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
     /**
      * Compare an edge.
      * @param edge is the edge to compare.
-     * @param value is the value to compare.
+     * @param minValue is the minimum value to compare (bottom of the range)
+     * @param maxValue is the maximum value to compare (top of the range)
      * @return -1 if "less" than this one, 0 if overlaps, or 1 if "greater".
      */
-    public int compare(final Edge edge, final double value);
+    public int compare(final Edge edge, final double minValue, final double maxValue);
     
   }
 
@@ -263,10 +285,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
-    public boolean traverse(final EdgeIterator edgeIterator, final TraverseComparator edgeComparator, final double value) {
+    public boolean traverse(final EdgeIterator edgeIterator, final TraverseComparator edgeComparator, final double minValue, final double maxValue) {
       Node currentNode = this;
       while (currentNode != null) {
-        final int result = edgeComparator.compare(currentNode.edge, value);
+        final int result = edgeComparator.compare(currentNode.edge, minValue, maxValue);
         if (result < 0) {
           currentNode = lesser;
         } else if (result > 0) {
@@ -298,11 +320,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
-    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
       }
-      return rootNode.traverse(edgeIterator, this, value);
+      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
     }
     
     @Override
@@ -316,10 +338,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     @Override
-    public int compare(final Edge edge, final double value) {
-      if (edge.planeBounds.getMinimumZ() > value) {
+    public int compare(final Edge edge, final double minValue, final double maxValue) {
+      if (edge.planeBounds.getMinimumZ() > maxValue) {
         return -1;
-      } else if (edge.planeBounds.getMaximumZ() < value) {
+      } else if (edge.planeBounds.getMaximumZ() < minValue) {
         return 1;
       }
       return 0;
@@ -343,11 +365,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
-    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
       }
-      return rootNode.traverse(edgeIterator, this, value);
+      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
     }
     
     @Override
@@ -361,10 +383,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     @Override
-    public int compare(final Edge edge, final double value) {
-      if (edge.planeBounds.getMinimumY() > value) {
+    public int compare(final Edge edge, final double minValue, final double maxValue) {
+      if (edge.planeBounds.getMinimumY() > maxValue) {
         return -1;
-      } else if (edge.planeBounds.getMaximumY() < value) {
+      } else if (edge.planeBounds.getMaximumY() < minValue) {
         return 1;
       }
       return 0;
@@ -388,11 +410,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
     }
     
-    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
       if (rootNode == null) {
         return true;
       }
-      return rootNode.traverse(edgeIterator, this, value);
+      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
     }
     
     @Override
@@ -406,10 +428,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     @Override
-    public int compare(final Edge edge, final double value) {
-      if (edge.planeBounds.getMinimumX() > value) {
+    public int compare(final Edge edge, final double minValue, final double maxValue) {
+      if (edge.planeBounds.getMinimumX() > maxValue) {
         return -1;
-      } else if (edge.planeBounds.getMaximumX() < value) {
+      } else if (edge.planeBounds.getMaximumX() < minValue) {
         return 1;
       }
       return 0;
@@ -417,6 +439,27 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
   }
 
+  /** Assess whether edge intersects the provided plane plus bounds.
+   */
+  private class IntersectorEdgeIterator implements EdgeIterator {
+    
+    private final Plane plane;
+    private final GeoPoint[] notablePoints;
+    private final Membership[] bounds;
+    
+    public IntersectorEdgeIterator(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+      this.plane = plane;
+      this notablePoints = notablePoints;
+      this.bounds = bounds;
+    }
+    
+    @Override
+    public boolean matches(final Edge edge) {
+      return !plane.intersects(planetModel, edge.plane, notablePoints, edge.notablePoints, bounds, edge.startPlane, edge.endPlane);
+    }
+
+  }
+  
   @Override
   public boolean equals(Object o) {
     // MHL
@@ -426,6 +469,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
   @Override
   public int hashCode() {
     // MHL
+    return 0;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/ab7342ca/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
index f0df49d..a205ca9 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -614,11 +614,11 @@ public class Plane extends Vector {
   }
 
   /**
-   * Public version of findIntersections.
+   * Find the intersection points between two planes, given a set of bounds.
    * @param planetModel is the planet model.
    * @param q is the plane to intersect with.
    * @param bounds are the bounds to consider to determine legal intersection points.
-   * @return the set of legal intersection points.
+   * @return the set of legal intersection points, or null if the planes are numerically identical.
    */
   public GeoPoint[] findIntersections(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
     if (isNumericallyIdentical(q)) {
@@ -626,6 +626,23 @@ public class Plane extends Vector {
     }
     return findIntersections(planetModel, q, bounds, NO_BOUNDS);
   }
+
+  /**
+   * Find the points between two planes, where one plane crosses the other, given a set of bounds.
+   * Crossing is not just intersection; the planes cannot touch at just one point on the ellipsoid,
+   * but must cross at two.
+   *
+   * @param planetModel is the planet model.
+   * @param q is the plane to intersect with.
+   * @param bounds are the bounds to consider to determine legal intersection points.
+   * @return the set of legal crossing points, or null if the planes are numerically identical.
+   */
+  public GeoPoint[] findCrossings(final PlanetModel planetModel, final Plane q, final Membership... bounds) {
+    if (isNumericallyIdentical(q)) {
+      return null;
+    }
+    return findCrossings(planetModel, q, bounds, NO_BOUNDS);
+  }
   
   /**
    * Find the intersection points between two planes, given a set of bounds.
@@ -755,6 +772,124 @@ public class Plane extends Vector {
     }
   }
 
+  /**
+   * Find the points between two planes, where one plane crosses the other, given a set of bounds.
+   * Crossing is not just intersection; the planes cannot touch at just one point on the ellipsoid,
+   * but must cross at two.
+   *
+   * @param planetModel is the planet model to use in finding points.
+   * @param q          is the plane to intersect with.
+   * @param bounds     is the set of bounds.
+   * @param moreBounds is another set of bounds.
+   * @return the intersection point(s) on the ellipsoid, if there are any.
+   */
+  protected GeoPoint[] findCrosses(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
+    // This code in this method is very similar to findIntersections(), but eliminates the cases where
+    // crossings are detected.
+    // Unnormalized, unchecked...
+    final Vector lineVector = new Vector(y * q.z - z * q.y, z * q.x - x * q.z, x * q.y - y * q.x);
+    if (Math.abs(lineVector.x) < MINIMUM_RESOLUTION && Math.abs(lineVector.y) < MINIMUM_RESOLUTION && Math.abs(lineVector.z) < MINIMUM_RESOLUTION) {
+      // Degenerate case: parallel planes
+      return NO_POINTS;
+    }
+
+    // The line will have the equation: A t + A0 = x, B t + B0 = y, C t + C0 = z.
+    // We have A, B, and C.  In order to come up with A0, B0, and C0, we need to find a point that is on both planes.
+    // To do this, we find the largest vector value (either x, y, or z), and look for a point that solves both plane equations
+    // simultaneous.  For example, let's say that the vector is (0.5,0.5,1), and the two plane equations are:
+    // 0.7 x + 0.3 y + 0.1 z + 0.0 = 0
+    // and
+    // 0.9 x - 0.1 y + 0.2 z + 4.0 = 0
+    // Then we'd pick z = 0, so the equations to solve for x and y would be:
+    // 0.7 x + 0.3y = 0.0
+    // 0.9 x - 0.1y = -4.0
+    // ... which can readily be solved using standard linear algebra.  Generally:
+    // Q0 x + R0 y = S0
+    // Q1 x + R1 y = S1
+    // ... can be solved by Cramer's rule:
+    // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
+    // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
+    // ... where det( a b / c d ) = ad - bc, so:
+    // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
+    // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
+    double x0;
+    double y0;
+    double z0;
+    // We try to maximize the determinant in the denominator
+    final double denomYZ = this.y * q.z - this.z * q.y;
+    final double denomXZ = this.x * q.z - this.z * q.x;
+    final double denomXY = this.x * q.y - this.y * q.x;
+    if (Math.abs(denomYZ) >= Math.abs(denomXZ) && Math.abs(denomYZ) >= Math.abs(denomXY)) {
+      // X is the biggest, so our point will have x0 = 0.0
+      if (Math.abs(denomYZ) < MINIMUM_RESOLUTION_SQUARED) {
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomYZ;
+      x0 = 0.0;
+      y0 = (-this.D * q.z - this.z * -q.D) * denom;
+      z0 = (this.y * -q.D + this.D * q.y) * denom;
+    } else if (Math.abs(denomXZ) >= Math.abs(denomXY) && Math.abs(denomXZ) >= Math.abs(denomYZ)) {
+      // Y is the biggest, so y0 = 0.0
+      if (Math.abs(denomXZ) < MINIMUM_RESOLUTION_SQUARED) {
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXZ;
+      x0 = (-this.D * q.z - this.z * -q.D) * denom;
+      y0 = 0.0;
+      z0 = (this.x * -q.D + this.D * q.x) * denom;
+    } else {
+      // Z is the biggest, so Z0 = 0.0
+      if (Math.abs(denomXY) < MINIMUM_RESOLUTION_SQUARED) {
+        return NO_POINTS;
+      }
+      final double denom = 1.0 / denomXY;
+      x0 = (-this.D * q.y - this.y * -q.D) * denom;
+      y0 = (this.x * -q.D + this.D * q.x) * denom;
+      z0 = 0.0;
+    }
+
+    // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
+    // will yield zero, one, or two points.
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // Use the quadratic formula to determine t values and candidate point(s)
+    final double A = lineVector.x * lineVector.x * planetModel.inverseAbSquared +
+      lineVector.y * lineVector.y * planetModel.inverseAbSquared +
+      lineVector.z * lineVector.z * planetModel.inverseCSquared;
+    final double B = 2.0 * (lineVector.x * x0 * planetModel.inverseAbSquared + lineVector.y * y0 * planetModel.inverseAbSquared + lineVector.z * z0 * planetModel.inverseCSquared);
+    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+
+    final double BsquaredMinus = B * B - 4.0 * A * C;
+    if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
+      // One point of intersection: cannot be a crossing.
+      return NO_POINTS;
+    } else if (BsquaredMinus > 0.0) {
+      final double inverse2A = 1.0 / (2.0 * A);
+      // Two solutions
+      final double sqrtTerm = Math.sqrt(BsquaredMinus);
+      final double t1 = (-B + sqrtTerm) * inverse2A;
+      final double t2 = (-B - sqrtTerm) * inverse2A;
+      GeoPoint point1 = new GeoPoint(lineVector.x * t1 + x0, lineVector.y * t1 + y0, lineVector.z * t1 + z0);
+      GeoPoint point2 = new GeoPoint(lineVector.x * t2 + x0, lineVector.y * t2 + y0, lineVector.z * t2 + z0);
+      //verifyPoint(planetModel, point1, q);
+      //verifyPoint(planetModel, point2, q);
+      //System.err.println("  "+point1+" and "+point2);
+      if (point1.isWithin(bounds, moreBounds)) {
+        if (point2.isWithin(bounds, moreBounds))
+          return new GeoPoint[]{point1, point2};
+        return new GeoPoint[]{point1};
+      }
+      if (point2.isWithin(bounds, moreBounds))
+        return new GeoPoint[]{point2};
+      return NO_POINTS;
+    } else {
+      // No solutions.
+      return NO_POINTS;
+    }
+  }
+
   /*
   protected void verifyPoint(final PlanetModel planetModel, final GeoPoint point, final Plane q) {
     if (!evaluateIsZero(point))


[08/25] lucene-solr:branch_6x: Get it to compile

Posted by kw...@apache.org.
Get it to compile


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/6bb6b4e8
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/6bb6b4e8
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/6bb6b4e8

Branch: refs/heads/branch_6x
Commit: 6bb6b4e82aaf0221a7375f3d4946f19312983166
Parents: 754ee14
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 25 14:33:38 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:22:44 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 55 ++++++++------------
 .../org/apache/lucene/spatial3d/geom/Plane.java | 12 +----
 2 files changed, 25 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6bb6b4e8/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 229f9f4..9b6f670 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -35,11 +35,12 @@ import java.util.Map;
  */
 class GeoComplexPolygon extends GeoBasePolygon {
   
-  private final XTree xtree = new XTree();
-  private final YTree ytree = new YTree();
-  private final ZTree ztree = new ZTree();
+  private final XTree xTree = new XTree();
+  private final YTree yTree = new YTree();
+  private final ZTree zTree = new ZTree();
   
   private final boolean testPointInSet;
+  private final GeoPoint testPoint;
   
   private final Plane testPointXZPlane;
   private final Plane testPointYZPlane;
@@ -62,6 +63,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
   public GeoComplexPolygon(final PlanetModel planetModel, final List<List<GeoPoint>> pointsList, final GeoPoint testPoint, final boolean testPointInSet) {
     super(planetModel);
     this.testPointInSet = testPointInSet;
+    this.testPoint = testPoint;
     
     this.testPointXZPlane = new Plane(0.0, 1.0, 0.0, -testPoint.y);
     this.testPointYZPlane = new Plane(1.0, 0.0, 0.0, -testPoint.x);
@@ -71,15 +73,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
     this.shapeStartEdges = new Edge[pointsList.size()];
     int edgePointIndex = 0;
     for (final List<GeoPoint> shapePoints : pointsList) {
-      GeoPoint lastGeoPoint = pointsList.get(shapePoints.size()-1);
+      GeoPoint lastGeoPoint = shapePoints.get(shapePoints.size()-1);
       edgePoints[edgePointIndex] = lastGeoPoint;
       Edge lastEdge = null;
       Edge firstEdge = null;
       for (final GeoPoint thisGeoPoint : shapePoints) {
         final Edge edge = new Edge(planetModel, lastGeoPoint, thisGeoPoint);
-        xtree.add(edge);
-        ytree.add(edge);
-        ztree.add(edge);
+        xTree.add(edge);
+        yTree.add(edge);
+        zTree.add(edge);
         // Now, link
         if (firstEdge == null) {
           firstEdge = edge;
@@ -98,19 +100,6 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
   }
 
-  /** Compute a legal point index from a possibly illegal one, that may have wrapped.
-   *@param index is the index.
-   *@return the normalized index.
-   */
-  protected int legalIndex(int index) {
-    while (index >= points.size())
-      index -= points.size();
-    while (index < 0) {
-      index += points.size();
-    }
-    return index;
-  }
-
   @Override
   public boolean isWithin(final double x, final double y, final double z) {
     return isWithin(new Vector(x, y, z));
@@ -181,7 +170,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointYZPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         xTree.traverse(testPointEdgeIterator, testPoint.x, testPoint.x);
         final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!yTree.traverse(checkPointEdgeIterator, thePoint.y, thePoint.y)) {
@@ -204,7 +193,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXYPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         zTree.traverse(testPointEdgeIterator, testPoint.z, testPoint.z);
         final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!xTree.traverse(checkPointEdgeIterator, thePoint.x, thePoint.x)) {
@@ -227,7 +216,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final SidedPlane checkPointOtherCutoffPlane = new SidedPlane(thePoint, travelPlane, intersectionPoints[0]);
         // Note: we need to handle the cases where end point of the first leg sits on an edge!
         // MHL
-        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoffPlane, testPointOtherCutoffPlane);
+        final CrossingEdgeIterator testPointEdgeIterator = new CrossingEdgeIterator(testPointXZPlane, testPointCutoffPlane, testPointOtherCutoffPlane, null);
         yTree.traverse(testPointEdgeIterator, testPoint.y, testPoint.y);
         final CrossingEdgeIterator checkPointEdgeIterator = new CrossingEdgeIterator(travelPlane, checkPointCutoffPlane, checkPointOtherCutoffPlane, thePoint);
         if (!zTree.traverse(checkPointEdgeIterator, thePoint.z, thePoint.z)) {
@@ -251,7 +240,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     final EdgeIterator intersector = new IntersectorEdgeIterator(p, notablePoints, bounds);
     // First, compute the bounds for the the plane
     final XYZBounds xyzBounds = new XYZBounds();
-    p.recordBounds(xyzBounds);
+    p.recordBounds(planetModel, xyzBounds, bounds);
     // Figure out which tree likely works best
     final double xDelta = xyzBounds.getMaximumX() - xyzBounds.getMinimumX();
     final double yDelta = xyzBounds.getMaximumY() - xyzBounds.getMinimumY();
@@ -259,13 +248,13 @@ class GeoComplexPolygon extends GeoBasePolygon {
     // Select the smallest range
     if (xDelta <= yDelta && xDelta <= zDelta) {
       // Drill down in x
-      return !xtree.traverse(intersector, xyzBounds.getMinimumX(), xyzBounds.getMaximumX());
+      return !xTree.traverse(intersector, xyzBounds.getMinimumX(), xyzBounds.getMaximumX());
     } else if (yDelta <= xDelta && yDelta <= zDelta) {
       // Drill down in y
-      return !ytree.traverse(intersector, xyzBounds.getMinimumY(), xyzBounds.getMaximumY());
+      return !yTree.traverse(intersector, xyzBounds.getMinimumY(), xyzBounds.getMaximumY());
     } else if (zDelta <= xDelta && zDelta <= yDelta) {
       // Drill down in z
-      return !ztree.traverse(intersector, xyzBounds.getMinimumZ(), xyzBounds.getMaximumZ());
+      return !zTree.traverse(intersector, xyzBounds.getMinimumZ(), xyzBounds.getMaximumZ());
     }
     return true;
   }
@@ -277,7 +266,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     for (final Edge startEdge : shapeStartEdges) {
       Edge currentEdge = startEdge;
       while (true) {
-        currentEdge.plane.recordBounds(this.planetModel, currentEdge.startPlane, currentEdge.edgePlane);
+        bounds.addPlane(this.planetModel, currentEdge.plane, currentEdge.startPlane, currentEdge.endPlane);
         currentEdge = currentEdge.next;
         if (currentEdge == startEdge) {
           break;
@@ -576,7 +565,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     public IntersectorEdgeIterator(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
       this.plane = plane;
-      this notablePoints = notablePoints;
+      this.notablePoints = notablePoints;
       this.bounds = bounds;
     }
     
@@ -596,11 +585,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
     private final Plane belowPlane;
     private final Membership bound1;
     private final Membership bound2;
-    private final GeoPoint thePoint;
+    private final Vector thePoint;
     
     public int crossingCount = 0;
     
-    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2, final GeoPoint thePoint) {
+    public CrossingEdgeIterator(final Plane plane, final Membership bound1, final Membership bound2, final Vector thePoint) {
       this.plane = plane;
       this.abovePlane = new Plane(plane, true);
       this.belowPlane = new Plane(plane, false);
@@ -612,7 +601,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
     @Override
     public boolean matches(final Edge edge) {
       // Early exit if the point is on the edge.
-      if (edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
+      if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
         return false;
       }
       final GeoPoint[] crossingPoints = plane.findCrossings(planetModel, edge.plane, bound1, bound2, edge.startPlane, edge.endPlane);
@@ -637,6 +626,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         
         if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
           return;
+        }
 
         final boolean edgeCrossesAbove = aboveIntersections.length > 0;
 
@@ -698,6 +688,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         
         if (aboveIntersections.length == 0 && belowIntersections.length == 0) {
           return;
+        }
 
         final boolean edgeCrossesAbove = aboveIntersections.length > 0;
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6bb6b4e8/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
index 66d093b..2408052 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -101,15 +101,7 @@ public class Plane extends Vector {
    *   or false in the negative direction.
    */
   public Plane(final Plane basePlane, final boolean above) {
-    this(basePlane.x, basePlane.y, basePlane.z, outsideEnvelope(basePlane.D, above));
-  }
-  
-  private double outsideEnvelope(final double value, boolean above) {
-    if (above) {
-      return Math.nextUp(value + MINIMUM_RESOLUTION);
-    } else {
-      return Math.nextDown(value - MINIMUM_RESOLUTION);
-    }
+    this(basePlane.x, basePlane.y, basePlane.z, above?Math.nextUp(basePlane.D + MINIMUM_RESOLUTION):Math.nextDown(basePlane.D - MINIMUM_RESOLUTION));
   }
   
   /** Construct the most accurate normalized plane through an x-y point and including the Z axis.
@@ -801,7 +793,7 @@ public class Plane extends Vector {
    * @param moreBounds is another set of bounds.
    * @return the intersection point(s) on the ellipsoid, if there are any.
    */
-  protected GeoPoint[] findCrosses(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
+  protected GeoPoint[] findCrossings(final PlanetModel planetModel, final Plane q, final Membership[] bounds, final Membership[] moreBounds) {
     // This code in this method is very similar to findIntersections(), but eliminates the cases where
     // crossings are detected.
     // Unnormalized, unchecked...


[02/25] lucene-solr:branch_6x: Add Edge subclass

Posted by kw...@apache.org.
Add Edge subclass


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/266a9a94
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/266a9a94
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/266a9a94

Branch: refs/heads/branch_6x
Commit: 266a9a949e00635241fb1ebb43abcba2438d89bc
Parents: 086330f
Author: Karl Wright <Da...@gmail.com>
Authored: Sun Apr 24 02:18:23 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:18:09 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 23 ++++++++++++++++++++
 1 file changed, 23 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/266a9a94/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 7fc53e8..3071fc8 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -93,6 +93,29 @@ class GeoComplexPolygon extends GeoBasePolygon {
     // MHL
   }
 
+  /**
+   * An instance of this class describes a single edge, and includes what is necessary to reliably determine intersection
+   * in the context of the even/odd algorithm used.
+   */
+  private static class Edge {
+    public final GeoPoint startPoint;
+    public final GeoPoint endPoint;
+    public final SidedPlane startPlane;
+    public final SidedPlane endPlane;
+    public final Plane plane;
+    public final XYZBounds planeBounds;
+    
+    public Edge(final PlanetModel pm, final GeoPoint startPoint, final GeoPoint endPoint) {
+      this.startPoint = startPoint;
+      this.endPoint = endPoint;
+      this.plane = new Plane(startPoint, endPoint);
+      this.startPlane =  new SidedPlane(endPoint, plane, startPoint);
+      this.endPlane = new SidedPlane(startPoint, plane, endPoint);
+      this.planeBounds = new XYZBounds();
+      this.plane.recordBounds(pm, this.planeBounds, this.startPlane, this.endPlane);
+    }
+  }
+  
   @Override
   public boolean equals(Object o) {
     // MHL


[20/25] lucene-solr:branch_6x: Rewrite tree handling to actually work.

Posted by kw...@apache.org.
Rewrite tree handling to actually work.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/aa7adc19
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/aa7adc19
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/aa7adc19

Branch: refs/heads/branch_6x
Commit: aa7adc190e5b1da919fb3320321e06b42397f5be
Parents: 5545e9e
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 08:12:42 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:25:57 2016 -0400

----------------------------------------------------------------------
 .../spatial3d/geom/GeoComplexPolygon.java       | 382 ++++++++++---------
 1 file changed, 202 insertions(+), 180 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/aa7adc19/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 06d6dba..3eff223 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -16,11 +16,9 @@
  */
 package org.apache.lucene.spatial3d.geom;
 
-import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.List;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
 
 /**
  * GeoComplexPolygon objects are structures designed to handle very large numbers of edges.
@@ -130,7 +128,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the XZ plane exclusively.
       final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXZPlane, testPointXZAbovePlane, testPointXZBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the y tree because that's fixed.
-      if (!yTree.traverse(crossingEdgeIterator, testPoint.y, testPoint.y)) {
+      if (!yTree.traverse(crossingEdgeIterator, testPoint.y)) {
         // Endpoint is on edge
         return true;
       }
@@ -139,7 +137,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the YZ plane exclusively.
       final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointYZPlane, testPointYZAbovePlane, testPointYZBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the x tree because that's fixed.
-      if (!xTree.traverse(crossingEdgeIterator, testPoint.x, testPoint.x)) {
+      if (!xTree.traverse(crossingEdgeIterator, testPoint.x)) {
         // Endpoint is on edge
         return true;
       }
@@ -148,7 +146,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // Use the XY plane exclusively.
       final LinearCrossingEdgeIterator crossingEdgeIterator = new LinearCrossingEdgeIterator(testPointXYPlane, testPointXYAbovePlane, testPointXYBelowPlane, testPoint, thePoint);
       // Traverse our way from the test point to the check point.  Use the z tree because that's fixed.
-      if (!zTree.traverse(crossingEdgeIterator, testPoint.z, testPoint.z)) {
+      if (!zTree.traverse(crossingEdgeIterator, testPoint.z)) {
         // Endpoint is on edge
         return true;
       }
@@ -280,11 +278,11 @@ class GeoComplexPolygon extends GeoBasePolygon {
       assert bestDistance < Double.MAX_VALUE : "Couldn't find an intersection point of any kind";
       
       final DualCrossingEdgeIterator edgeIterator = new DualCrossingEdgeIterator(firstLegPlane, firstLegAbovePlane, firstLegBelowPlane, secondLegPlane, testPoint, thePoint, intersectionPoint);
-      if (!firstLegTree.traverse(edgeIterator, firstLegValue, firstLegValue)) {
+      if (!firstLegTree.traverse(edgeIterator, firstLegValue)) {
         return true;
       }
       edgeIterator.setSecondLeg();
-      if (!secondLegTree.traverse(edgeIterator, secondLegValue, secondLegValue)) {
+      if (!secondLegTree.traverse(edgeIterator, secondLegValue)) {
         return true;
       }
       return ((edgeIterator.crossingCount  & 1) == 0)?testPointInSet:!testPointInSet;
@@ -304,6 +302,9 @@ class GeoComplexPolygon extends GeoBasePolygon {
     // First, compute the bounds for the the plane
     final XYZBounds xyzBounds = new XYZBounds();
     p.recordBounds(planetModel, xyzBounds, bounds);
+    for (final GeoPoint point : notablePoints) {
+      xyzBounds.addPoint(point);
+    }
     // Figure out which tree likely works best
     final double xDelta = xyzBounds.getMaximumX() - xyzBounds.getMinimumX();
     final double yDelta = xyzBounds.getMaximumY() - xyzBounds.getMinimumY();
@@ -387,6 +388,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       this.planeBounds.addPoint(startPoint);
       this.planeBounds.addPoint(endPoint);
       this.plane.recordBounds(pm, this.planeBounds, this.startPlane, this.endPlane);
+      System.err.println("Recording edge from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
     }
   }
   
@@ -404,39 +406,6 @@ class GeoComplexPolygon extends GeoBasePolygon {
   }
   
   /**
-   * Comparison interface for tree traversal.  An object implementing this interface
-   * gets to decide the relationship between the Edge object and the criteria being considered.
-   */
-  private static interface TraverseComparator {
-    
-    /**
-     * Compare an edge.
-     * @param edge is the edge to compare.
-     * @param minValue is the minimum value to compare (bottom of the range)
-     * @param maxValue is the maximum value to compare (top of the range)
-     * @return -1 if "less" than this one, 0 if overlaps, or 1 if "greater".
-     */
-    public int compare(final Edge edge, final double minValue, final double maxValue);
-    
-  }
-
-  /**
-   * Comparison interface for tree addition.  An object implementing this interface
-   * gets to decide the relationship between the Edge object and the criteria being considered.
-   */
-  private static interface AddComparator {
-    
-    /**
-     * Compare an edge.
-     * @param edge is the edge to compare.
-     * @param addEdge is the edge being added.
-     * @return -1 if "less" than this one, 0 if overlaps, or 1 if "greater".
-     */
-    public int compare(final Edge edge, final Edge addEdge);
-    
-  }
-  
-  /**
    * An instance of this class represents a node in a tree.  The tree is designed to be given
    * a value and from that to iterate over a list of edges.
    * In order to do this efficiently, each new edge is dropped into the tree using its minimum and
@@ -448,207 +417,249 @@ class GeoComplexPolygon extends GeoBasePolygon {
    *
    */
   private static class Node {
+    public final double minimumValue;
+    public final double maximumValue;
     public final Edge edge;
     public Node lesser = null;
     public Node greater = null;
-    public Node overlaps = null;
+    public Node within = null;
     
-    public Node(final Edge edge) {
+    public Node(final Edge edge, final double minimumValue, final double maximumValue) {
       this.edge = edge;
+      this.minimumValue = minimumValue;
+      this.maximumValue = maximumValue;
     }
     
-    public void add(final Edge newEdge, final AddComparator edgeComparator) {
-      Node currentNode = this;
-      while (true) {
-        final int result = edgeComparator.compare(currentNode.edge, newEdge);
-        if (result < 0) {
-          if (currentNode.lesser == null) {
-            currentNode.lesser = new Node(newEdge);
-            return;
-          }
-          currentNode = currentNode.lesser;
-        } else if (result > 0) {
-          if (currentNode.greater == null) {
-            currentNode.greater = new Node(newEdge);
-            return;
-          }
-          currentNode = currentNode.greater;
-        } else {
-          if (currentNode.overlaps == null) {
-            currentNode.overlaps = new Node(newEdge);
-            return;
-          }
-          currentNode = currentNode.overlaps;
-        }
+  }
+  
+  /** An interface describing a tree.
+   */
+  private static abstract class Tree {
+    private Node rootNode = null;
+    
+    protected static final int CONTAINED = 0;
+    protected static final int WITHIN = 1;
+    protected static final int OVERLAPS_MINIMUM = 2;
+    protected static final int OVERLAPS_MAXIMUM = 3;
+    protected static final int LESS = 4;
+    protected static final int GREATER = 5;
+    
+    /** Add a new edge to the tree.
+     * @param edge is the edge to add.
+     */
+    public void add(final Edge edge) {
+      rootNode = addEdge(rootNode, edge, getMinimum(edge), getMaximum(edge));
+    }
+
+    /** Get the minimum value from the edge.
+     * @param edge is the edge.
+     * @return the minimum value.
+     */
+    protected abstract double getMinimum(final Edge edge);
+    
+    /** Get the maximum value from the edge.
+     * @param edge is the edge.
+     * @return the maximum value.
+     */
+    protected abstract double getMaximum(final Edge edge);
+    
+    /** Worker method for adding an edge.
+     * @param node is the node to add into.
+     * @param newEdge is the new edge to add.
+     * @param minimumValue is the minimum limit of the subrange of the edge we'll be adding.
+     * @param maximumValue is the maximum limit of the subrange of the edge we'll be adding.
+     * @return the updated node reference.
+     */
+    protected Node addEdge(final Node node, final Edge newEdge, final double minimumValue, final double maximumValue) {
+      if (node == null) {
+        // Create and return a new node
+        return new Node(newEdge, minimumValue, maximumValue);
+      }
+      // Compare with what's here
+      int result = compareForAdd(node.minimumValue, node.maximumValue, minimumValue, maximumValue);
+      switch (result) {
+      case CONTAINED:
+        // The node is contained in the range provided.  We need to create a new node and insert
+        // it into the "within" chain.
+        final Node rval = new Node(newEdge, minimumValue, maximumValue);
+        rval.within = node.within;
+        return rval;
+      case WITHIN:
+        // The new edge is within the node provided
+        node.within = addEdge(node.within, newEdge, minimumValue, maximumValue);
+        return node;
+      case OVERLAPS_MINIMUM:
+        // The new edge overlaps the minimum value, but not the maximum value.
+        // Here we need to create TWO entries: one for the lesser side, and one for the within chain.
+        final double lesserMaximum = Math.nextDown(node.minimumValue);
+        node.lesser = addEdge(node.lesser, newEdge, minimumValue, lesserMaximum);
+        return addEdge(node, newEdge, node.minimumValue, maximumValue);
+      case OVERLAPS_MAXIMUM:
+        // The new edge overlaps the maximum value, but not the minimum value.
+        // Need to create two entries, one on the greater side, and one back into the current node.
+        final double greaterMinimum = Math.nextUp(node.maximumValue);
+        node.greater = addEdge(node.greater, newEdge, greaterMinimum, maximumValue);
+        return addEdge(node, newEdge, minimumValue, node.maximumValue);
+      case LESS:
+        // The new edge is clearly less than the current node.
+        node.lesser = addEdge(node.lesser, newEdge, minimumValue, maximumValue);
+        return node;
+      case GREATER:
+        // The new edge is clearly greater than the current node.
+        node.greater = addEdge(node.greater, newEdge, minimumValue, maximumValue);
+        return node;
+      default:
+        throw new RuntimeException("Unexpected comparison result: "+result);
       }
+      
     }
     
-    public boolean traverse(final EdgeIterator edgeIterator, final TraverseComparator edgeComparator, final double minValue, final double maxValue) {
-      Node currentNode = this;
+    /** Traverse the tree, finding all edges that intersect the provided value.
+     * @param edgeIterator provides the method to call for any encountered matching edge.
+     * @param value is the value to match.
+     * @return false if the traversal was aborted before completion.
+     */
+    public boolean traverse(final EdgeIterator edgeIterator, final double value) {
+      // Since there is one distinct value we are looking for, we can just do a straight descent through the nodes.
+      Node currentNode = rootNode;
       while (currentNode != null) {
-        final int result = edgeComparator.compare(currentNode.edge, minValue, maxValue);
-        if (result < 0) {
+        if (value < currentNode.minimumValue) {
           currentNode = currentNode.lesser;
-        } else if (result > 0) {
+        } else if (value > currentNode.maximumValue) {
           currentNode = currentNode.greater;
         } else {
+          // We're within the bounds of the node.  Call the iterator, and descend
           if (!edgeIterator.matches(currentNode.edge)) {
             return false;
           }
-          currentNode = currentNode.overlaps;
+          currentNode = currentNode.within;
         }
       }
       return true;
     }
-  }
-  
-  /** An interface describing a tree.
-   */
-  private static interface Tree {
-    
-    public void add(final Edge edge);
     
-    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue);
+    /** Traverse the tree, finding all edges that intersect the provided value range.
+     * @param edgeIterator provides the method to call for any encountered matching edge.
+     *   Edges will not be invoked more than once.
+     * @param minValue is the minimum value.
+     * @param maxValue is the maximum value.
+     * @return false if the traversal was aborted before completion.
+     */
+    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
+      // This is tricky because edges are duplicated in the tree (where they got split).
+      // We need to eliminate those duplicate edges as we traverse.  This requires us to keep a set of edges we've seen.
+      // Luckily, the number of edges we're likely to encounter in a real-world situation is small, so we can get away with it.
+      return traverseEdges(rootNode, edgeIterator, minValue, maxValue, new HashSet<>());
+    }
 
+    protected boolean traverseEdges(final Node node, final EdgeIterator edgeIterator, final double minValue, final double maxValue, final Set<Edge> edgeSet) {
+      if (node == null) {
+        return true;
+      }
+      if (maxValue < node.minimumValue) {
+        return traverseEdges(node.lesser, edgeIterator, minValue, maxValue, edgeSet);
+      } else if (minValue > node.maximumValue) {
+        return traverseEdges(node.greater, edgeIterator, minValue, maxValue, edgeSet);
+      } else {
+        // There's overlap with the current node, and there may also be overlap with the lesser side and greater side
+        if (minValue < node.minimumValue) {
+          if (!traverseEdges(node.lesser, edgeIterator, minValue, maxValue, edgeSet)) {
+            return false;
+          }
+        }
+        if (!edgeSet.contains(node.edge)) {
+          if (!edgeIterator.matches(node.edge)) {
+            return false;
+          }
+          edgeSet.add(node.edge);
+        }
+        if (maxValue > node.maximumValue) {
+          if (!traverseEdges(node.greater, edgeIterator, minValue, maxValue, edgeSet)) {
+            return false;
+          }
+        }
+        return traverseEdges(node.within, edgeIterator, minValue, maxValue, edgeSet);
+      }
+    }
+    
+    /** Compare a node against a subrange of a new edge.
+     * @param node is the node to compare.
+     * @param newEdge is the edge being added.
+     * @param minimumValue is the minimum value for the edge being added.
+     * @param maximumValue is the maximum value for the edge being added.
+     * @return the comparison result.
+     */
+    protected int compareForAdd(final double nodeMinimumValue, final double nodeMaximumValue, final double minimumValue, final double maximumValue) {
+      if (minimumValue <= nodeMinimumValue && maximumValue >= nodeMaximumValue) {
+        return CONTAINED;
+      } else if (nodeMinimumValue <= minimumValue && nodeMaximumValue >= maximumValue) {
+        return WITHIN;
+      } else if (maximumValue < nodeMinimumValue) {
+        return LESS;
+      } else if (minimumValue > nodeMaximumValue) {
+        return GREATER;
+      } else if (minimumValue < nodeMinimumValue) {
+        return OVERLAPS_MINIMUM;
+      } else {
+        return OVERLAPS_MAXIMUM;
+      }
+    }
   }
   
   /** This is the z-tree.
    */
-  private static class ZTree implements Tree, TraverseComparator, AddComparator {
+  private static class ZTree extends Tree {
     public Node rootNode = null;
     
     public ZTree() {
     }
     
     @Override
-    public void add(final Edge edge) {
-      if (rootNode == null) {
-        rootNode = new Node(edge);
-      } else {
-        rootNode.add(edge, this);
-      }
-    }
-    
-    @Override
-    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
-      if (rootNode == null) {
-        return true;
-      }
-      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
+    protected double getMinimum(final Edge edge) {
+      return edge.planeBounds.getMinimumZ();
     }
     
     @Override
-    public int compare(final Edge edge, final Edge addEdge) {
-      if (edge.planeBounds.getMaximumZ() < addEdge.planeBounds.getMinimumZ()) {
-        return 1;
-      } else if (edge.planeBounds.getMinimumZ() > addEdge.planeBounds.getMaximumZ()) {
-        return -1;
-      }
-      return 0;
+    protected double getMaximum(final Edge edge) {
+      return edge.planeBounds.getMaximumZ();
     }
-    
-    @Override
-    public int compare(final Edge edge, final double minValue, final double maxValue) {
-      if (edge.planeBounds.getMinimumZ() > maxValue) {
-        return -1;
-      } else if (edge.planeBounds.getMaximumZ() < minValue) {
-        return 1;
-      }
-      return 0;
-    }
-    
+
   }
   
   /** This is the y-tree.
    */
-  private static class YTree implements Tree, TraverseComparator, AddComparator {
-    public Node rootNode = null;
+  private static class YTree extends Tree {
     
     public YTree() {
     }
     
     @Override
-    public void add(final Edge edge) {
-      if (rootNode == null) {
-        rootNode = new Node(edge);
-      } else {
-        rootNode.add(edge, this);
-      }
+    protected double getMinimum(final Edge edge) {
+      return edge.planeBounds.getMinimumY();
     }
     
     @Override
-    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
-      if (rootNode == null) {
-        return true;
-      }
-      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
-    }
-    
-    @Override
-    public int compare(final Edge edge, final Edge addEdge) {
-      if (edge.planeBounds.getMaximumY() < addEdge.planeBounds.getMinimumY()) {
-        return 1;
-      } else if (edge.planeBounds.getMinimumY() > addEdge.planeBounds.getMaximumY()) {
-        return -1;
-      }
-      return 0;
-    }
-    
-    @Override
-    public int compare(final Edge edge, final double minValue, final double maxValue) {
-      if (edge.planeBounds.getMinimumY() > maxValue) {
-        return -1;
-      } else if (edge.planeBounds.getMaximumY() < minValue) {
-        return 1;
-      }
-      return 0;
+    protected double getMaximum(final Edge edge) {
+      return edge.planeBounds.getMaximumY();
     }
     
   }
 
   /** This is the x-tree.
    */
-  private static class XTree implements Tree, TraverseComparator, AddComparator {
-    public Node rootNode = null;
+  private static class XTree extends Tree {
     
     public XTree() {
     }
     
     @Override
-    public void add(final Edge edge) {
-      if (rootNode == null) {
-        rootNode = new Node(edge);
-      } else {
-        rootNode.add(edge, this);
-      }
+    protected double getMinimum(final Edge edge) {
+      return edge.planeBounds.getMinimumX();
     }
     
     @Override
-    public boolean traverse(final EdgeIterator edgeIterator, final double minValue, final double maxValue) {
-      if (rootNode == null) {
-        return true;
-      }
-      return rootNode.traverse(edgeIterator, this, minValue, maxValue);
-    }
-    
-    @Override
-    public int compare(final Edge edge, final Edge addEdge) {
-      if (edge.planeBounds.getMaximumX() < addEdge.planeBounds.getMinimumX()) {
-        return 1;
-      } else if (edge.planeBounds.getMinimumX() > addEdge.planeBounds.getMaximumX()) {
-        return -1;
-      }
-      return 0;
-    }
-    
-    @Override
-    public int compare(final Edge edge, final double minValue, final double maxValue) {
-      if (edge.planeBounds.getMinimumX() > maxValue) {
-        return -1;
-      } else if (edge.planeBounds.getMaximumX() < minValue) {
-        return 1;
-      }
-      return 0;
+    protected double getMaximum(final Edge edge) {
+      return edge.planeBounds.getMaximumX();
     }
     
   }
@@ -924,8 +935,10 @@ class GeoComplexPolygon extends GeoBasePolygon {
     
     @Override
     public boolean matches(final Edge edge) {
+      System.err.println("Processing edge "+edge);
       // Early exit if the point is on the edge.
       if (thePoint != null && edge.plane.evaluateIsZero(thePoint) && edge.startPlane.isWithin(thePoint) && edge.endPlane.isWithin(thePoint)) {
+        System.err.println(" Check point is on edge: isWithin = true");
         return false;
       }
       // If the intersection point lies on this edge, we should still be able to consider crossing points only.
@@ -942,11 +955,15 @@ class GeoComplexPolygon extends GeoBasePolygon {
         for (final GeoPoint crossingPoint : crossingPoints) {
           countCrossingPoint(crossingPoint, edge);
         }
+        System.err.println(" All crossing points processed");
+      } else {
+        System.err.println(" No crossing points!");
       }
       return true;
     }
 
     private void countCrossingPoint(final GeoPoint crossingPoint, final Edge edge) {
+      System.err.println(" Crossing point "+crossingPoint);
       // We consider crossing points only in this method.
       // Unlike the linear case, there are additional cases when:
       // (1) The crossing point and the intersection point are the same, but are not the endpoint of an edge;
@@ -960,12 +977,14 @@ class GeoComplexPolygon extends GeoBasePolygon {
       // In either case, we have to be sure to count each edge only once, since it might appear in both the
       // first leg and the second.  If the first leg can process it, it should, and the second should skip it.
       if (crossingPoint.isNumericallyIdentical(intersectionPoint)) {
+        System.err.println(" Crosses intersection point.");
         if (isSecondLeg) {
           // See whether this edge would have been processed in the first leg; if so, we skip it.
           final GeoPoint[] firstLegCrossings = testPointPlane.findCrossings(planetModel, edge.plane, testPointCutoffPlane, testPointOtherCutoffPlane, edge.startPlane, edge.endPlane);
           for (final GeoPoint firstLegCrossing : firstLegCrossings) {
             if (firstLegCrossing.isNumericallyIdentical(intersectionPoint)) {
               // We already processed it, so we're done here.
+              System.err.println("  Already processed on previous leg: exit");
               return;
             }
           }
@@ -994,6 +1013,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
         
       if (crossingPoint.isNumericallyIdentical(edge.startPoint)) {
+        System.err.println(" Crossing point = edge.startPoint");
         // We have to figure out if this crossing should be counted.
           
         // Does the crossing for this edge go up, or down?  Or can't we tell?
@@ -1062,6 +1082,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         }
           
       } else if (crossingPoint.isNumericallyIdentical(edge.endPoint)) {
+        System.err.println(" Crossing point = edge.endPoint");
         // Figure out if the crossing should be counted.
           
         // Does the crossing for this edge go up, or down?  Or can't we tell?
@@ -1115,6 +1136,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
           crossingCount++;
         }
       } else {
+        System.err.println(" Not a special case: incrementing crossing count");
         // Not a special case, so we can safely count a crossing.
         crossingCount++;
       }


[25/25] lucene-solr:branch_6x: Fix javadoc

Posted by kw...@apache.org.
Fix javadoc


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/9a06fb4e
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/9a06fb4e
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/9a06fb4e

Branch: refs/heads/branch_6x
Commit: 9a06fb4e221076df57bd5bcda1ac2f474a85cc3e
Parents: a73d075
Author: Karl Wright <Da...@gmail.com>
Authored: Thu Apr 28 19:58:55 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Thu Apr 28 20:27:16 2016 -0400

----------------------------------------------------------------------
 .../java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/9a06fb4e/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 661953a..c7197d8 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -598,8 +598,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
     }
     
     /** Compare a node against a subrange of a new edge.
-     * @param node is the node to compare.
-     * @param newEdge is the edge being added.
+     * @param nodeMinimumValue is the node's minimum value.
+     * @param nodeMaximumValue is the node's maximum value.
      * @param minimumValue is the minimum value for the edge being added.
      * @param maximumValue is the maximum value for the edge being added.
      * @return the comparison result.