You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2015/04/22 16:47:01 UTC

svn commit: r1675374 [1/2] - in /lucene/dev/branches/lucene6196/lucene/spatial/src: java/org/apache/lucene/spatial/spatial4j/geo3d/ test/org/apache/lucene/spatial/spatial4j/

Author: dsmiley
Date: Wed Apr 22 14:47:00 2015
New Revision: 1675374

URL: http://svn.apache.org/r1675374
Log:
LUCENE-6196: committing Karl's latest patch
https://reviews.apache.org/r/33353/ (diff #9) https://reviews.apache.org/r/33353/diff/raw/

Added:
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthLatitudeZone.java   (with props)
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthRectangle.java   (with props)
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthLatitudeZone.java   (with props)
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthRectangle.java   (with props)
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWideNorthRectangle.java   (with props)
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWideSouthRectangle.java   (with props)
Modified:
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxBase.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxFactory.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBaseExtendedShape.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCircle.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCompositeMembershipShape.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateHorizontalLine.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLatitudeZone.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLongitudeSlice.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegeneratePoint.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateVerticalLine.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLatitudeZone.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLongitudeSlice.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoRectangle.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoShape.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWideDegenerateHorizontalLine.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWideLongitudeSlice.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWideRectangle.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoWorld.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Plane.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/SidedPlane.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/Vector.java
    lucene/dev/branches/lucene6196/lucene/spatial/src/test/org/apache/lucene/spatial/spatial4j/Geo3dRptTest.java

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxBase.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxBase.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxBase.java Wed Apr 22 14:47:00 2015
@@ -22,6 +22,9 @@ package org.apache.lucene.spatial.spatia
 */
 public abstract class GeoBBoxBase implements GeoBBox {
 
+    protected final static GeoPoint NORTH_POLE = new GeoPoint(0.0,0.0,1.0);
+    protected final static GeoPoint SOUTH_POLE = new GeoPoint(0.0,0.0,-1.0);
+
     @Override
     public abstract boolean isWithin(final Vector point);
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxFactory.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxFactory.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBBoxFactory.java Wed Apr 22 14:47:00 2015
@@ -30,6 +30,7 @@ public class GeoBBoxFactory
      *@return a GeoBBox corresponding to what was specified.
      */
     public static GeoBBox makeGeoBBox(double topLat, double bottomLat, double leftLon, double rightLon) {
+        //System.err.println("Making rectangle for topLat="+topLat*180.0/Math.PI+", bottomLat="+bottomLat*180.0/Math.PI+", leftLon="+leftLon*180.0/Math.PI+", rightlon="+rightLon*180.0/Math.PI);
         if (topLat > Math.PI * 0.5)
             topLat = Math.PI * 0.5;
         if (bottomLat < -Math.PI * 0.5)
@@ -41,10 +42,18 @@ public class GeoBBoxFactory
         if (leftLon == -Math.PI && rightLon == Math.PI) {
             if (topLat == Math.PI * 0.5 && bottomLat == -Math.PI * 0.5)
                 return new GeoWorld();
-            if (topLat == bottomLat)
+            if (topLat == bottomLat) {
+                if (topLat == Math.PI * 0.5 || topLat == -Math.PI * 0.5)
+                    return new GeoDegeneratePoint(topLat,0.0);
                 return new GeoDegenerateLatitudeZone(topLat);
+            }
+            if (topLat == Math.PI * 0.5)
+                return new GeoNorthLatitudeZone(bottomLat);
+            else if (bottomLat == -Math.PI * 0.5)
+                return new GeoSouthLatitudeZone(topLat);
             return new GeoLatitudeZone(topLat, bottomLat);
         }
+        //System.err.println(" not latitude zone");
         double extent = rightLon - leftLon;
         if (extent < 0.0)
           extent += Math.PI * 2.0;
@@ -57,19 +66,36 @@ public class GeoBBoxFactory
           
           return new GeoLongitudeSlice(leftLon, rightLon);
         }
+        //System.err.println(" not longitude slice");
         if (leftLon == rightLon) {
           if (topLat == bottomLat)
             return new GeoDegeneratePoint(topLat, leftLon);
           return new GeoDegenerateVerticalLine(topLat, bottomLat, leftLon);
         }
+        //System.err.println(" not vertical line");
         if (extent >= Math.PI) {
           if (topLat == bottomLat) {
+            //System.err.println(" wide degenerate line");
             return new GeoWideDegenerateHorizontalLine(topLat, leftLon, rightLon);
           }
+          if (topLat == Math.PI * 0.5) {
+            return new GeoWideNorthRectangle(bottomLat, leftLon, rightLon);
+          } else if (bottomLat == -Math.PI * 0.5) {
+            return new GeoWideSouthRectangle(topLat, leftLon, rightLon);
+          }
+          //System.err.println(" wide rect");
           return new GeoWideRectangle(topLat, bottomLat, leftLon, rightLon);
         }
-        if (topLat == bottomLat)
+        if (topLat == bottomLat) {
+          //System.err.println(" horizontal line");
           return new GeoDegenerateHorizontalLine(topLat, leftLon, rightLon);
+        }
+        if (topLat == Math.PI * 0.5) {
+            return new GeoNorthRectangle(bottomLat, leftLon, rightLon);
+        } else if (bottomLat == -Math.PI * 0.5) {
+            return new GeoSouthRectangle(topLat, leftLon, rightLon);
+        }
+        //System.err.println(" rectangle");
         return new GeoRectangle(topLat, bottomLat, leftLon, rightLon);
     }
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBaseExtendedShape.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBaseExtendedShape.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBaseExtendedShape.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoBaseExtendedShape.java Wed Apr 22 14:47:00 2015
@@ -59,7 +59,7 @@ public abstract class GeoBaseExtendedSha
      *@return true if there's such an intersection, false if not.
      */
     @Override
