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/05/04 15:19:03 UTC

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

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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -21,250 +21,251 @@ import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.List;
 
-/** GeoConvexPolygon objects are generic building blocks of more complex structures.
-* The only restrictions on these objects are: (1) they must be convex; (2) they must have
-* a maximum extent no larger than PI.  Violating either one of these limits will
-* cause the logic to fail.
-*/
-public class GeoConvexPolygon extends GeoBaseExtendedShape implements GeoMembershipShape
-{
-    protected final List<GeoPoint> points;
-    protected final BitSet isInternalEdges;
-
-    protected SidedPlane[] edges = null;
-    protected boolean[] internalEdges = null;
-    protected GeoPoint[][] notableEdgePoints = null;
-    
-    protected GeoPoint[] edgePoints = null;
-    
-    protected double fullDistance = 0.0;
-    
-    /** Create a convex polygon from a list of points.  The first point must be on the
-    * external edge.
-    */
-    public GeoConvexPolygon(final List<GeoPoint> pointList) {
-        this.points = pointList;
-        this.isInternalEdges = null;
-        donePoints(false);
-    }
-
-    /** Create a convex polygon from a list of points, keeping track of which boundaries
-    * are internal.  This is used when creating a polygon as a building block for another shape.
-    */
-    public GeoConvexPolygon(final List<GeoPoint> pointList, final BitSet internalEdgeFlags, final boolean returnEdgeInternal) {
-        this.points = pointList;
-        this.isInternalEdges = internalEdgeFlags;
-        donePoints(returnEdgeInternal);
-    }
-    
-    /** Create a convex polygon, with a starting latitude and longitude.
-    * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-    */
-    public GeoConvexPolygon(final double startLatitude, final double startLongitude)
-    {
-        points = new ArrayList<GeoPoint>();
-        isInternalEdges = new BitSet();
-        // Argument checking
-        if (startLatitude > Math.PI * 0.5 || startLatitude < -Math.PI * 0.5)
-            throw new IllegalArgumentException("Latitude out of range");
-        if (startLongitude < -Math.PI || startLongitude > Math.PI)
-            throw new IllegalArgumentException("Longitude out of range");
-        
-        final GeoPoint p = new GeoPoint(startLatitude, startLongitude);
-        points.add(p);
-    }
-    
-    /** Add a point to the polygon.
-     * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
-     *@param latitude is the latitude of the next point.
-     *@param longitude is the longitude of the next point.
-     *@param isInternalEdge is true if the edge just added should be considered "internal", and not
-     * intersected as part of the intersects() operation.
-     */
-    public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
-        // Argument checking
-        if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-            throw new IllegalArgumentException("Latitude out of range");
-        if (longitude < -Math.PI || longitude > Math.PI)
-            throw new IllegalArgumentException("Longitude out of range");
-        
-        final GeoPoint p = new GeoPoint(latitude, longitude);
-        isInternalEdges.set(points.size(),isInternalEdge);
-        points.add(p);
-    }
-
-    /** Finish the polygon, by connecting the last added point with the starting point.
-    */
-    public void donePoints(final boolean isInternalReturnEdge) {
-        // If fewer than 3 points, can't do it.
-        if (points.size() < 3)
-            throw new IllegalArgumentException("Polygon needs at least three points.");
-        // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
-        // to a segment can provide an interior measurement.
-        edges = new SidedPlane[points.size()];
-        notableEdgePoints = new GeoPoint[points.size()][];
-        internalEdges = new boolean[points.size()];
-        for (int i = 0; i < points.size(); i++) {
-            final GeoPoint start = points.get(i);
-            final boolean isInternalEdge = (isInternalEdges!=null?(i == isInternalEdges.size()?isInternalReturnEdge:isInternalEdges.get(i)):false);
-            final GeoPoint end = points.get(legalIndex(i+1));
-            final double distance = start.arcDistance(end);
-            if (distance > fullDistance)
-                fullDistance = distance;
-            final GeoPoint check = points.get(legalIndex(i+2));
-            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();
-    }
-    
-    protected void createCenterPoint() {
-        // In order to naively confirm that the polygon is convex, I would need to
-        // check every edge, and verify that every point (other than the edge endpoints)
-        // is within the edge's sided plane.  This is an order n^2 operation.  That's still
-        // not wrong, though, because everything else about polygons has a similar cost.
-        for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-            final SidedPlane edge = edges[edgeIndex];
-            for (int pointIndex =0; pointIndex < points.size(); pointIndex++) {
-                if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex+1)) {
-                    if (!edge.isWithin(points.get(pointIndex)))
-                        throw new IllegalArgumentException("Polygon is not convex: Point "+points.get(pointIndex)+" Edge "+edge);
-                }
-            }
-        }
-        edgePoints = new GeoPoint[]{points.get(0)};
-    }
-    
-    protected int legalIndex(int index) {
-        while (index >= points.size())
-            index -= points.size();
-        return index;
-    }
-    
-    @Override
-    public boolean isWithin(final Vector point)
-    {
-        for (final SidedPlane edge : edges) {
-            if (!edge.isWithin(point))
-                return false;
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z)
-    {
-        for (final SidedPlane edge : edges) {
-            if (!edge.isWithin(x,y,z))
-                return false;
-        }
-        return true;
-    }
-
-    @Override
-    public GeoPoint[] getEdgePoints()
-    {
-        return edgePoints;
-    }
-      
-    @Override
-    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];
-                int count = 0;
-                for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-                    if (otherIndex != edgeIndex) {
-                        membershipBounds[count++] = edges[otherIndex];
-                    }
-                }
-                if (edge.intersects(p,notablePoints, points, bounds,membershipBounds)) {
-                    //System.err.println(" intersects!");
-                    return true;
-                }
-            }
-        }
-        //System.err.println(" no intersection");
+/**
+ * GeoConvexPolygon objects are generic building blocks of more complex structures.
+ * The only restrictions on these objects are: (1) they must be convex; (2) they must have
+ * a maximum extent no larger than PI.  Violating either one of these limits will
+ * cause the logic to fail.
+ */
+public class GeoConvexPolygon extends GeoBaseExtendedShape implements GeoMembershipShape {
+  protected final List<GeoPoint> points;
+  protected final BitSet isInternalEdges;
+
+  protected SidedPlane[] edges = null;
+  protected boolean[] internalEdges = null;
+  protected GeoPoint[][] notableEdgePoints = null;
+
+  protected GeoPoint[] edgePoints = null;
+
+  protected double fullDistance = 0.0;
+
+  /**
+   * Create a convex polygon from a list of points.  The first point must be on the
+   * external edge.
+   */
+  public GeoConvexPolygon(final List<GeoPoint> pointList) {
+    this.points = pointList;
+    this.isInternalEdges = null;
+    donePoints(false);
+  }
+
+  /**
+   * Create a convex polygon from a list of points, keeping track of which boundaries
+   * are internal.  This is used when creating a polygon as a building block for another shape.
+   */
+  public GeoConvexPolygon(final List<GeoPoint> pointList, final BitSet internalEdgeFlags, final boolean returnEdgeInternal) {
+    this.points = pointList;
+    this.isInternalEdges = internalEdgeFlags;
+    donePoints(returnEdgeInternal);
+  }
+
+  /**
+   * Create a convex polygon, with a starting latitude and longitude.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   */
+  public GeoConvexPolygon(final double startLatitude, final double startLongitude) {
+    points = new ArrayList<GeoPoint>();
+    isInternalEdges = new BitSet();
+    // Argument checking
+    if (startLatitude > Math.PI * 0.5 || startLatitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (startLongitude < -Math.PI || startLongitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+
+    final GeoPoint p = new GeoPoint(startLatitude, startLongitude);
+    points.add(p);
+  }
+
+  /**
+   * Add a point to the polygon.
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   *
+   * @param latitude       is the latitude of the next point.
+   * @param longitude      is the longitude of the next point.
+   * @param isInternalEdge is true if the edge just added should be considered "internal", and not
+   *                       intersected as part of the intersects() operation.
+   */
+  public void addPoint(final double latitude, final double longitude, final boolean isInternalEdge) {
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Latitude out of range");
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+
+    final GeoPoint p = new GeoPoint(latitude, longitude);
+    isInternalEdges.set(points.size(), isInternalEdge);
+    points.add(p);
+  }
+
+  /**
+   * Finish the polygon, by connecting the last added point with the starting point.
+   */
+  public void donePoints(final boolean isInternalReturnEdge) {
+    // If fewer than 3 points, can't do it.
+    if (points.size() < 3)
+      throw new IllegalArgumentException("Polygon needs at least three points.");
+    // Time to construct the planes.  If the polygon is truly convex, then any adjacent point
+    // to a segment can provide an interior measurement.
+    edges = new SidedPlane[points.size()];
+    notableEdgePoints = new GeoPoint[points.size()][];
+    internalEdges = new boolean[points.size()];
+    for (int i = 0; i < points.size(); i++) {
+      final GeoPoint start = points.get(i);
+      final boolean isInternalEdge = (isInternalEdges != null ? (i == isInternalEdges.size() ? isInternalReturnEdge : isInternalEdges.get(i)) : false);
+      final GeoPoint end = points.get(legalIndex(i + 1));
+      final double distance = start.arcDistance(end);
+      if (distance > fullDistance)
+        fullDistance = distance;
+      final GeoPoint check = points.get(legalIndex(i + 2));
+      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();
+  }
+
+  protected void createCenterPoint() {
+    // In order to naively confirm that the polygon is convex, I would need to
+    // check every edge, and verify that every point (other than the edge endpoints)
+    // is within the edge's sided plane.  This is an order n^2 operation.  That's still
+    // not wrong, though, because everything else about polygons has a similar cost.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) {
+        if (pointIndex != edgeIndex && pointIndex != legalIndex(edgeIndex + 1)) {
+          if (!edge.isWithin(points.get(pointIndex)))
+            throw new IllegalArgumentException("Polygon is not convex: Point " + points.get(pointIndex) + " Edge " + edge);
+        }
+      }
+    }
+    edgePoints = new GeoPoint[]{points.get(0)};
+  }
+
+  protected int legalIndex(int index) {
+    while (index >= points.size())
+      index -= points.size();
+    return index;
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    for (final SidedPlane edge : edges) {
+      if (!edge.isWithin(point))
         return false;
     }
+    return true;
+  }
 
-    /** 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)
-    {
-        bounds = super.getBounds(bounds);
-
-        // Add all the points
-        for (final GeoPoint point : points) {
-            bounds.addPoint(point);
-        }
-
-        // Add planes with membership.
-        for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
-            final SidedPlane edge = edges[edgeIndex];
-            // Construct boundaries
-            final Membership[] membershipBounds = new Membership[edges.length-1];
-            int count = 0;
-            for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
-                if (otherIndex != edgeIndex) {
-                    membershipBounds[count++] = edges[otherIndex];
-                }
-            }
-            edge.recordBounds(bounds,membershipBounds);
-        }
-
-        if (fullDistance >= Math.PI) {
-            // We can't reliably assume that bounds did its longitude calculation right, so we force it to be unbounded.
-            bounds.noLongitudeBound();
-        }
-        return bounds;
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    for (final SidedPlane edge : edges) {
+      if (!edge.isWithin(x, y, z))
+        return false;
     }
+    return true;
+  }
 
-    @Override
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof GeoConvexPolygon))
-            return false;
-        GeoConvexPolygon other = (GeoConvexPolygon)o;
-        if (other.points.size() != points.size())
-            return false;
-        
-        for (int i = 0; i < points.size(); i++) {
-            if (!other.points.get(i).equals(points.get(i)))
-                return false;
-        }
-        return true;
-    }
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  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];
+        int count = 0;
+        for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+          if (otherIndex != edgeIndex) {
+            membershipBounds[count++] = edges[otherIndex];
+          }
+        }
+        if (edge.intersects(p, notablePoints, points, bounds, membershipBounds)) {
+          //System.err.println(" intersects!");
+          return true;
+        }
+      }
+    }
+    //System.err.println(" no intersection");
+    return false;
+  }
+
+  /**
+   * 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) {
+    bounds = super.getBounds(bounds);
+
+    // Add all the points
+    for (final GeoPoint point : points) {
+      bounds.addPoint(point);
+    }
+
+    // Add planes with membership.
+    for (int edgeIndex = 0; edgeIndex < edges.length; edgeIndex++) {
+      final SidedPlane edge = edges[edgeIndex];
+      // Construct boundaries
+      final Membership[] membershipBounds = new Membership[edges.length - 1];
+      int count = 0;
+      for (int otherIndex = 0; otherIndex < edges.length; otherIndex++) {
+        if (otherIndex != edgeIndex) {
+          membershipBounds[count++] = edges[otherIndex];
+        }
+      }
+      edge.recordBounds(bounds, membershipBounds);
+    }
+
+    if (fullDistance >= Math.PI) {
+      // We can't reliably assume that bounds did its longitude calculation right, so we force it to be unbounded.
+      bounds.noLongitudeBound();
+    }
+    return bounds;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoConvexPolygon))
+      return false;
+    GeoConvexPolygon other = (GeoConvexPolygon) o;
+    if (other.points.size() != points.size())
+      return false;
 
-    @Override
-    public int hashCode() {
-        return points.hashCode();
+    for (int i = 0; i < points.size(); i++) {
+      if (!other.points.get(i).equals(points.get(i)))
+        return false;
     }
+    return true;
+  }
 
-    @Override
-    public String toString() {
-        StringBuilder edgeString = new StringBuilder("{");
-        for (int i = 0; i < edges.length; i++) {
-            edgeString.append(edges[i]).append(" internal? ").append(internalEdges[i]).append("; ");
-        }
-        edgeString.append("}");
-        return "GeoConvexPolygon: {points=" + points + " edges="+edgeString+"}";
-    }
+  @Override
+  public int hashCode() {
+    return points.hashCode();
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder edgeString = new StringBuilder("{");
+    for (int i = 0; i < edges.length; i++) {
+      edgeString.append(edges[i]).append(" internal? ").append(internalEdges[i]).append("; ");
+    }
+    edgeString.append("}");
+    return "GeoConvexPolygon: {points=" + points + " edges=" + edgeString + "}";
+  }
 }
   

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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -17,188 +17,185 @@ package org.apache.lucene.spatial.spatia
  * limitations under the License.
  */
 
-/** Degenerate bounding box limited on two sides (left lon, right lon).
-* The left-right maximum extent for this shape is PI; for anything larger, use
-* GeoWideDegenerateHorizontalLine.
-*/
-public class GeoDegenerateHorizontalLine extends GeoBBoxBase
-{
-    public final double latitude;
-    public final double leftLon;
-    public final double rightLon;
-      
-    public final GeoPoint LHC;
-    public final GeoPoint RHC;
-    
-    public final Plane plane;
-    public final SidedPlane leftPlane;
-    public final SidedPlane rightPlane;
-
-    public final GeoPoint[] planePoints;
-
-    public final GeoPoint centerPoint;
-    public final GeoPoint[] edgePoints;
-    
-    /** Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI} */
-    public GeoDegenerateHorizontalLine(final double latitude, final double leftLon, double rightLon)
-    {
-        // Argument checking
-        if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
-            throw new IllegalArgumentException("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.latitude = latitude;
-        this.leftLon = leftLon;
-        this.rightLon = rightLon;
-          
-        final double sinLatitude = Math.sin(latitude);
-        final double cosLatitude = Math.cos(latitude);
-        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 two points
-        this.LHC = new GeoPoint(sinLatitude,sinLeftLon,cosLatitude,cosLeftLon);
-        this.RHC = new GeoPoint(sinLatitude,sinRightLon,cosLatitude,cosRightLon);
-        
-        this.plane = new Plane(sinLatitude);
-
-        // 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(sinLatitude,sinMiddleLon,cosLatitude,cosMiddleLon);
-        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};
-    }
-
-    @Override
-    public GeoBBox expand(final double angle)
-    {
-        double newTopLat = latitude + angle;
-        double newBottomLat = latitude - 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 plane.evaluateIsZero(point) &&
-          leftPlane.isWithin(point) &&
-          rightPlane.isWithin(point);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z)
-    {
-        return plane.evaluateIsZero(x,y,z) &&
-          leftPlane.isWithin(x,y,z) &&
-          rightPlane.isWithin(x,y,z);
-    }
-
-    @Override
-    public double getRadius()
-    {
-        double topAngle = centerPoint.arcDistance(RHC);
-        double bottomAngle = centerPoint.arcDistance(LHC);
-        return Math.max(topAngle,bottomAngle);
-    }
-
-    /** Returns the center of a circle into which the area will be inscribed.
-    *@return the center.
-    */
-    @Override
-    public GeoPoint getCenter() {
-        return centerPoint;
-    }
-
-    @Override
-    public GeoPoint[] getEdgePoints()
-    {
-        return edgePoints;
-    }
-      
-    @Override
-    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
-    {
-        return p.intersects(plane,notablePoints,planePoints,bounds,leftPlane,rightPlane);
-    }
-
-    /** 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.addLatitudeZone(latitude).addLongitudeSlice(leftLon,rightLon);
-        return bounds;
-    }
-
-    @Override
-    public int getRelationship(final GeoShape path) {
-        if (path.intersects(plane,planePoints,leftPlane,rightPlane))
-            return OVERLAPS;
-
-        if (path.isWithin(centerPoint))
-            return CONTAINS;
-
-        return DISJOINT;
-    }
-
-    @Override
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof GeoDegenerateHorizontalLine))
-            return false;
-        GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine)o;
-        return other.LHC.equals(LHC) && other.RHC.equals(RHC);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = LHC.hashCode();
-        result = 31 * result + RHC.hashCode();
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        return "GeoDegenerateHorizontalLine: {latitude="+latitude+"("+latitude*180.0/Math.PI+"), leftlon="+leftLon+"("+leftLon*180.0/Math.PI+"), rightLon="+rightLon+"("+rightLon*180.0/Math.PI+")}";
-    }
+/**
+ * Degenerate bounding box limited on two sides (left lon, right lon).
+ * The left-right maximum extent for this shape is PI; for anything larger, use
+ * GeoWideDegenerateHorizontalLine.
+ */
+public class GeoDegenerateHorizontalLine extends GeoBBoxBase {
+  public final double latitude;
+  public final double leftLon;
+  public final double rightLon;
+
+  public final GeoPoint LHC;
+  public final GeoPoint RHC;
+
+  public final Plane plane;
+  public final SidedPlane leftPlane;
+  public final SidedPlane rightPlane;
+
+  public final GeoPoint[] planePoints;
+
+  public final GeoPoint centerPoint;
+  public final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+   */
+  public GeoDegenerateHorizontalLine(final double latitude, final double leftLon, double rightLon) {
+    // Argument checking
+    if (latitude > Math.PI * 0.5 || latitude < -Math.PI * 0.5)
+      throw new IllegalArgumentException("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.latitude = latitude;
+    this.leftLon = leftLon;
+    this.rightLon = rightLon;
+
+    final double sinLatitude = Math.sin(latitude);
+    final double cosLatitude = Math.cos(latitude);
+    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 two points
+    this.LHC = new GeoPoint(sinLatitude, sinLeftLon, cosLatitude, cosLeftLon);
+    this.RHC = new GeoPoint(sinLatitude, sinRightLon, cosLatitude, cosRightLon);
+
+    this.plane = new Plane(sinLatitude);
+
+    // 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(sinLatitude, sinMiddleLon, cosLatitude, cosMiddleLon);
+    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};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - 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 plane.evaluateIsZero(point) &&
+        leftPlane.isWithin(point) &&
+        rightPlane.isWithin(point);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        leftPlane.isWithin(x, y, z) &&
+        rightPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    double topAngle = centerPoint.arcDistance(RHC);
+    double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(plane, notablePoints, planePoints, bounds, leftPlane, rightPlane);
+  }
+
+  /**
+   * 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.addLatitudeZone(latitude).addLongitudeSlice(leftLon, rightLon);
+    return bounds;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    if (path.intersects(plane, planePoints, leftPlane, rightPlane))
+      return OVERLAPS;
+
+    if (path.isWithin(centerPoint))
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateHorizontalLine))
+      return false;
+    GeoDegenerateHorizontalLine other = (GeoDegenerateHorizontalLine) o;
+    return other.LHC.equals(LHC) && other.RHC.equals(RHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = LHC.hashCode();
+    result = 31 * result + RHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateHorizontalLine: {latitude=" + latitude + "(" + latitude * 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/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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -17,130 +17,125 @@ package org.apache.lucene.spatial.spatia
  * limitations under the License.
  */
 
-/** This GeoBBox represents an area rectangle of one specific latitude with
-* no longitude bounds.
-*/
-public class GeoDegenerateLatitudeZone extends GeoBBoxBase
-{
-    public final double latitude;
-    
-    public final double sinLatitude;
-    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)
-    {
-        this.latitude = latitude;
-          
-        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};
-    }
-
-    @Override
-    public GeoBBox expand(final double angle)
-    {
-        double newTopLat = latitude + angle;
-        double newBottomLat = latitude - angle;
-        return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, -Math.PI, Math.PI);
-    }
-
-    @Override
-    public boolean isWithin(final Vector point)
-    {
-        return Math.abs(point.z - this.sinLatitude) < 1e-10;
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z)
-    {
-        return Math.abs(z - this.sinLatitude) < 1e-10;
-    }
-
-    @Override
-    public double getRadius()
-    {
-        return Math.PI;
-    }
-
-    /** Returns the center of a circle into which the area will be inscribed.
-    *@return the center.
-    */
-    @Override
-    public GeoPoint getCenter() {
-        // Totally arbitrary
-        return interiorPoint;
-    }
-
-    @Override
-    public GeoPoint[] getEdgePoints()
-    {
-        return edgePoints;
-    }
-      
-    @Override
-    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
-    {
-        return p.intersects(plane,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(latitude);
-        return bounds;
-    }
-
-    @Override
-    public int getRelationship(final GeoShape path) {
-        // 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.
-        //System.out.println("Got here! latitude="+latitude+" path="+path);
-        
-        if (path.intersects(plane,planePoints)) {
-            return OVERLAPS;
-        }
-
-        if (path.isWithin(interiorPoint)) {
-            return CONTAINS;
-        }
-        
-        return DISJOINT;
-    }
-
-    @Override
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof GeoDegenerateLatitudeZone))
-            return false;
-        GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone)o;
-        return other.latitude == latitude;
-    }
+/**
+ * This GeoBBox represents an area rectangle of one specific latitude with
+ * no longitude bounds.
+ */
+public class GeoDegenerateLatitudeZone extends GeoBBoxBase {
+  public final double latitude;
 
-    @Override
-    public int hashCode() {
-        long temp = Double.doubleToLongBits(latitude);
-        int result = (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        return "GeoDegenerateLatitudeZone: {lat="+latitude+"("+latitude*180.0/Math.PI+")}";
-    }
+  public final double sinLatitude;
+  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) {
+    this.latitude = latitude;
+
+    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};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    double newTopLat = latitude + angle;
+    double newBottomLat = latitude - angle;
+    return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, -Math.PI, Math.PI);
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return Math.abs(point.z - this.sinLatitude) < 1e-10;
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return Math.abs(z - this.sinLatitude) < 1e-10;
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    // Totally arbitrary
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(plane, 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(latitude);
+    return bounds;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // 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.
+    //System.out.println("Got here! latitude="+latitude+" path="+path);
+
+    if (path.intersects(plane, planePoints)) {
+      return OVERLAPS;
+    }
+
+    if (path.isWithin(interiorPoint)) {
+      return CONTAINS;
+    }
+
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLatitudeZone))
+      return false;
+    GeoDegenerateLatitudeZone other = (GeoDegenerateLatitudeZone) o;
+    return other.latitude == latitude;
+  }
+
+  @Override
+  public int hashCode() {
+    long temp = Double.doubleToLongBits(latitude);
+    int result = (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLatitudeZone: {lat=" + latitude + "(" + latitude * 180.0 / Math.PI + ")}";
+  }
 }
 

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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -17,144 +17,141 @@ package org.apache.lucene.spatial.spatia
  * limitations under the License.
  */
 