-    public abstract boolean intersects(final Plane plane, final Membership... bounds);
+    public abstract boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
 
     /** Compute longitude/latitude bounds for the shape.
     *@param bounds is the optional input bounds object.  If this is null,

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCircle.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCircle.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCircle.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCircle.java Wed Apr 22 14:47:00 2015
@@ -27,6 +27,7 @@ public class GeoCircle extends GeoBaseEx
     public final double cutoffLinearDistance;
     public final SidedPlane circlePlane;
     public final GeoPoint[] edgePoints;
+    public static final GeoPoint[] circlePoints = new GeoPoint[0];
     
     public GeoCircle(final double lat, final double lon, final double cutoffAngle)
     {
@@ -35,7 +36,7 @@ public class GeoCircle extends GeoBaseEx
             throw new IllegalArgumentException("Latitude out of bounds");
         if (lon < -Math.PI || lon > Math.PI)
             throw new IllegalArgumentException("Longitude out of bounds");
-        if (cutoffAngle < 0.0 || cutoffAngle > Math.PI)
+        if (cutoffAngle <= 0.0 || cutoffAngle > Math.PI)
             throw new IllegalArgumentException("Cutoff angle out of bounds");
         final double sinAngle = Math.sin(cutoffAngle);
         final double cosAngle = Math.cos(cutoffAngle);
@@ -47,9 +48,25 @@ public class GeoCircle extends GeoBaseEx
         this.cutoffAngle = cutoffAngle;
         this.circlePlane = new SidedPlane(center, center, -cosAngle);
         
-        // Compute a point on the circle boundary.  This can be any point that is easy to compute.
-        // This requires some math, so I've implemented it in Plane.
-        this.edgePoints = new GeoPoint[]{center.getSamplePoint(sinAngle,cosAngle)};
+        // Compute a point on the circle boundary. 
+        if (cutoffAngle == Math.PI)
+            this.edgePoints = new GeoPoint[0];
+        else {
+            // Move from center only in latitude.  Then, if we go past the north pole, adjust the longitude also.
+            double newLat = lat + cutoffAngle;
+            double newLon = lon;
+            if (newLat > Math.PI * 0.5) {
+                newLat = Math.PI - newLat;
+                newLon += Math.PI;
+            }
+            while (newLon > Math.PI) {
+                newLon -= Math.PI * 2.0;
+            }
+            final GeoPoint edgePoint = new GeoPoint(newLat,newLon);
+            //if (Math.abs(circlePlane.evaluate(edgePoint)) > 1e-10)
+            //    throw new RuntimeException("Computed an edge point that does not satisfy circlePlane equation! "+circlePlane.evaluate(edgePoint));
+            this.edgePoints = new GeoPoint[]{edgePoint};
+        }
     }
     
     @Override
@@ -170,8 +187,6 @@ public class GeoCircle extends GeoBaseEx
     @Override
     public boolean isWithin(final Vector point)
     {
-        if (point == null)
-            return false;
         // Fastest way of determining membership
         return circlePlane.isWithin(point);
     }
@@ -190,9 +205,9 @@ public class GeoCircle extends GeoBaseEx
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return circlePlane.intersects(p, bounds);
+        return circlePlane.intersects(p, notablePoints, circlePoints, bounds);
     }
 
     /** Compute longitude/latitude bounds for the shape.

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCompositeMembershipShape.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCompositeMembershipShape.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCompositeMembershipShape.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoCompositeMembershipShape.java Wed Apr 22 14:47:00 2015
@@ -63,10 +63,10 @@ public class GeoCompositeMembershipShape
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
         for (GeoMembershipShape shape : shapes) {
-            if (shape.intersects(p,bounds))
+            if (shape.intersects(p,notablePoints,bounds))
                 return true;
         }
         return false;

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoConvexPolygon.java Wed Apr 22 14:47:00 2015
@@ -33,6 +33,7 @@ public class GeoConvexPolygon extends Ge
 
     protected SidedPlane[] edges = null;
     protected boolean[] internalEdges = null;
+    protected GeoPoint[][] notableEdgePoints = null;
     
     protected GeoPoint[] edgePoints = null;
     
@@ -98,6 +99,7 @@ public class GeoConvexPolygon extends Ge
             throw new IllegalArgumentException("Polygon needs at least three points.");
         // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
         edges = new SidedPlane[points.size()];
+        notableEdgePoints = new GeoPoint[points.size()][];
         internalEdges = new boolean[points.size()];
         // to a segment can provide an interior measurement.
         for (int i = 0; i < points.size(); i++) {
@@ -108,6 +110,7 @@ public class GeoConvexPolygon extends Ge
             final SidedPlane sp = new SidedPlane(check,start,end);
             //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check);
             edges[i] = sp;
+            notableEdgePoints[i] = new GeoPoint[]{start,end};
             internalEdges[i] = isInternalEdge;
         }
         createCenterPoint();
@@ -163,11 +166,14 @@ public class GeoConvexPolygon extends Ge
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
+        //System.err.println("Checking for polygon intersection with plane "+p+"...");
         for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
             final SidedPlane edge = edges[edgeIndex];
+            final GeoPoint[] points = this.notableEdgePoints[edgeIndex];
             if (!internalEdges[edgeIndex]) {
+                //System.err.println(" non-internal edge "+edge);
                 // Edges flagged as 'internal only' are excluded from the matching
                 // Construct boundaries
                 final Membership[] membershipBounds = new Membership[edges.length-1];
@@ -177,10 +183,13 @@ public class GeoConvexPolygon extends Ge
                         membershipBounds[count++] = edges[otherIndex];
                     }
                 }
-                if (edge.intersects(p,bounds,membershipBounds))
+                if (edge.intersects(p,notablePoints, points, bounds,membershipBounds)) {
+                    //System.err.println(" intersects!");
                     return true;
+                }
             }
         }
+        //System.err.println(" no intersection");
         return false;
     }
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateHorizontalLine.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateHorizontalLine.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateHorizontalLine.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateHorizontalLine.java Wed Apr 22 14:47:00 2015
@@ -33,7 +33,9 @@ public class GeoDegenerateHorizontalLine
     public final Plane plane;
     public final SidedPlane leftPlane;
     public final SidedPlane rightPlane;
-      
+
+    public final GeoPoint[] planePoints;
+
     public final GeoPoint centerPoint;
     public final GeoPoint[] edgePoints;
     
@@ -83,6 +85,8 @@ public class GeoDegenerateHorizontalLine
         this.leftPlane = new SidedPlane(centerPoint,cosLeftLon,sinLeftLon);
         this.rightPlane = new SidedPlane(centerPoint,cosRightLon,sinRightLon);
 
+        this.planePoints = new GeoPoint[]{LHC,RHC};
+
         this.edgePoints = new GeoPoint[]{centerPoint};
     }
 
@@ -107,7 +111,7 @@ public class GeoDegenerateHorizontalLine
     @Override
     public boolean isWithin(final Vector point)
     {
-        return plane.evaluate(point) == 0.0 &&
+        return plane.evaluateIsZero(point) &&
           leftPlane.isWithin(point) &&
           rightPlane.isWithin(point);
     }
@@ -115,7 +119,7 @@ public class GeoDegenerateHorizontalLine
     @Override
     public boolean isWithin(final double x, final double y, final double z)
     {
-        return plane.evaluate(x,y,z) == 0.0 &&
+        return plane.evaluateIsZero(x,y,z) &&
           leftPlane.isWithin(x,y,z) &&
           rightPlane.isWithin(x,y,z);
     }
@@ -135,9 +139,9 @@ public class GeoDegenerateHorizontalLine
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(plane,bounds,leftPlane,rightPlane);
+        return p.intersects(plane,notablePoints,planePoints,bounds,leftPlane,rightPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -158,7 +162,7 @@ public class GeoDegenerateHorizontalLine
 
     @Override
     public int getRelationship(final GeoShape path) {
-        if (path.intersects(plane,leftPlane,rightPlane))
+        if (path.intersects(plane,planePoints,leftPlane,rightPlane))
             return OVERLAPS;
 
         if (path.isWithin(centerPoint))

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLatitudeZone.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLatitudeZone.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLatitudeZone.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLatitudeZone.java Wed Apr 22 14:47:00 2015
@@ -28,6 +28,7 @@ public class GeoDegenerateLatitudeZone e
     public final Plane plane;
     public final GeoPoint interiorPoint;
     public final GeoPoint[] edgePoints;
+    public final static GeoPoint[] planePoints = new GeoPoint[0];
     
     public GeoDegenerateLatitudeZone(final double latitude)
     {
@@ -36,7 +37,6 @@ public class GeoDegenerateLatitudeZone e
         this.sinLatitude = Math.sin(latitude);
         double cosLatitude = Math.cos(latitude);
         this.plane = new Plane(sinLatitude);
-
         // Compute an interior point.  
         interiorPoint = new GeoPoint(cosLatitude,0.0,sinLatitude);
         edgePoints = new GeoPoint[]{interiorPoint};
@@ -53,13 +53,13 @@ public class GeoDegenerateLatitudeZone e
     @Override
     public boolean isWithin(final Vector point)
     {
-        return point.z == this.sinLatitude;
+        return Math.abs(point.z - this.sinLatitude) < 1e-10;
     }
 
     @Override
     public boolean isWithin(final double x, final double y, final double z)
     {
-        return z == this.sinLatitude;
+        return Math.abs(z - this.sinLatitude) < 1e-10;
     }
 
     @Override
@@ -75,9 +75,9 @@ public class GeoDegenerateLatitudeZone e
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(plane,bounds);
+        return p.intersects(plane,notablePoints,planePoints,bounds);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -102,7 +102,7 @@ public class GeoDegenerateLatitudeZone e
         // work with no area endpoints.  So we rely entirely on intersections.
         //System.out.println("Got here! latitude="+latitude+" path="+path);
         
-        if (path.intersects(plane)) {
+        if (path.intersects(plane,planePoints)) {
             return OVERLAPS;
         }
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLongitudeSlice.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLongitudeSlice.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLongitudeSlice.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateLongitudeSlice.java Wed Apr 22 14:47:00 2015
@@ -30,6 +30,8 @@ public class GeoDegenerateLongitudeSlice
     public final GeoPoint interiorPoint;
     public final GeoPoint[] edgePoints;
 
+    public final static GeoPoint[] planePoints = new GeoPoint[]{NORTH_POLE,SOUTH_POLE};
+
     /** Accepts only values in the following ranges: lon: {@code -PI -> PI} */
     public GeoDegenerateLongitudeSlice(final double longitude)
     {
@@ -65,14 +67,14 @@ public class GeoDegenerateLongitudeSlice
     @Override
     public boolean isWithin(final Vector point)
     {
-        return plane.evaluate(point) == 0.0 &&
+        return plane.evaluateIsZero(point) &&
             boundingPlane.isWithin(point);
     }
 
     @Override
     public boolean isWithin(final double x, final double y, final double z)
     {
-        return plane.evaluate(x,y,z) == 0.0 &&
+        return plane.evaluateIsZero(x,y,z) &&
             boundingPlane.isWithin(x,y,z);
     }
 
@@ -89,9 +91,9 @@ public class GeoDegenerateLongitudeSlice
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(plane,bounds,boundingPlane);
+        return p.intersects(plane,notablePoints,planePoints,bounds,boundingPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -114,7 +116,7 @@ public class GeoDegenerateLongitudeSlice
     @Override
     public int getRelationship(final GeoShape path) {
         // Look for intersections.
-        if (path.intersects(plane,boundingPlane))
+        if (path.intersects(plane,planePoints,boundingPlane))
             return OVERLAPS;
 
         if (path.isWithin(interiorPoint))

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegeneratePoint.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegeneratePoint.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegeneratePoint.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegeneratePoint.java Wed Apr 22 14:47:00 2015
@@ -64,7 +64,7 @@ public class GeoDegeneratePoint extends
      *@return true if there's such an intersection, false if not.
      */
     @Override
-    public boolean intersects(final Plane plane, final Membership... bounds) {
+    public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
         if (plane.evaluate(this) == 0.0)
             return false;
         

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateVerticalLine.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateVerticalLine.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateVerticalLine.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoDegenerateVerticalLine.java Wed Apr 22 14:47:00 2015
@@ -32,7 +32,9 @@ public class GeoDegenerateVerticalLine e
     public final SidedPlane bottomPlane;
     public final SidedPlane boundingPlane;
     public final Plane plane;
-      
+
+    public final GeoPoint[] planePoints;
+    
     public final GeoPoint centerPoint;
     public final GeoPoint[] edgePoints;
     
@@ -77,6 +79,8 @@ public class GeoDegenerateVerticalLine e
 
         this.boundingPlane = new SidedPlane(centerPoint,-sinLongitude,cosLongitude);
 
+        this.planePoints = new GeoPoint[]{UHC,LHC};
+
         this.edgePoints = new GeoPoint[]{centerPoint};
     }
 
@@ -98,7 +102,7 @@ public class GeoDegenerateVerticalLine e
     @Override
     public boolean isWithin(final Vector point)
     {
-        return plane.evaluate(point) == 0.0 &&
+        return plane.evaluateIsZero(point) &&
           boundingPlane.isWithin(point) &&
           topPlane.isWithin(point) &&
           bottomPlane.isWithin(point);
@@ -107,7 +111,7 @@ public class GeoDegenerateVerticalLine e
     @Override
     public boolean isWithin(final double x, final double y, final double z)
     {
-        return plane.evaluate(x,y,z) == 0.0 &&
+        return plane.evaluateIsZero(x,y,z) &&
           boundingPlane.isWithin(x,y,z) &&
           topPlane.isWithin(x,y,z) &&
           bottomPlane.isWithin(x,y,z);
@@ -131,9 +135,9 @@ public class GeoDegenerateVerticalLine e
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(plane,bounds,boundingPlane,topPlane,bottomPlane);
+        return p.intersects(plane,notablePoints,planePoints,bounds,boundingPlane,topPlane,bottomPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -155,12 +159,18 @@ public class GeoDegenerateVerticalLine e
 
     @Override
     public int getRelationship(final GeoShape path) {
-        if (path.intersects(plane,boundingPlane,topPlane,bottomPlane))
+        //System.err.println(this+" relationship to "+path);
+        if (path.intersects(plane,planePoints,boundingPlane,topPlane,bottomPlane)) {
+            //System.err.println(" overlaps");
             return OVERLAPS;
+        }
 
-        if (path.isWithin(centerPoint))
+        if (path.isWithin(centerPoint)) {
+            //System.err.println(" contains");
             return CONTAINS;
+        }
 
+        //System.err.println(" disjoint");
         return DISJOINT;
     }
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLatitudeZone.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLatitudeZone.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLatitudeZone.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLatitudeZone.java Wed Apr 22 14:47:00 2015
@@ -28,6 +28,7 @@ public class GeoLatitudeZone extends Geo
     public final SidedPlane topPlane;
     public final SidedPlane bottomPlane;
     public final GeoPoint interiorPoint;
+    public final static GeoPoint[] planePoints = new GeoPoint[0];
 
     // We need two additional points because a latitude zone's boundaries don't intersect.  This is a very
     // special case that most GeoBBox's do not have.
@@ -106,10 +107,10 @@ public class GeoLatitudeZone extends Geo
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(topPlane,bounds,bottomPlane) ||
-          p.intersects(bottomPlane,bounds,topPlane);
+        return p.intersects(topPlane,notablePoints,planePoints,bounds,bottomPlane) ||
+          p.intersects(bottomPlane,notablePoints,planePoints,bounds,topPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -149,8 +150,8 @@ public class GeoLatitudeZone extends Geo
         // Second, the shortcut of seeing whether endpoints are in/out is not going to 
         // work with no area endpoints.  So we rely entirely on intersections.
 
-        if (path.intersects(topPlane,bottomPlane) ||
-            path.intersects(bottomPlane,topPlane))
+        if (path.intersects(topPlane,planePoints,bottomPlane) ||
+            path.intersects(bottomPlane,planePoints,topPlane))
             return OVERLAPS;
 
         // There is another case for latitude zones only.  This is when the boundaries of the shape all fit

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLongitudeSlice.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLongitudeSlice.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLongitudeSlice.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoLongitudeSlice.java Wed Apr 22 14:47:00 2015
@@ -29,9 +29,11 @@ public class GeoLongitudeSlice extends G
     public final SidedPlane leftPlane;
     public final SidedPlane rightPlane;
       
+    public final static GeoPoint[] planePoints = new GeoPoint[]{NORTH_POLE,SOUTH_POLE};
+    
     public final GeoPoint centerPoint;
-    public final GeoPoint northPole = new GeoPoint(0.0,0.0,1.0);
-    public final GeoPoint[] edgePoints = new GeoPoint[]{northPole};
+
+    public final static GeoPoint[] edgePoints = new GeoPoint[]{NORTH_POLE};
     
     /** Accepts only values in the following ranges: lon: {@code -PI -> PI} */
     public GeoLongitudeSlice(final double leftLon, double rightLon)
@@ -115,10 +117,10 @@ public class GeoLongitudeSlice extends G
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(leftPlane,bounds,rightPlane) ||
-          p.intersects(rightPlane,bounds,leftPlane);
+        return p.intersects(leftPlane,notablePoints,planePoints,bounds,rightPlane) ||
+          p.intersects(rightPlane,notablePoints,planePoints,bounds,leftPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -144,13 +146,13 @@ public class GeoLongitudeSlice extends G
         if (insideRectangle == SOME_INSIDE)
             return OVERLAPS;
 
-        final boolean insideShape = path.isWithin(northPole);
+        final boolean insideShape = path.isWithin(NORTH_POLE);
         
         if (insideRectangle == ALL_INSIDE && insideShape)
             return OVERLAPS;
 
-        if (path.intersects(leftPlane,rightPlane) ||
-            path.intersects(rightPlane,leftPlane)) {
+        if (path.intersects(leftPlane,planePoints,rightPlane) ||
+            path.intersects(rightPlane,planePoints,leftPlane)) {
             return OVERLAPS;
         }
 

Added: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthLatitudeZone.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthLatitudeZone.java?rev=1675374&view=auto
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthLatitudeZone.java (added)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthLatitudeZone.java Wed Apr 22 14:47:00 2015
@@ -0,0 +1,171 @@
+package org.apache.lucene.spatial.spatial4j.geo3d;
+
+/*
+ * 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.
+ */
+
+/** This GeoBBox represents an area rectangle limited only in south latitude.
+*/
+public class GeoNorthLatitudeZone extends GeoBBoxBase
+{
+    public final double bottomLat;
+    public final double cosBottomLat;
+    public final SidedPlane bottomPlane;
+    public final GeoPoint interiorPoint;
+    public final static GeoPoint[] planePoints = new GeoPoint[0];
+
+    public final GeoPoint bottomBoundaryPoint;
+    
+    // Edge points
+    public final GeoPoint[] edgePoints;
+    
+    public GeoNorthLatitudeZone(final double bottomLat)
+    {
+        this.bottomLat = bottomLat;
+          
+        final double sinBottomLat = Math.sin(bottomLat);
+        this.cosBottomLat = Math.cos(bottomLat);
+          
+        // Construct sample points, so we get our sidedness right
+        final Vector bottomPoint = new Vector(0.0,0.0,sinBottomLat);
+
+        // Compute an interior point.  Pick one whose lat is between top and bottom.
+        final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+        final double sinMiddleLat = Math.sin(middleLat);
+        this.interiorPoint = new GeoPoint(Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat),0.0,sinMiddleLat);
+        this.bottomBoundaryPoint = new GeoPoint(Math.sqrt(1.0 - sinBottomLat * sinBottomLat),0.0,sinBottomLat);
+        
+        this.bottomPlane = new SidedPlane(interiorPoint,sinBottomLat);
+        
+        this.edgePoints = new GeoPoint[]{bottomBoundaryPoint};
+    }
+
+    @Override
+    public GeoBBox expand(final double angle)
+    {
+        final double newTopLat = Math.PI * 0.5;
+        final double newBottomLat = bottomLat - angle;
+        return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, -Math.PI, Math.PI);
+    }
+
+    @Override
+    public boolean isWithin(final Vector point)
+    {
+        return
+          bottomPlane.isWithin(point);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z)
+    {
+        return
+          bottomPlane.isWithin(x,y,z);
+    }
+
+    @Override
+    public double getRadius()
+    {
+        // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+        // would contain all the bounding box points, when starting in the "center".
+        if (bottomLat < 0.0)
+            return Math.PI;
+        double maxCosLat = cosBottomLat;
+        return maxCosLat * Math.PI;
+    }
+
+    @Override
+    public GeoPoint[] getEdgePoints()
+    {
+        return edgePoints;
+    }
+      
+    @Override
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
+    {
+        return
+          p.intersects(bottomPlane,notablePoints,planePoints,bounds);
+    }
+
+    /** Compute longitude/latitude bounds for the shape.
+    *@param bounds is the optional input bounds object.  If this is null,
+    * a bounds object will be created.  Otherwise, the input object will be modified.
+    *@return a Bounds object describing the shape's bounds.  If the bounds cannot
+    * be computed, then return a Bounds object with noLongitudeBound,
+    * noTopLatitudeBound, and noBottomLatitudeBound.
+    */
+    @Override
+    public Bounds getBounds(Bounds bounds)
+    {
+        if (bounds == null)
+            bounds = new Bounds();
+        bounds.noLongitudeBound().noTopLatitudeBound().addLatitudeZone(bottomLat);
+        return bounds;
+    }
+
+    @Override
+    public int getRelationship(final GeoShape path) {
+        final int insideRectangle = isShapeInsideBBox(path);
+        if (insideRectangle == SOME_INSIDE)
+            return OVERLAPS;
+
+        final boolean insideShape = path.isWithin(bottomBoundaryPoint);
+
+        if (insideRectangle == ALL_INSIDE && insideShape)
+            return OVERLAPS;
+
+        // Second, the shortcut of seeing whether endpoints are in/out is not going to 
+        // work with no area endpoints.  So we rely entirely on intersections.
+
+        if (
+            path.intersects(bottomPlane,planePoints))
+            return OVERLAPS;
+
+        // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+        // within the zone, but the shape includes areas outside the zone crossing a pole.
+        // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+        // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+        // one such point is within, then OVERLAPS is the right answer.  
+        
+        if (insideShape)
+            return CONTAINS;
+
+        if (insideRectangle == ALL_INSIDE)
+            return WITHIN;
+
+        return DISJOINT;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof GeoNorthLatitudeZone))
+            return false;
+        GeoNorthLatitudeZone other = (GeoNorthLatitudeZone)o;
+        return other.bottomPlane.equals(bottomPlane);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = bottomPlane.hashCode();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        return "GeoNorthLatitudeZone: {bottomlat="+bottomLat+"("+bottomLat*180.0/Math.PI+")}";
+    }
+}
+

Added: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthRectangle.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthRectangle.java?rev=1675374&view=auto
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthRectangle.java (added)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoNorthRectangle.java Wed Apr 22 14:47:00 2015
@@ -0,0 +1,243 @@
+package org.apache.lucene.spatial.spatial4j.geo3d;
+
+/*
+ * 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.
+ */
+
+/** Bounding box limited on three sides (bottom lat, left lon, right lon), including
+* the north pole.
+* The left-right maximum extent for this shape is PI; for anything larger, use
+* GeoWideNorthRectangle.
+*/
+public class GeoNorthRectangle extends GeoBBoxBase
+{
+    public final double bottomLat;
+    public final double leftLon;
+    public final double rightLon;
+      
+    public final double cosMiddleLat;
+      
+    public final GeoPoint LRHC;
+    public final GeoPoint LLHC;
+    
+    public final SidedPlane bottomPlane;
+    public final SidedPlane leftPlane;
+    public final SidedPlane rightPlane;
+    
+    public final GeoPoint[] bottomPlanePoints;
+    public final GeoPoint[] leftPlanePoints;
+    public final GeoPoint[] rightPlanePoints;
+    
+    public final GeoPoint centerPoint;
+
+    public final GeoPoint[] edgePoints = new GeoPoint[]{NORTH_POLE};
+    
+    /** Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI} */
+    public GeoNorthRectangle(final double bottomLat, final double leftLon, double rightLon)
+    {
+        // Argument checking
+        if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+            throw new IllegalArgumentException("Bottom latitude out of range");
+        if (leftLon < -Math.PI || leftLon > Math.PI)
+            throw new IllegalArgumentException("Left longitude out of range");
+        if (rightLon < -Math.PI || rightLon > Math.PI)
+            throw new IllegalArgumentException("Right longitude out of range");
+        double extent = rightLon - leftLon;
+        if (extent < 0.0) {
+            extent += 2.0 * Math.PI;
+        }
+        if (extent > Math.PI)
+            throw new IllegalArgumentException("Width of rectangle too great");
+
+        this.bottomLat = bottomLat;
+        this.leftLon = leftLon;
+        this.rightLon = rightLon;
+          
+        final double sinBottomLat = Math.sin(bottomLat);
+        final double cosBottomLat = Math.cos(bottomLat);
+        final double sinLeftLon = Math.sin(leftLon);
+        final double cosLeftLon = Math.cos(leftLon);
+        final double sinRightLon = Math.sin(rightLon);
+        final double cosRightLon = Math.cos(rightLon);
+        
+        // Now build the points
+        this.LRHC = new GeoPoint(sinBottomLat,sinRightLon,cosBottomLat,cosRightLon);
+        this.LLHC = new GeoPoint(sinBottomLat,sinLeftLon,cosBottomLat,cosLeftLon);
+        
+        final double middleLat = (Math.PI * 0.5 + bottomLat) * 0.5;
+        final double sinMiddleLat = Math.sin(middleLat);
+        this.cosMiddleLat = Math.cos(middleLat);
+        // Normalize
+        while (leftLon > rightLon) {
+            rightLon += Math.PI * 2.0;
+        }
+        final double middleLon = (leftLon + rightLon) * 0.5;
+        final double sinMiddleLon = Math.sin(middleLon);
+        final double cosMiddleLon = Math.cos(middleLon);
+          
+        this.centerPoint = new GeoPoint(sinMiddleLat,sinMiddleLon,cosMiddleLat,cosMiddleLon);
+
+        this.bottomPlane = new SidedPlane(centerPoint,sinBottomLat);
+        this.leftPlane = new SidedPlane(centerPoint,cosLeftLon,sinLeftLon);
+        this.rightPlane = new SidedPlane(centerPoint,cosRightLon,sinRightLon);
+
+        this.bottomPlanePoints = new GeoPoint[]{LLHC,LRHC};
+        this.leftPlanePoints = new GeoPoint[]{NORTH_POLE,LLHC};
+        this.rightPlanePoints = new GeoPoint[]{NORTH_POLE,LRHC};
+        
+    }
+
+    @Override
+    public GeoBBox expand(final double angle)
+    {
+        final double newTopLat = Math.PI * 0.5;
+        final double newBottomLat = bottomLat - angle;
+        // Figuring out when we escalate to a special case requires some prefiguring
+        double currentLonSpan = rightLon - leftLon;
+        if (currentLonSpan < 0.0)
+            currentLonSpan += Math.PI * 2.0;
+        double newLeftLon = leftLon - angle;
+        double newRightLon = rightLon + angle;
+        if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+            newLeftLon = -Math.PI;
+            newRightLon = Math.PI;
+        }
+        return GeoBBoxFactory.makeGeoBBox(newTopLat,newBottomLat,newLeftLon,newRightLon);
+    }
+
+    @Override
+    public boolean isWithin(final Vector point)
+    {
+        return
+          bottomPlane.isWithin(point) &&
+          leftPlane.isWithin(point) &&
+          rightPlane.isWithin(point);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z)
+    {
+        return
+          bottomPlane.isWithin(x,y,z) &&
+          leftPlane.isWithin(x,y,z) &&
+          rightPlane.isWithin(x,y,z);
+    }
+
+    @Override
+    public double getRadius()
+    {
+        // Here we compute the distance from the middle point to one of the corners.  However, we need to be careful
+        // to use the longest of three distances: the distance to a corner on the top; the distnace to a corner on the bottom, and
+        // the distance to the right or left edge from the center.
+        final double centerAngle = (rightLon - (rightLon + leftLon) * 0.5) * cosMiddleLat;
+        final double bottomAngle = centerPoint.arcDistance(LLHC);
+        return Math.max(centerAngle,bottomAngle);
+    }
+      
+    @Override
+    public GeoPoint[] getEdgePoints()
+    {
+        return edgePoints;
+    }
+      
+    @Override
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
+    {
+        return
+          p.intersects(bottomPlane,notablePoints,bottomPlanePoints,bounds,leftPlane,rightPlane) ||
+          p.intersects(leftPlane,notablePoints,leftPlanePoints,bounds,rightPlane,bottomPlane) ||
+          p.intersects(rightPlane,notablePoints,rightPlanePoints,bounds,leftPlane,bottomPlane);
+    }
+
+    /** Compute longitude/latitude bounds for the shape.
+    *@param bounds is the optional input bounds object.  If this is null,
+    * a bounds object will be created.  Otherwise, the input object will be modified.
+    *@return a Bounds object describing the shape's bounds.  If the bounds cannot
+    * be computed, then return a Bounds object with noLongitudeBound,
+    * noTopLatitudeBound, and noBottomLatitudeBound.
+    */
+    @Override
+    public Bounds getBounds(Bounds bounds)
+    {
+        if (bounds == null)
+            bounds = new Bounds();
+        bounds.noTopLatitudeBound().addLatitudeZone(bottomLat)
+            .addLongitudeSlice(leftLon,rightLon);
+        return bounds;
+    }
+
+    @Override
+    public int getRelationship(final GeoShape path) {
+        //System.err.println(this+" getrelationship with "+path);
+        final int insideRectangle = isShapeInsideBBox(path);
+        if (insideRectangle == SOME_INSIDE)
+        {
+            //System.err.println(" some inside");
+            return OVERLAPS;
+        }
+
+        final boolean insideShape = path.isWithin(NORTH_POLE);
+        
+        if (insideRectangle == ALL_INSIDE && insideShape) {
+            //System.err.println(" inside of each other");
+            return OVERLAPS;
+        }
+
+        if (
+            path.intersects(bottomPlane,bottomPlanePoints,leftPlane,rightPlane) ||
+            path.intersects(leftPlane,leftPlanePoints,bottomPlane,rightPlane) ||
+            path.intersects(rightPlane,rightPlanePoints,leftPlane,bottomPlane)) {
+            //System.err.println(" edges intersect");
+            return OVERLAPS;
+        }
+
+        if (insideRectangle == ALL_INSIDE)
+        {
+            //System.err.println(" shape inside rectangle");
+            return WITHIN;
+        }
+    
+        if (insideShape) {
+            //System.err.println(" shape contains rectangle");
+            return CONTAINS;
+        }
+        //System.err.println(" disjoint");
+        return DISJOINT;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof GeoNorthRectangle))
+            return false;
+        GeoNorthRectangle other = (GeoNorthRectangle)o;
+        return other.LLHC.equals(LLHC) && other.LRHC.equals(LRHC);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = LLHC.hashCode();
+        result = 31 * result + LRHC.hashCode();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        return "GeoNorthRectangle: {bottomlat="+bottomLat+"("+bottomLat*180.0/Math.PI+"), leftlon="+leftLon+"("+leftLon*180.0/Math.PI+"), rightlon="+rightLon+"("+rightLon*180.0/Math.PI+")}";
+    }
+}
+  
+

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPath.java Wed Apr 22 14:47:00 2015
@@ -67,6 +67,20 @@ public class GeoPath extends GeoBaseExte
           if (ps.isDegenerate())
               return;
           segments.add(ps);
+        } else {
+            // First point.  We compute the basic set of edgepoints here because we've got the lat and lon available.
+            // Move from center only in latitude.  Then, if we go past the north pole, adjust the longitude also.
+            double newLat = lat + cutoffAngle;
+            double newLon = lon;
+            if (newLat > Math.PI * 0.5) {
+                newLat = Math.PI - newLat;
+                newLon += Math.PI;
+            }
+            while (newLon > Math.PI) {
+                newLon -= Math.PI * 2.0;
+            }
+            final GeoPoint edgePoint = new GeoPoint(newLat,newLon);
+            this.edgePoints = new GeoPoint[]{edgePoint};
         }
         final SegmentEndpoint se = new SegmentEndpoint(end, originDistance, cutoffOffset, cutoffAngle, chordDistance);
         points.add(se);
@@ -77,8 +91,24 @@ public class GeoPath extends GeoBaseExte
             throw new IllegalArgumentException("Path must have at least one point");
         if (segments.size() > 0) {
             edgePoints = new GeoPoint[]{points.get(0).circlePlane.getSampleIntersectionPoint(segments.get(0).invertedStartCutoffPlane)};
-        } else {
-            edgePoints = new GeoPoint[]{points.get(0).point.getSamplePoint(cutoffOffset,originDistance)};
+        }
+        for (int i = 0; i < points.size(); i++) {
+            final SegmentEndpoint pathPoint = points.get(i);
+            Membership previousEndBound = null;
+            GeoPoint[] previousEndNotablePoints = null;
+            Membership nextStartBound = null;
+            GeoPoint[] nextStartNotablePoints = null;
+            if (i > 0) {
+                final PathSegment previousSegment = segments.get(i-1);
+                previousEndBound = previousSegment.invertedEndCutoffPlane;
+                previousEndNotablePoints = previousSegment.endCutoffPlanePoints;
+            }
+            if (i < segments.size()) {
+                final PathSegment nextSegment = segments.get(i);
+                nextStartBound = nextSegment.invertedStartCutoffPlane;
+                nextStartNotablePoints = nextSegment.startCutoffPlanePoints;
+            }
+            pathPoint.setCutoffPlanes(previousEndNotablePoints,previousEndBound,nextStartNotablePoints,nextStartBound);
         }
     }
     
@@ -267,7 +297,7 @@ public class GeoPath extends GeoBaseExte
     }
       
     @Override
-    public boolean intersects(final Plane plane, final Membership... bounds)
+    public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds)
     {
         // We look for an intersection with any of the exterior edges of the path.
         // We also have to look for intersections with the cones described by the endpoints.
@@ -279,21 +309,14 @@ public class GeoPath extends GeoBaseExte
         // Well, sort of.  We can detect intersections also due to overlap of segments with each other.
         // But that's an edge case and we won't be optimizing for it.
         
-        for (int i = 0; i < points.size(); i++) {
-            final SegmentEndpoint pathPoint = points.get(i);
-            Membership previousEndBound = null;
-            Membership nextStartBound = null;
-            if (i > 0)
-                previousEndBound = segments.get(i-1).invertedEndCutoffPlane;
-            if (i < segments.size())
-                nextStartBound = segments.get(i).invertedStartCutoffPlane;
-            if (pathPoint.intersects(plane, bounds, previousEndBound, nextStartBound)) {
+        for (final SegmentEndpoint pathPoint : points) {
+            if (pathPoint.intersects(plane, notablePoints, bounds)) {
                 return true;
             }
         }
 
-        for (PathSegment pathSegment : segments) {
-            if (pathSegment.intersects(plane, bounds)) {
+        for (final PathSegment pathSegment : segments) {
+            if (pathSegment.intersects(plane, notablePoints, bounds)) {
                 return true;
             }
         }
@@ -363,7 +386,11 @@ public class GeoPath extends GeoBaseExte
         public final double cutoffNormalDistance;
         public final double cutoffAngle;
         public final double chordDistance;
-
+        public Membership[] cutoffPlanes = null;
+        public GeoPoint[] notablePoints = null;
+        
+        public final static GeoPoint[] circlePoints = new GeoPoint[0];
+        
         public SegmentEndpoint(final GeoPoint point, final double originDistance, final double cutoffOffset, final double cutoffAngle, final double chordDistance)
         {
             this.point = point;
@@ -373,6 +400,30 @@ public class GeoPath extends GeoBaseExte
             this.circlePlane = new SidedPlane(point, point, -originDistance);
         }
       
+        public void setCutoffPlanes(final GeoPoint[] previousEndNotablePoints, final Membership previousEndPlane,
+            final GeoPoint[] nextStartNotablePoints, final Membership nextStartPlane) {
+            if (previousEndNotablePoints == null && nextStartNotablePoints == null) {
+                cutoffPlanes = new Membership[0];
+                notablePoints = new GeoPoint[0];
+            } else if (previousEndNotablePoints != null && nextStartNotablePoints == null) {
+                cutoffPlanes = new Membership[]{previousEndPlane};
+                notablePoints = previousEndNotablePoints;
+            } else if (previousEndNotablePoints == null && nextStartNotablePoints != null) {
+                cutoffPlanes = new Membership[]{nextStartPlane};
+                notablePoints = nextStartNotablePoints;
+            } else {
+                cutoffPlanes = new Membership[]{previousEndPlane,nextStartPlane};
+                notablePoints = new GeoPoint[previousEndNotablePoints.length + nextStartNotablePoints.length];
+                int i = 0;
+                for (GeoPoint p : previousEndNotablePoints) {
+                    notablePoints[i++] = p;
+                }
+                for (GeoPoint p : nextStartNotablePoints) {
+                    notablePoints[i++] = p;
+                }
+            }
+        }
+        
         public boolean isWithin(final Vector point)
         {
             return circlePlane.isWithin(point);
@@ -407,9 +458,9 @@ public class GeoPath extends GeoBaseExte
             return dist;
         }
         
-        public boolean intersects(final Plane p, final Membership[] bounds, final Membership previousEndCutoff, final Membership nextStartCutoff)
+        public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds)
         {
-            return circlePlane.intersects(p, bounds, previousEndCutoff, nextStartCutoff);
+            return circlePlane.intersects(p, notablePoints, this.notablePoints, bounds, this.cutoffPlanes);
         }
 
         public void getBounds(Bounds bounds)
@@ -450,6 +501,10 @@ public class GeoPath extends GeoBaseExte
         public final SidedPlane lowerConnectingPlane;
         public final SidedPlane startCutoffPlane;
         public final SidedPlane endCutoffPlane;
+        public final GeoPoint[] upperConnectingPlanePoints;
+        public final GeoPoint[] lowerConnectingPlanePoints;
+        public final GeoPoint[] startCutoffPlanePoints;
+        public final GeoPoint[] endCutoffPlanePoints;
         public final double planeBoundingOffset;
         public final double arcWidth;
         public final double chordDistance;
@@ -475,6 +530,10 @@ public class GeoPath extends GeoBaseExte
                 lowerConnectingPlane = null;
                 startCutoffPlane = null;
                 endCutoffPlane = null;
+                upperConnectingPlanePoints = null;
+                lowerConnectingPlanePoints = null;
+                startCutoffPlanePoints = null;
+                endCutoffPlanePoints = null;
                 invertedStartCutoffPlane = null;
                 invertedEndCutoffPlane = null;
             } else {
@@ -484,6 +543,18 @@ public class GeoPath extends GeoBaseExte
                 // Cutoff planes use opposite endpoints as correct side examples
                 startCutoffPlane = new SidedPlane(end,normalizedConnectingPlane,start);
                 endCutoffPlane = new SidedPlane(start,normalizedConnectingPlane,end);
+                final Membership[] upperSide = new Membership[]{upperConnectingPlane};
+                final Membership[] lowerSide = new Membership[]{lowerConnectingPlane};
+                final Membership[] startSide = new Membership[]{startCutoffPlane};
+                final Membership[] endSide = new Membership[]{endCutoffPlane};
+                final GeoPoint ULHC = upperConnectingPlane.findIntersections(startCutoffPlane,lowerSide,endSide)[0];
+                final GeoPoint URHC = upperConnectingPlane.findIntersections(endCutoffPlane,lowerSide,startSide)[0];
+                final GeoPoint LLHC = lowerConnectingPlane.findIntersections(startCutoffPlane,upperSide,endSide)[0];
+                final GeoPoint LRHC = lowerConnectingPlane.findIntersections(endCutoffPlane,upperSide,startSide)[0];
+                upperConnectingPlanePoints = new GeoPoint[]{ULHC,URHC};
+                lowerConnectingPlanePoints = new GeoPoint[]{LLHC,LRHC};
+                startCutoffPlanePoints = new GeoPoint[]{ULHC,LLHC};
+                endCutoffPlanePoints = new GeoPoint[]{URHC,LRHC};
                 invertedStartCutoffPlane = new SidedPlane(startCutoffPlane);
                 invertedEndCutoffPlane = new SidedPlane(endCutoffPlane);
             }
@@ -535,7 +606,7 @@ public class GeoPath extends GeoBaseExte
             final double perpZ = normalizedConnectingPlane.x * point.y - normalizedConnectingPlane.y * point.x;
 
             // If we have a degenerate line, then just compute the normal distance from point x to the start
-            if (perpX < 1e-10 && perpY < 1e-10 && perpZ < 1e-10)
+            if (Math.abs(perpX) < Vector.MINIMUM_RESOLUTION && Math.abs(perpY) < Vector.MINIMUM_RESOLUTION && Math.abs(perpZ) < Vector.MINIMUM_RESOLUTION)
               return point.normalDistance(start);
 
             final double normFactor = 1.0 / Math.sqrt(perpX * perpX + perpY * perpY + perpZ * perpZ);
@@ -556,7 +627,7 @@ public class GeoPath extends GeoBaseExte
             final double perpZ = normalizedConnectingPlane.x * point.y - normalizedConnectingPlane.y * point.x;
 
             // If we have a degenerate line, then just compute the normal distance from point x to the start
-            if (Math.abs(perpX) < 1e-10 && Math.abs(perpY) < 1e-10 && Math.abs(perpZ) < 1e-10)
+            if (Math.abs(perpX) < Vector.MINIMUM_RESOLUTION && Math.abs(perpY) < Vector.MINIMUM_RESOLUTION && Math.abs(perpZ) < Vector.MINIMUM_RESOLUTION)
                 return point.linearDistance(start);
 
             // Next, we need the vector of the line, which is the cross product of the normalized connecting plane
@@ -584,10 +655,10 @@ public class GeoPath extends GeoBaseExte
             return point.linearDistance(normLineX,normLineY,normLineZ) + start.linearDistance(normLineX,normLineY,normLineZ);
         }
         
-        public boolean intersects(final Plane p, final Membership[] bounds)
+        public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership[] bounds)
         {
-            return upperConnectingPlane.intersects(p, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
-                lowerConnectingPlane.intersects(p, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
+            return upperConnectingPlane.intersects(p, notablePoints, upperConnectingPlanePoints, bounds, lowerConnectingPlane, startCutoffPlane, endCutoffPlane) ||
+                lowerConnectingPlane.intersects(p, notablePoints, lowerConnectingPlanePoints, bounds, upperConnectingPlane, startCutoffPlane, endCutoffPlane);
         }
 
         public void getBounds(Bounds bounds)

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoPoint.java Wed Apr 22 14:47:00 2015
@@ -41,42 +41,4 @@ public class GeoPoint extends Vector
         return Tools.safeAcos(evaluate(v));
     }
 
-    /** Find a single point that is a specified arc distance away from this point.
-    */
-    public GeoPoint getSamplePoint(final double sinRotationAngle, final double cosRotationAngle) {
-        // Rotate in the best of three possible directions: x-y, x-z, y-z.
-        final double absX = Math.abs(x);
-        final double absY = Math.abs(y);
-        final double absZ = Math.abs(z);
-        if (absX > absY) {
-            // x > y
-            if (absY > absZ) {
-                // x > y > z
-                // rotate in x-y
-                return new GeoPoint(x*cosRotationAngle-y*sinRotationAngle,x*sinRotationAngle+y*cosRotationAngle,z);
-            } else {
-                // x > z > y OR z > x > y
-                // rotate in x-z
-                return new GeoPoint(x*cosRotationAngle-z*sinRotationAngle,y,x*sinRotationAngle+z*cosRotationAngle);
-            }
-        } else {
-            // y > x
-            if (absX > absZ) {
-                // y > x > z
-                // rotate in x-y
-                return new GeoPoint(x*cosRotationAngle-y*sinRotationAngle,x*sinRotationAngle+y*cosRotationAngle,z);
-            } else {
-                // y > z > x OR z > y > x
-                // rotate in y-z
-                return new GeoPoint(x,y*cosRotationAngle-z*sinRotationAngle,y*sinRotationAngle+z*cosRotationAngle);
-            }
-        }
-    }
-    
-    /** Find a single point that is a specified arc distance away from this point.
-    */
-    public GeoPoint getSamplePoint(final double rotationAngle) {
-        return getSamplePoint(Math.sin(rotationAngle), Math.cos(rotationAngle));
-    }
-
 }

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoRectangle.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoRectangle.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoRectangle.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoRectangle.java Wed Apr 22 14:47:00 2015
@@ -39,7 +39,12 @@ public class GeoRectangle extends GeoBBo
     public final SidedPlane bottomPlane;
     public final SidedPlane leftPlane;
     public final SidedPlane rightPlane;
-      
+    
+    public final GeoPoint[] topPlanePoints;
+    public final GeoPoint[] bottomPlanePoints;
+    public final GeoPoint[] leftPlanePoints;
+    public final GeoPoint[] rightPlanePoints;
+    
     public final GeoPoint centerPoint;
 
     public final GeoPoint[] edgePoints;
@@ -103,6 +108,11 @@ public class GeoRectangle extends GeoBBo
         this.leftPlane = new SidedPlane(centerPoint,cosLeftLon,sinLeftLon);
         this.rightPlane = new SidedPlane(centerPoint,cosRightLon,sinRightLon);
 
+        this.topPlanePoints = new GeoPoint[]{ULHC,URHC};
+        this.bottomPlanePoints = new GeoPoint[]{LLHC,LRHC};
+        this.leftPlanePoints = new GeoPoint[]{ULHC,LLHC};
+        this.rightPlanePoints = new GeoPoint[]{URHC,LRHC};
+        
         this.edgePoints = new GeoPoint[]{ULHC};
     }
 