-/** Degenerate longitude slice.
-*/
-public class GeoDegenerateLongitudeSlice extends GeoBBoxBase
-{
-    public final double longitude;
-    
-    public final double sinLongitude;
-    public final double cosLongitude;
-    public final SidedPlane boundingPlane;
-    public final Plane plane;
-    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)
-    {
-        // Argument checking
-        if (longitude < -Math.PI || longitude > Math.PI)
-            throw new IllegalArgumentException("Longitude out of range");
-        this.longitude = longitude;
-          
-        this.sinLongitude = Math.sin(longitude);
-        this.cosLongitude = Math.cos(longitude);
-
-        this.plane = new Plane(cosLongitude, sinLongitude);
-        // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
-        this.interiorPoint = new GeoPoint(cosLongitude, sinLongitude, 0.0);
-        this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
-        this.edgePoints = new GeoPoint[]{interiorPoint};
-    }
-
-    @Override
-    public GeoBBox expand(final double angle)
-    {
-        // Figuring out when we escalate to a special case requires some prefiguring
-        double newLeftLon = longitude - angle;
-        double newRightLon = longitude + angle;
-        double currentLonSpan = 2.0 * angle;
-        if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
-            newLeftLon = -Math.PI;
-            newRightLon = Math.PI;
-        }
-        return GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5,-Math.PI * 0.5,newLeftLon,newRightLon);
-    }
-
-    @Override
-    public boolean isWithin(final Vector point)
-    {
-        return plane.evaluateIsZero(point) &&
-            boundingPlane.isWithin(point);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z)
-    {
-        return plane.evaluateIsZero(x,y,z) &&
-            boundingPlane.isWithin(x,y,z);
-    }
-
-    @Override
-    public double getRadius()
-    {
-        return Math.PI * 0.5;
-    }
-
-    /** Returns the center of a circle into which the area will be inscribed.
-    *@return the center.
-    */
-    @Override
-    public GeoPoint getCenter() {
-        return interiorPoint;
-    }
-
-    @Override
-    public GeoPoint[] getEdgePoints()
-    {
-        return edgePoints;
-    }
-      
-    @Override
-    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
-    {
-        return p.intersects(plane,notablePoints,planePoints,bounds,boundingPlane);
-    }
-
-    /** 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().noBottomLatitudeBound();
-        bounds.addLongitudeSlice(longitude,longitude);
-        return bounds;
-    }
-
-    @Override
-    public int getRelationship(final GeoShape path) {
-        // Look for intersections.
-        if (path.intersects(plane,planePoints,boundingPlane))
-            return OVERLAPS;
-
-        if (path.isWithin(interiorPoint))
-            return CONTAINS;
-
-        return DISJOINT;
-    }
-
-    @Override
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof GeoDegenerateLongitudeSlice))
-            return false;
-        GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice)o;
-        return other.longitude == longitude;
-    }
+/**
+ * Degenerate longitude slice.
+ */
+public class GeoDegenerateLongitudeSlice extends GeoBBoxBase {
+  public final double longitude;
 
-    @Override
-    public int hashCode() {
-        int result;
-        long temp;
-        temp = Double.doubleToLongBits(longitude);
-        result = (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        return "GeoDegenerateLongitudeSlice: {longitude="+longitude+"("+longitude*180.0/Math.PI+")}";
-    }
+  public final double sinLongitude;
+  public final double cosLongitude;
+  public final SidedPlane boundingPlane;
+  public final Plane plane;
+  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) {
+    // Argument checking
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+    this.longitude = longitude;
+
+    this.sinLongitude = Math.sin(longitude);
+    this.cosLongitude = Math.cos(longitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+    // We need a bounding plane too, which is perpendicular to the longitude plane and sided so that the point (0.0, longitude) is inside.
+    this.interiorPoint = new GeoPoint(cosLongitude, sinLongitude, 0.0);
+    this.boundingPlane = new SidedPlane(interiorPoint, -sinLongitude, cosLongitude);
+    this.edgePoints = new GeoPoint[]{interiorPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    // Figuring out when we escalate to a special case requires some prefiguring
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * angle;
+    if (currentLonSpan + 2.0 * angle >= Math.PI * 2.0) {
+      newLeftLon = -Math.PI;
+      newRightLon = Math.PI;
+    }
+    return GeoBBoxFactory.makeGeoBBox(Math.PI * 0.5, -Math.PI * 0.5, newLeftLon, newRightLon);
+  }
+
+  @Override
+  public boolean isWithin(final Vector point) {
+    return plane.evaluateIsZero(point) &&
+        boundingPlane.isWithin(point);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z);
+  }
+
+  @Override
+  public double getRadius() {
+    return Math.PI * 0.5;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return interiorPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(plane, notablePoints, planePoints, bounds, boundingPlane);
+  }
+
+  /**
+   * 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().noBottomLatitudeBound();
+    bounds.addLongitudeSlice(longitude, longitude);
+    return bounds;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    // Look for intersections.
+    if (path.intersects(plane, planePoints, boundingPlane))
+      return OVERLAPS;
+
+    if (path.isWithin(interiorPoint))
+      return CONTAINS;
+
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateLongitudeSlice))
+      return false;
+    GeoDegenerateLongitudeSlice other = (GeoDegenerateLongitudeSlice) o;
+    return other.longitude == longitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    temp = Double.doubleToLongBits(longitude);
+    result = (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateLongitudeSlice: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
 }
   
 

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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -17,156 +17,175 @@ package org.apache.lucene.spatial.spatia
  * limitations under the License.
  */
 
-/** This class represents a degenerate point bounding box.
-* It is not a simple GeoPoint because we must have the latitude and longitude.
-*/
-public class GeoDegeneratePoint extends GeoPoint implements GeoBBox
-{
-    public final double latitude;
-    public final double longitude;
-    public final GeoPoint[] edgePoints;
-	
-    public GeoDegeneratePoint(final double lat, final double lon)
-    {
-        super(lat,lon);
-        this.latitude = lat;
-        this.longitude = lon;
-        this.edgePoints = new GeoPoint[]{this};
-    }
-
-    /** Expand box by specified angle.
-     *@param angle is the angle amount to expand the GeoBBox by.
-     *@return a new GeoBBox.
-     */
-    @Override
-    public GeoBBox expand(final double angle) {
-        final double newTopLat = latitude + angle;
-        final double newBottomLat = latitude - angle;
-        final double newLeftLon = longitude - angle;
-        final double newRightLon = longitude + angle;
-        return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, newLeftLon, newRightLon);
-    }
-
-    /** Return a sample point that is on the edge of the shape.
-     *@return an interior point.
-     */
-    @Override
-    public GeoPoint[] getEdgePoints() {
-        return edgePoints;
-    }
-    
-    /** Assess whether a plane, within the provided bounds, intersects
-     * with the shape.
-     *@param plane is the plane to assess for intersection with the shape's edges or
-     *  bounding curves.
-     *@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.
-     */
-    @Override
-    public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
-        if (plane.evaluate(this) == 0.0)
-            return false;
-        
-        for (Membership m : bounds) {
-            if (!m.isWithin(this))
-                return false;
-        }
-        return true;
-    }
-
-    /** 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.addPoint(latitude,longitude);
-        return bounds;
-    }
-
-    /** Equals */
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof GeoDegeneratePoint))
-            return false;
-        GeoDegeneratePoint other = (GeoDegeneratePoint)o;
-        return other.latitude == latitude && other.longitude == longitude;
-    }
-
-    @Override
-    public int hashCode() {
-        int result;
-        long temp;
-        temp = Double.doubleToLongBits(latitude);
-        result = (int) (temp ^ (temp >>> 32));
-        temp = Double.doubleToLongBits(longitude);
-        result = 31 * result + (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        return "GeoDegeneratePoint: {lat="+latitude+"("+latitude*180.0/Math.PI+"), lon="+longitude+"("+longitude*180.0/Math.PI+")}";
-    }
-    
-    /** Check if a point is within this shape.
-     *@param point is the point to check.
-     *@return true if the point is within this shape
-     */
-    @Override
-    public boolean isWithin(final Vector point) {
-        return isWithin(point.x,point.y,point.z);
-    }
-
-    /** Check if a point is within this shape.
-     *@param x is x coordinate of point to check.
-     *@param y is y coordinate of point to check.
-     *@param z is z coordinate of point to check.
-     *@return true if the point is within this shape
-     */
-    @Override
-    public boolean isWithin(final double x, final double y, final double z) {
-        return x == this.x && y == this.y && z == this.z;
-    }
-
-    /** Returns the radius of a circle into which the GeoSizeable area can
-     * be inscribed.
-     *@return the radius.
-     */
-    @Override
-    public double getRadius() {
-        return 0.0;
-    }
-
-    /** Returns the center of a circle into which the area will be inscribed.
-    *@return the center.
-    */
-    @Override
-    public GeoPoint getCenter() {
-        return this;
-    }
-
-    /** Find the spatial relationship between a shape and the current geo area.
-     * Note: return value is how the GeoShape relates to the GeoArea, not the
-     * other way around. For example, if this GeoArea is entirely within the
-     * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
-     * by this GeoArea, then WITHIN should be returned.
-     *@param shape is the shape to consider.
-     *@return the relationship, from the perspective of the shape.
-     */
-    @Override
-    public int getRelationship(final GeoShape shape) {
-        if (shape.isWithin(this))
-            return CONTAINS;
+/**
+ * This class represents a degenerate point bounding box.
+ * It is not a simple GeoPoint because we must have the latitude and longitude.
+ */
+public class GeoDegeneratePoint extends GeoPoint implements GeoBBox {
+  public final double latitude;
+  public final double longitude;
+  public final GeoPoint[] edgePoints;
+
+  public GeoDegeneratePoint(final double lat, final double lon) {
+    super(lat, lon);
+    this.latitude = lat;
+    this.longitude = lon;
+    this.edgePoints = new GeoPoint[]{this};
+  }
+
+  /**
+   * Expand box by specified angle.
+   *
+   * @param angle is the angle amount to expand the GeoBBox by.
+   * @return a new GeoBBox.
+   */
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = latitude + angle;
+    final double newBottomLat = latitude - angle;
+    final double newLeftLon = longitude - angle;
+    final double newRightLon = longitude + angle;
+    return GeoBBoxFactory.makeGeoBBox(newTopLat, newBottomLat, newLeftLon, newRightLon);
+  }
+
+  /**
+   * Return a sample point that is on the edge of the shape.
+   *
+   * @return an interior point.
+   */
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  /**
+   * Assess whether a plane, within the provided bounds, intersects
+   * with the shape.
+   *
+   * @param plane  is the plane to assess for intersection with the shape's edges or
+   *               bounding curves.
+   * @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.
+   */
+  @Override
+  public boolean intersects(final Plane plane, final GeoPoint[] notablePoints, final Membership... bounds) {
+    if (plane.evaluate(this) == 0.0)
+      return false;
+
+    for (Membership m : bounds) {
+      if (!m.isWithin(this))
+        return false;
+    }
+    return true;
+  }
+
+  /**
+   * 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.addPoint(latitude, longitude);
+    return bounds;
+  }
+
+  /**
+   * Equals
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegeneratePoint))
+      return false;
+    GeoDegeneratePoint other = (GeoDegeneratePoint) o;
+    return other.latitude == latitude && other.longitude == longitude;
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    temp = Double.doubleToLongBits(latitude);
+    result = (int) (temp ^ (temp >>> 32));
+    temp = Double.doubleToLongBits(longitude);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegeneratePoint: {lat=" + latitude + "(" + latitude * 180.0 / Math.PI + "), lon=" + longitude + "(" + longitude * 180.0 / Math.PI + ")}";
+  }
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param point is the point to check.
+   * @return true if the point is within this shape
+   */
+  @Override
+  public boolean isWithin(final Vector point) {
+    return isWithin(point.x, point.y, point.z);
+  }
+
+  /**
+   * Check if a point is within this shape.
+   *
+   * @param x is x coordinate of point to check.
+   * @param y is y coordinate of point to check.
+   * @param z is z coordinate of point to check.
+   * @return true if the point is within this shape
+   */
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return x == this.x && y == this.y && z == this.z;
+  }
+
+  /**
+   * Returns the radius of a circle into which the GeoSizeable area can
+   * be inscribed.
+   *
+   * @return the radius.
+   */
+  @Override
+  public double getRadius() {
+    return 0.0;
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return this;
+  }
+
+  /**
+   * Find the spatial relationship between a shape and the current geo area.
+   * Note: return value is how the GeoShape relates to the GeoArea, not the
+   * other way around. For example, if this GeoArea is entirely within the
+   * shape, then CONTAINS should be returned.  If the shape is entirely enclosed
+   * by this GeoArea, then WITHIN should be returned.
+   *
+   * @param shape is the shape to consider.
+   * @return the relationship, from the perspective of the shape.
+   */
+  @Override
+  public int getRelationship(final GeoShape shape) {
+    if (shape.isWithin(this))
+      return CONTAINS;
 
-        return DISJOINT;
-    }
+    return DISJOINT;
+  }
 
 }
 

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=1677595&r1=1677594&r2=1677595&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 Mon May  4 13:19:02 2015
@@ -17,191 +17,188 @@ package org.apache.lucene.spatial.spatia
  * limitations under the License.
  */
 