@@ -161,12 +171,12 @@ public class GeoRectangle extends GeoBBo
     }
       
     @Override
-    public boolean intersects(final Plane p, final Membership... bounds)
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
     {
-        return p.intersects(topPlane,bounds,bottomPlane,leftPlane,rightPlane) ||
-          p.intersects(bottomPlane,bounds,topPlane,leftPlane,rightPlane) ||
-          p.intersects(leftPlane,bounds,rightPlane,topPlane,bottomPlane) ||
-          p.intersects(rightPlane,bounds,leftPlane,topPlane,bottomPlane);
+        return p.intersects(topPlane,notablePoints,topPlanePoints,bounds,bottomPlane,leftPlane,rightPlane) ||
+          p.intersects(bottomPlane,notablePoints,bottomPlanePoints,bounds,topPlane,leftPlane,rightPlane) ||
+          p.intersects(leftPlane,notablePoints,leftPlanePoints,bounds,rightPlane,topPlane,bottomPlane) ||
+          p.intersects(rightPlane,notablePoints,rightPlanePoints,bounds,leftPlane,topPlane,bottomPlane);
     }
 
     /** Compute longitude/latitude bounds for the shape.
@@ -188,27 +198,40 @@ public class GeoRectangle extends GeoBBo
 
     @Override
     public int getRelationship(final GeoShape path) {
+        //System.err.println(this+" getrelationship with "+path);
         final int insideRectangle = isShapeInsideBBox(path);
         if (insideRectangle == SOME_INSIDE)
+        {
+            //System.err.println(" some inside");
             return OVERLAPS;
+        }
 
         final boolean insideShape = path.isWithin(ULHC);
-        
-        if (insideRectangle == ALL_INSIDE && insideShape)
+
+        if (insideRectangle == ALL_INSIDE && insideShape) {
+            //System.err.println(" inside of each other");
             return OVERLAPS;
+        }
 
-        if (path.intersects(topPlane,bottomPlane,leftPlane,rightPlane) ||
-            path.intersects(bottomPlane,topPlane,leftPlane,rightPlane) ||
-            path.intersects(leftPlane,topPlane,bottomPlane,rightPlane) ||
-            path.intersects(rightPlane,leftPlane,topPlane,bottomPlane))
+        if (path.intersects(topPlane,topPlanePoints,bottomPlane,leftPlane,rightPlane) ||
+            path.intersects(bottomPlane,bottomPlanePoints,topPlane,leftPlane,rightPlane) ||
+            path.intersects(leftPlane,leftPlanePoints,topPlane,bottomPlane,rightPlane) ||
+            path.intersects(rightPlane,rightPlanePoints,leftPlane,topPlane,bottomPlane)) {
+            //System.err.println(" edges intersect");
             return OVERLAPS;
+        }
 
         if (insideRectangle == ALL_INSIDE)
+        {
+            //System.err.println(" shape inside rectangle");
             return WITHIN;
+        }
     
-        if (insideShape)
+        if (insideShape) {
+            //System.err.println(" shape contains rectangle");
             return CONTAINS;
-        
+        }
+        //System.err.println(" disjoint");
         return DISJOINT;
     }
 

Modified: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoShape.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoShape.java?rev=1675374&r1=1675373&r2=1675374&view=diff
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoShape.java (original)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoShape.java Wed Apr 22 14:47:00 2015
@@ -37,11 +37,14 @@ public interface GeoShape extends Member
      * helped for some complex shapes that are built out of overlapping parts.
      *@param plane is the plane to assess for intersection with the shape's edges or
      *  bounding curves.
+     *@param notablePoints represents the intersections of the plane with the supplied
+     *  bounds.  These are used to disambiguate when two planes are identical and it needs
+     *  to be determined whether any points exist that fulfill all the bounds.
      *@param bounds are a set of bounds that define an area that an
      *  intersection must be within in order to qualify (provided by a GeoArea).
      *@return true if there's such an intersection, false if not.
      */
-    public boolean intersects(final Plane plane, final Membership... bounds);
+    public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds);
 
     /** Compute longitude/latitude bounds for the shape.
     *@param bounds is the optional input bounds object.  If this is null,

Added: lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthLatitudeZone.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthLatitudeZone.java?rev=1675374&view=auto
==============================================================================
--- lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthLatitudeZone.java (added)
+++ lucene/dev/branches/lucene6196/lucene/spatial/src/java/org/apache/lucene/spatial/spatial4j/geo3d/GeoSouthLatitudeZone.java Wed Apr 22 14:47:00 2015
@@ -0,0 +1,167 @@
+package org.apache.lucene.spatial.spatial4j.geo3d;
+
+/*
+ * 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.
+ */
+
+/** This GeoBBox represents an area rectangle limited only in north latitude.
+*/
+public class GeoSouthLatitudeZone extends GeoBBoxBase
+{
+    public final double topLat;
+    public final double cosTopLat;
+    public final SidedPlane topPlane;
+    public final GeoPoint interiorPoint;
+    public final static GeoPoint[] planePoints = new GeoPoint[0];
+
+    public final GeoPoint topBoundaryPoint;
+    
+    // Edge points
+    public final GeoPoint[] edgePoints;
+    
+    public GeoSouthLatitudeZone(final double topLat)
+    {
+        this.topLat = topLat;
+          
+        final double sinTopLat = Math.sin(topLat);
+        this.cosTopLat = Math.cos(topLat);
+          
+        // Construct sample points, so we get our sidedness right
+        final Vector topPoint = new Vector(0.0,0.0,sinTopLat);
+
+        // Compute an interior point.  Pick one whose lat is between top and bottom.
+        final double middleLat = (topLat - Math.PI * 0.5) * 0.5;
+        final double sinMiddleLat = Math.sin(middleLat);
+        this.interiorPoint = new GeoPoint(Math.sqrt(1.0 - sinMiddleLat * sinMiddleLat),0.0,sinMiddleLat);
+        this.topBoundaryPoint = new GeoPoint(Math.sqrt(1.0 - sinTopLat * sinTopLat),0.0,sinTopLat);
+        
+        this.topPlane = new SidedPlane(interiorPoint,sinTopLat);
+        
+        this.edgePoints = new GeoPoint[]{topBoundaryPoint};
+    }
+
+    @Override
+    public GeoBBox expand(final double angle)
+    {
+        final double newTopLat = topLat + angle;
+        final double newBottomLat = -Math.PI * 0.5;
+        return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, -Math.PI, Math.PI);
+    }
+
+    @Override
+    public boolean isWithin(final Vector point)
+    {
+        return topPlane.isWithin(point);
+    }
+
+    @Override
+    public boolean isWithin(final double x, final double y, final double z)
+    {
+        return topPlane.isWithin(x,y,z);
+    }
+
+    @Override
+    public double getRadius()
+    {
+        // This is a bit tricky.  I guess we should interpret this as meaning the angle of a circle that
+        // would contain all the bounding box points, when starting in the "center".
+        if (topLat > 0.0)
+            return Math.PI;
+        double maxCosLat = cosTopLat;
+        return maxCosLat * Math.PI;
+    }
+
+    @Override
+    public GeoPoint[] getEdgePoints()
+    {
+        return edgePoints;
+    }
+      
+    @Override
+    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
+    {
+        return p.intersects(topPlane,notablePoints,planePoints,bounds);
+    }
+
+    /** Compute longitude/latitude bounds for the shape.
+    *@param bounds is the optional input bounds object.  If this is null,
+    * a bounds object will be created.  Otherwise, the input object will be modified.
+    *@return a Bounds object describing the shape's bounds.  If the bounds cannot
+    * be computed, then return a Bounds object with noLongitudeBound,
+    * noTopLatitudeBound, and noBottomLatitudeBound.
+    */
+    @Override
+    public Bounds getBounds(Bounds bounds)
+    {
+        if (bounds == null)
+            bounds = new Bounds();
+        bounds.noLongitudeBound().addLatitudeZone(topLat).noBottomLatitudeBound();
+        return bounds;
+    }
+
+    @Override
+    public int getRelationship(final GeoShape path) {
+        final int insideRectangle = isShapeInsideBBox(path);
+        if (insideRectangle == SOME_INSIDE)
+            return OVERLAPS;
+
+        final boolean insideShape = path.isWithin(topBoundaryPoint);
+        
+        if (insideRectangle == ALL_INSIDE && insideShape)
+            return OVERLAPS;
+
+        // Second, the shortcut of seeing whether endpoints are in/out is not going to 
+        // work with no area endpoints.  So we rely entirely on intersections.
+
+        if (path.intersects(topPlane,planePoints))
+            return OVERLAPS;
+
+        // There is another case for latitude zones only.  This is when the boundaries of the shape all fit
+        // within the zone, but the shape includes areas outside the zone crossing a pole.
+        // In this case, the above "overlaps" check is insufficient.  We also need to check a point on either boundary
+        // whether it is within the shape.  If both such points are within, then CONTAINS is the right answer.  If
+        // one such point is within, then OVERLAPS is the right answer.  
+        
+        if (insideShape)
+            return CONTAINS;
+
+        if (insideRectangle == ALL_INSIDE)
+            return WITHIN;
+
+        return DISJOINT;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof GeoSouthLatitudeZone))
+            return false;
+        GeoSouthLatitudeZone other = (GeoSouthLatitudeZone)o;
+        return other.topPlane.equals(topPlane);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = topPlane.hashCode();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        return "GeoSouthLatitudeZone: {toplat="+topLat+"("+topLat*180.0/Math.PI+")}";
+    }
+}
+