-/** Degenerate bounding box limited on two sides (top lat, bottom lat).
-*/
-public class GeoDegenerateVerticalLine extends GeoBBoxBase
-{
-    public final double topLat;
-    public final double bottomLat;
-    public final double longitude;
-      
-    public final GeoPoint UHC;
-    public final GeoPoint LHC;
-    
-    public final SidedPlane topPlane;
-    public final SidedPlane bottomPlane;
-    public final SidedPlane boundingPlane;
-    public final Plane plane;
-
-    public final GeoPoint[] planePoints;
-    
-    public final GeoPoint centerPoint;
-    public final GeoPoint[] edgePoints;
-    
-    /** Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI} */
-    public GeoDegenerateVerticalLine(final double topLat, final double bottomLat, final double longitude)
-    {
-        // Argument checking
-        if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
-            throw new IllegalArgumentException("Top latitude out of range");
-        if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
-            throw new IllegalArgumentException("Bottom latitude out of range");
-        if (topLat < bottomLat)
-            throw new IllegalArgumentException("Top latitude less than bottom latitude");
-        if (longitude < -Math.PI || longitude > Math.PI)
-            throw new IllegalArgumentException("Longitude out of range");
-
-        this.topLat = topLat;
-        this.bottomLat = bottomLat;
-        this.longitude = longitude;
-          
-        final double sinTopLat = Math.sin(topLat);
-        final double cosTopLat = Math.cos(topLat);
-        final double sinBottomLat = Math.sin(bottomLat);
-        final double cosBottomLat = Math.cos(bottomLat);
-        final double sinLongitude = Math.sin(longitude);
-        final double cosLongitude = Math.cos(longitude);
-        
-        // Now build the two points
-        this.UHC = new GeoPoint(sinTopLat,sinLongitude,cosTopLat,cosLongitude);
-        this.LHC = new GeoPoint(sinBottomLat,sinLongitude,cosBottomLat,cosLongitude);
-        
-        this.plane = new Plane(cosLongitude,sinLongitude);
-          
-        final double middleLat = (topLat + bottomLat) * 0.5;
-        final double sinMiddleLat = Math.sin(middleLat);
-        final double cosMiddleLat = Math.cos(middleLat);
-          
-        this.centerPoint = new GeoPoint(sinMiddleLat,sinLongitude,cosMiddleLat,cosLongitude);
-
-        this.topPlane = new SidedPlane(centerPoint,sinTopLat);
-        this.bottomPlane = new SidedPlane(centerPoint,sinBottomLat);
-
-        this.boundingPlane = new SidedPlane(centerPoint,-sinLongitude,cosLongitude);
-
-        this.planePoints = new GeoPoint[]{UHC,LHC};
-
-        this.edgePoints = new GeoPoint[]{centerPoint};
-    }
-
-    @Override
-    public GeoBBox expand(final double angle)
-    {
-        final double newTopLat = topLat + angle;
-        final double newBottomLat = bottomLat - angle;
-        double newLeftLon = longitude - angle;
-        double newRightLon = longitude + angle;
-        double currentLonSpan = 2.0 * 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 plane.evaluateIsZero(point) &&
-          boundingPlane.isWithin(point) &&
-          topPlane.isWithin(point) &&
-          bottomPlane.isWithin(point);
-    }
-
-    @Override
-    public boolean isWithin(final double x, final double y, final double z)
-    {
-        return plane.evaluateIsZero(x,y,z) &&
-          boundingPlane.isWithin(x,y,z) &&
-          topPlane.isWithin(x,y,z) &&
-          bottomPlane.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 topAngle = centerPoint.arcDistance(UHC);
-        final double bottomAngle = centerPoint.arcDistance(LHC);
-        return Math.max(topAngle,bottomAngle);
-    }
-
-    /** Returns the center of a circle into which the area will be inscribed.
-    *@return the center.
-    */
-    @Override
-    public GeoPoint getCenter() {
-        return centerPoint;
-    }
-
-    @Override
-    public GeoPoint[] getEdgePoints()
-    {
-        return edgePoints;
-    }
-      
-    @Override
-    public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds)
-    {
-        return p.intersects(plane,notablePoints,planePoints,bounds,boundingPlane,topPlane,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.addLatitudeZone(topLat).addLatitudeZone(bottomLat)
-            .addLongitudeSlice(longitude,longitude);
-        return bounds;
-    }
-
-    @Override
-    public int getRelationship(final GeoShape path) {
-        //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)) {
-            //System.err.println(" contains");
-            return CONTAINS;
-        }
-
-        //System.err.println(" disjoint");
-        return DISJOINT;
-    }
-
-    @Override
-    public boolean equals(Object o)
-    {
-        if (!(o instanceof GeoDegenerateVerticalLine))
-            return false;
-        GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine)o;
-        return other.UHC.equals(UHC) && other.LHC.equals(LHC);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = UHC.hashCode();
-        result = 31 * result + LHC.hashCode();
-        return result;
-    }
-    
-    @Override
-    public String toString() {
-        return "GeoDegenerateVerticalLine: {longitude="+longitude+"("+longitude*180.0/Math.PI+"), toplat="+topLat+"("+topLat*180.0/Math.PI+"), bottomlat="+bottomLat+"("+bottomLat*180.0/Math.PI+")}";
-    }
+/**
+ * Degenerate bounding box limited on two sides (top lat, bottom lat).
+ */
+public class GeoDegenerateVerticalLine extends GeoBBoxBase {
+  public final double topLat;
+  public final double bottomLat;
+  public final double longitude;
+
+  public final GeoPoint UHC;
+  public final GeoPoint LHC;
+
+  public final SidedPlane topPlane;
+  public final SidedPlane bottomPlane;
+  public final SidedPlane boundingPlane;
+  public final Plane plane;
+
+  public final GeoPoint[] planePoints;
+
+  public final GeoPoint centerPoint;
+  public final GeoPoint[] edgePoints;
+
+  /**
+   * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, longitude: {@code -PI -> PI}
+   */
+  public GeoDegenerateVerticalLine(final double topLat, final double bottomLat, final double longitude) {
+    // Argument checking
+    if (topLat > Math.PI * 0.5 || topLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Top latitude out of range");
+    if (bottomLat > Math.PI * 0.5 || bottomLat < -Math.PI * 0.5)
+      throw new IllegalArgumentException("Bottom latitude out of range");
+    if (topLat < bottomLat)
+      throw new IllegalArgumentException("Top latitude less than bottom latitude");
+    if (longitude < -Math.PI || longitude > Math.PI)
+      throw new IllegalArgumentException("Longitude out of range");
+
+    this.topLat = topLat;
+    this.bottomLat = bottomLat;
+    this.longitude = longitude;
+
+    final double sinTopLat = Math.sin(topLat);
+    final double cosTopLat = Math.cos(topLat);
+    final double sinBottomLat = Math.sin(bottomLat);
+    final double cosBottomLat = Math.cos(bottomLat);
+    final double sinLongitude = Math.sin(longitude);
+    final double cosLongitude = Math.cos(longitude);
+
+    // Now build the two points
+    this.UHC = new GeoPoint(sinTopLat, sinLongitude, cosTopLat, cosLongitude);
+    this.LHC = new GeoPoint(sinBottomLat, sinLongitude, cosBottomLat, cosLongitude);
+
+    this.plane = new Plane(cosLongitude, sinLongitude);
+
+    final double middleLat = (topLat + bottomLat) * 0.5;
+    final double sinMiddleLat = Math.sin(middleLat);
+    final double cosMiddleLat = Math.cos(middleLat);
+
+    this.centerPoint = new GeoPoint(sinMiddleLat, sinLongitude, cosMiddleLat, cosLongitude);
+
+    this.topPlane = new SidedPlane(centerPoint, sinTopLat);
+    this.bottomPlane = new SidedPlane(centerPoint, sinBottomLat);
+
+    this.boundingPlane = new SidedPlane(centerPoint, -sinLongitude, cosLongitude);
+
+    this.planePoints = new GeoPoint[]{UHC, LHC};
+
+    this.edgePoints = new GeoPoint[]{centerPoint};
+  }
+
+  @Override
+  public GeoBBox expand(final double angle) {
+    final double newTopLat = topLat + angle;
+    final double newBottomLat = bottomLat - angle;
+    double newLeftLon = longitude - angle;
+    double newRightLon = longitude + angle;
+    double currentLonSpan = 2.0 * 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 plane.evaluateIsZero(point) &&
+        boundingPlane.isWithin(point) &&
+        topPlane.isWithin(point) &&
+        bottomPlane.isWithin(point);
+  }
+
+  @Override
+  public boolean isWithin(final double x, final double y, final double z) {
+    return plane.evaluateIsZero(x, y, z) &&
+        boundingPlane.isWithin(x, y, z) &&
+        topPlane.isWithin(x, y, z) &&
+        bottomPlane.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 topAngle = centerPoint.arcDistance(UHC);
+    final double bottomAngle = centerPoint.arcDistance(LHC);
+    return Math.max(topAngle, bottomAngle);
+  }
+
+  /**
+   * Returns the center of a circle into which the area will be inscribed.
+   *
+   * @return the center.
+   */
+  @Override
+  public GeoPoint getCenter() {
+    return centerPoint;
+  }
+
+  @Override
+  public GeoPoint[] getEdgePoints() {
+    return edgePoints;
+  }
+
+  @Override
+  public boolean intersects(final Plane p, final GeoPoint[] notablePoints, final Membership... bounds) {
+    return p.intersects(plane, notablePoints, planePoints, bounds, boundingPlane, topPlane, 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.addLatitudeZone(topLat).addLatitudeZone(bottomLat)
+        .addLongitudeSlice(longitude, longitude);
+    return bounds;
+  }
+
+  @Override
+  public int getRelationship(final GeoShape path) {
+    //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)) {
+      //System.err.println(" contains");
+      return CONTAINS;
+    }
+
+    //System.err.println(" disjoint");
+    return DISJOINT;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof GeoDegenerateVerticalLine))
+      return false;
+    GeoDegenerateVerticalLine other = (GeoDegenerateVerticalLine) o;
+    return other.UHC.equals(UHC) && other.LHC.equals(LHC);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = UHC.hashCode();
+    result = 31 * result + LHC.hashCode();
+    return result;
+  }
+
+  @Override
+  public String toString() {
+    return "GeoDegenerateVerticalLine: {longitude=" + longitude + "(" + longitude * 180.0 / Math.PI + "), toplat=" + topLat + "(" + topLat * 180.0 / Math.PI + "), bottomlat=" + bottomLat + "(" + bottomLat * 180.0 / Math.PI + ")}";
+  }
 }