You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by iv...@apache.org on 2020/02/07 18:31:14 UTC

[lucene-solr] branch branch_8x updated: UCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry

This is an automated email from the ASF dual-hosted git repository.

ivera pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new 5c1f2ca  UCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry
5c1f2ca is described below

commit 5c1f2ca22a756b16f0e35aa5dde221578fe1ce76
Author: Ignacio Vera <iv...@apache.org>
AuthorDate: Fri Feb 7 19:29:13 2020 +0100

    UCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry
---
 lucene/CHANGES.txt                                 |   3 +
 .../LatLonDocValuesPointInPolygonQuery.java        |   4 +-
 .../lucene/document/LatLonPointInPolygonQuery.java |   4 +-
 .../java/org/apache/lucene/document/XYShape.java   |  47 +++----
 .../lucene/document/XYShapeBoundingBoxQuery.java   | 142 --------------------
 .../apache/lucene/document/XYShapeLineQuery.java   | 146 ---------------------
 .../apache/lucene/document/XYShapePointQuery.java  | 126 ------------------
 ...{XYShapePolygonQuery.java => XYShapeQuery.java} |  57 ++++----
 .../java/org/apache/lucene/geo/ComponentTree.java  |  16 +--
 .../src/java/org/apache/lucene/geo/EdgeTree.java   |  72 +++++-----
 .../src/java/org/apache/lucene/geo/Line2D.java     |  31 ++---
 .../core/src/java/org/apache/lucene/geo/Point.java |   4 +-
 .../src/java/org/apache/lucene/geo/Point2D.java    |  28 ++--
 .../src/java/org/apache/lucene/geo/Polygon2D.java  |  49 ++++---
 .../src/java/org/apache/lucene/geo/XYGeometry.java |  51 +++++++
 .../src/java/org/apache/lucene/geo/XYLine.java     |  30 +++--
 .../apache/lucene/geo/{Point.java => XYPoint.java} |  40 +++---
 .../src/java/org/apache/lucene/geo/XYPolygon.java  |  34 ++---
 .../java/org/apache/lucene/geo/XYPolygon2D.java    |  44 -------
 .../java/org/apache/lucene/geo/XYRectangle.java    |   7 +-
 .../java/org/apache/lucene/geo/XYRectangle2D.java  |  22 ++--
 .../lucene/document/BaseLatLonShapeTestCase.java   |  16 ++-
 .../lucene/document/BaseXYShapeTestCase.java       |  16 ++-
 .../apache/lucene/document/TestLatLonShape.java    |  13 +-
 .../lucene/document/TestLatLonShapeEncoding.java   |   4 +-
 .../lucene/document/TestXYLineShapeQueries.java    |   4 +-
 .../document/TestXYMultiLineShapeQueries.java      |   4 +-
 .../document/TestXYMultiPointShapeQueries.java     |   4 +-
 .../document/TestXYMultiPolygonShapeQueries.java   |   4 +-
 .../lucene/document/TestXYPointShapeQueries.java   |   4 +-
 .../lucene/document/TestXYPolygonShapeQueries.java |   4 +-
 .../lucene/document/TestXYShapeEncoding.java       |   4 +-
 .../test/org/apache/lucene/geo/TestPoint2D.java    |   8 +-
 .../test/org/apache/lucene/geo/TestPolygon2D.java  |   2 +-
 34 files changed, 309 insertions(+), 735 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index e8c614e..d359035 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -61,6 +61,9 @@ Improvements
 * LUCENE-9123: Add new JapaneseTokenizer constructors with discardCompoundToken option that controls whether
   the tokenizer emits original (compound) tokens when the mode is not NORMAL. (Kazuaki Hiraga via Tomoko Uchida)
 
+* LUCENE-9194: Simplify XYShapeXQuery API by adding a new abstract class called XYGeometry. Queries are
+  executed with input objects that extend such interface. (Ignacio Vera)
+
 Optimizations
 ---------------------
 
diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesPointInPolygonQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesPointInPolygonQuery.java
index 525b77e..abf1c88 100644
--- a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesPointInPolygonQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesPointInPolygonQuery.java
@@ -22,8 +22,8 @@ import java.util.Arrays;
 
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.GeoEncodingUtils;
+import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.Polygon2D;
 import org.apache.lucene.index.DocValues;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.index.SortedNumericDocValues;
@@ -104,7 +104,7 @@ public class LatLonDocValuesPointInPolygonQuery extends Query {
 
     return new ConstantScoreWeight(this, boost) {
 
-      final Component2D tree = Polygon2D.create(polygons);
+      final Component2D tree = LatLonGeometry.create(polygons);
       final GeoEncodingUtils.PolygonPredicate polygonPredicate = GeoEncodingUtils.createComponentPredicate(tree);
 
       @Override
diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
index 82212ae..b823ca6 100644
--- a/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java
@@ -21,8 +21,8 @@ import java.util.Arrays;
 
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.GeoEncodingUtils;
+import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.Polygon2D;
 import org.apache.lucene.index.FieldInfo;
 import org.apache.lucene.index.LeafReader;
 import org.apache.lucene.index.LeafReaderContext;
@@ -142,7 +142,7 @@ final class LatLonPointInPolygonQuery extends Query {
   @Override
   public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException {
 
-    final Component2D tree = Polygon2D.create(polygons);
+    final Component2D tree = LatLonGeometry.create(polygons);
     final GeoEncodingUtils.PolygonPredicate polygonPredicate = GeoEncodingUtils.createComponentPredicate(tree);
     // bounding box over all polygons, this can speed up tree intersection/cheaply improve approximation for complex multi-polygons
     final byte minLat[] = new byte[Integer.BYTES];
diff --git a/lucene/core/src/java/org/apache/lucene/document/XYShape.java b/lucene/core/src/java/org/apache/lucene/document/XYShape.java
index 387d048..88f9a5d 100644
--- a/lucene/core/src/java/org/apache/lucene/document/XYShape.java
+++ b/lucene/core/src/java/org/apache/lucene/document/XYShape.java
@@ -22,6 +22,9 @@ import java.util.List;
 import org.apache.lucene.document.ShapeField.QueryRelation; // javadoc
 import org.apache.lucene.document.ShapeField.Triangle;
 import org.apache.lucene.geo.Tessellator;
+import org.apache.lucene.geo.XYGeometry;
+import org.apache.lucene.geo.XYPoint;
+import org.apache.lucene.geo.XYRectangle;
 import org.apache.lucene.index.PointValues; // javadoc
 import org.apache.lucene.geo.XYLine;
 import org.apache.lucene.geo.XYPolygon;
@@ -34,7 +37,7 @@ import static org.apache.lucene.geo.XYEncodingUtils.encode;
 /**
  * A cartesian shape utility class for indexing and searching geometries whose vertices are unitless x, y values.
  * <p>
- * This class defines six static factory methods for common indexing and search operations:
+ * This class defines seven static factory methods for common indexing and search operations:
  * <ul>
  *   <li>{@link #createIndexableFields(String, XYPolygon)} for indexing a cartesian polygon.
  *   <li>{@link #createIndexableFields(String, XYLine)} for indexing a cartesian linestring.
@@ -42,6 +45,8 @@ import static org.apache.lucene.geo.XYEncodingUtils.encode;
  *   <li>{@link #newBoxQuery newBoxQuery()} for matching cartesian shapes that have some {@link QueryRelation} with a bounding box.
  *   <li>{@link #newBoxQuery newLineQuery()} for matching cartesian shapes that have some {@link QueryRelation} with a linestring.
  *   <li>{@link #newBoxQuery newPolygonQuery()} for matching cartesian shapes that have some {@link QueryRelation} with a polygon.
+ *   <li>{@link #newGeometryQuery newGeometryQuery()} for matching cartesian shapes that have some {@link QueryRelation}
+ *   with one or more {@link XYGeometry}.
  * </ul>
 
  * <b>WARNING</b>: Like {@link LatLonPoint}, vertex values are indexed with some loss of precision from the
@@ -88,43 +93,41 @@ public class XYShape {
 
   /** create a query to find all cartesian shapes that intersect a defined bounding box **/
   public static Query newBoxQuery(String field, QueryRelation queryRelation, float minX, float maxX, float minY, float maxY) {
-    return new XYShapeBoundingBoxQuery(field, queryRelation, minX, maxX, minY, maxY);
+    XYRectangle rectangle = new XYRectangle(minX, maxX, minY, maxY);
+    return newGeometryQuery(field, queryRelation, rectangle);
   }
 
   /** create a query to find all cartesian shapes that intersect a provided linestring (or array of linestrings) **/
   public static Query newLineQuery(String field, QueryRelation queryRelation, XYLine... lines) {
-    if (queryRelation == QueryRelation.CONTAINS && lines.length > 1) {
-      BooleanQuery.Builder builder = new BooleanQuery.Builder();
-      for (int i =0; i < lines.length; i++) {
-        builder.add(newLineQuery(field, queryRelation, lines[i]), BooleanClause.Occur.MUST);
-      }
-      return builder.build();
-    }
-    return new XYShapeLineQuery(field, queryRelation, lines);
+    return newGeometryQuery(field, queryRelation, lines);
   }
 
   /** create a query to find all cartesian shapes that intersect a provided polygon (or array of polygons) **/
   public static Query newPolygonQuery(String field, QueryRelation queryRelation, XYPolygon... polygons) {
-    if (queryRelation == QueryRelation.CONTAINS && polygons.length > 1) {
-      BooleanQuery.Builder builder = new BooleanQuery.Builder();
-      for (int i =0; i < polygons.length; i++) {
-        builder.add(newPolygonQuery(field, queryRelation, polygons[i]), BooleanClause.Occur.MUST);
-      }
-      return builder.build();
-    }
-    return new XYShapePolygonQuery(field, queryRelation, polygons);
+    return newGeometryQuery(field, queryRelation, polygons);
   }
 
   /** create a query to find all indexed shapes that comply the {@link QueryRelation} with the provided point
    **/
   public static Query newPointQuery(String field, QueryRelation queryRelation, float[]... points) {
-    if (queryRelation == QueryRelation.CONTAINS && points.length > 1) {
+    XYPoint[] pointArray = new XYPoint[points.length];
+    for (int i =0; i < points.length; i++) {
+      pointArray[i] = new XYPoint(points[i][0], points[i][1]);
+    }
+    return newGeometryQuery(field, queryRelation, pointArray);
+  }
+
+  /** create a query to find all indexed geo shapes that intersect a provided geometry collection
+   *  note: Components do not support dateline crossing
+   **/
+  public static Query newGeometryQuery(String field, QueryRelation queryRelation, XYGeometry... xyGeometries) {
+    if (queryRelation == QueryRelation.CONTAINS && xyGeometries.length > 1) {
       BooleanQuery.Builder builder = new BooleanQuery.Builder();
-      for (int i =0; i < points.length; i++) {
-        builder.add(newPointQuery(field, queryRelation, points[i]), BooleanClause.Occur.MUST);
+      for (int i = 0; i < xyGeometries.length; i++) {
+        builder.add(newGeometryQuery(field, queryRelation, xyGeometries[i]), BooleanClause.Occur.MUST);
       }
       return builder.build();
     }
-    return new XYShapePointQuery(field, queryRelation, points);
+    return new XYShapeQuery(field, queryRelation, xyGeometries);
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/document/XYShapeBoundingBoxQuery.java b/lucene/core/src/java/org/apache/lucene/document/XYShapeBoundingBoxQuery.java
deleted file mode 100644
index 7f977b9..0000000
--- a/lucene/core/src/java/org/apache/lucene/document/XYShapeBoundingBoxQuery.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.document;
-
-import org.apache.lucene.document.ShapeField.QueryRelation;
-import org.apache.lucene.geo.Component2D;
-import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
-import org.apache.lucene.index.PointValues.Relation;
-import org.apache.lucene.util.NumericUtils;
-
-import static org.apache.lucene.geo.XYEncodingUtils.decode;
-
-/**
- * Finds all previously indexed cartesian shapes that intersect the specified bounding box.
- *
- * <p>The field must be indexed using
- * {@link org.apache.lucene.document.XYShape#createIndexableFields} added per document.
- **/
-public class XYShapeBoundingBoxQuery extends ShapeQuery {
-  final Component2D rectangle2D;
-  final private XYRectangle rectangle;
-
-  /** construct a Bounding Box Query over cartesian geometries from the given ranges */
-  public XYShapeBoundingBoxQuery(String field, QueryRelation queryRelation, double minX, double maxX, double minY, double maxY) {
-    super(field, queryRelation);
-    this.rectangle = new XYRectangle(minX, maxX, minY, maxY);
-    this.rectangle2D = XYRectangle2D.create(this.rectangle);
-  }
-
-  @Override
-  protected Relation relateRangeBBoxToQuery(int minXOffset, int minYOffset, byte[] minTriangle,
-                                                        int maxXOffset, int maxYOffset, byte[] maxTriangle) {
-    double minY = decode(NumericUtils.sortableBytesToInt(minTriangle, minYOffset));
-    double minX = decode(NumericUtils.sortableBytesToInt(minTriangle, minXOffset));
-    double maxY = decode(NumericUtils.sortableBytesToInt(maxTriangle, maxYOffset));
-    double maxX = decode(NumericUtils.sortableBytesToInt(maxTriangle, maxXOffset));
-    // check internal node against query
-    Relation rel = rectangle2D.relate(minX, maxX, minY, maxY);
-    // TODO: Check if this really helps
-    if (queryRelation == QueryRelation.INTERSECTS && rel == Relation.CELL_CROSSES_QUERY) {
-      // for intersects we can restrict the conditions by using the inner box
-      double innerMaxY = decode(NumericUtils.sortableBytesToInt(maxTriangle, minYOffset));
-      if (rectangle2D.relate(minX, maxX, minY, innerMaxY) == Relation.CELL_INSIDE_QUERY) {
-        return Relation.CELL_INSIDE_QUERY;
-      }
-      double innerMaX = decode(NumericUtils.sortableBytesToInt(maxTriangle, minXOffset));
-      if (rectangle2D.relate(minX, innerMaX, minY, maxY) == Relation.CELL_INSIDE_QUERY) {
-        return Relation.CELL_INSIDE_QUERY;
-      }
-      double innerMinY = decode(NumericUtils.sortableBytesToInt(minTriangle, maxYOffset));
-      if (rectangle2D.relate(minX, maxX, innerMinY, maxY) == Relation.CELL_INSIDE_QUERY) {
-        return Relation.CELL_INSIDE_QUERY;
-      }
-      double innerMinX = decode(NumericUtils.sortableBytesToInt(minTriangle, maxXOffset));
-      if (rectangle2D.relate(innerMinX, maxX, minY, maxY) == Relation.CELL_INSIDE_QUERY) {
-        return Relation.CELL_INSIDE_QUERY;
-      }
-    }
-    return rel;
-  }
-
-  /** returns true if the query matches the encoded triangle */
-  @Override
-  protected boolean queryMatches(byte[] t, ShapeField.DecodedTriangle scratchTriangle, QueryRelation queryRelation) {
-    // decode indexed triangle
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double aY = decode(scratchTriangle.aY);
-    double aX = decode(scratchTriangle.aX);
-    double bY = decode(scratchTriangle.bY);
-    double bX = decode(scratchTriangle.bX);
-    double cY = decode(scratchTriangle.cY);
-    double cX = decode(scratchTriangle.cX);
-
-    switch (queryRelation) {
-      case INTERSECTS: return rectangle2D.relateTriangle(aX, aY, bX, bY, cX, cY) != Relation.CELL_OUTSIDE_QUERY;
-      case WITHIN: return rectangle2D.contains(aX, aY) && rectangle2D.contains(bX, bY) && rectangle2D.contains(cX, cY);
-      case DISJOINT: return rectangle2D.relateTriangle(aX, aY, bX, bY, cX, cY) == Relation.CELL_OUTSIDE_QUERY;
-      default: throw new IllegalArgumentException("Unsupported query type :[" + queryRelation + "]");
-    }
-  }
-
-  @Override
-  protected Component2D.WithinRelation queryWithin(byte[] t, ShapeField.DecodedTriangle scratchTriangle) {
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double aY = decode(scratchTriangle.aY);
-    double aX = decode(scratchTriangle.aX);
-    double bY = decode(scratchTriangle.bY);
-    double bX = decode(scratchTriangle.bX);
-    double cY = decode(scratchTriangle.cY);
-    double cX = decode(scratchTriangle.cX);
-
-    return rectangle2D.withinTriangle(aX, aY, scratchTriangle.ab, bX, bY, scratchTriangle.bc, cX, cY, scratchTriangle.ca);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return sameClassAs(o) && equalsTo(getClass().cast(o));
-  }
-
-  @Override
-  protected boolean equalsTo(Object o) {
-    return super.equalsTo(o) && rectangle.equals(((XYShapeBoundingBoxQuery)o).rectangle);
-  }
-
-  @Override
-  public int hashCode() {
-    int hash = super.hashCode();
-    hash = 31 * hash + rectangle.hashCode();
-    return hash;
-  }
-
-  @Override
-  public String toString(String field) {
-    final StringBuilder sb = new StringBuilder();
-    sb.append(getClass().getSimpleName());
-    sb.append(':');
-    if (this.field.equals(field) == false) {
-      sb.append(" field=");
-      sb.append(this.field);
-      sb.append(':');
-    }
-    sb.append(rectangle.toString());
-    return sb.toString();
-  }
-}
\ No newline at end of file
diff --git a/lucene/core/src/java/org/apache/lucene/document/XYShapeLineQuery.java b/lucene/core/src/java/org/apache/lucene/document/XYShapeLineQuery.java
deleted file mode 100644
index 1a61bdd..0000000
--- a/lucene/core/src/java/org/apache/lucene/document/XYShapeLineQuery.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.document;
-
-import java.util.Arrays;
-
-import org.apache.lucene.document.ShapeField.QueryRelation;
-import org.apache.lucene.geo.Component2D;
-import org.apache.lucene.geo.Line2D;
-import org.apache.lucene.geo.XYLine;
-import org.apache.lucene.index.PointValues.Relation;
-import org.apache.lucene.util.NumericUtils;
-
-import static org.apache.lucene.geo.XYEncodingUtils.decode;
-
-/**
- * Finds all previously indexed cartesian shapes that intersect the specified arbitrary {@code XYLine}.
- * <p>
- * Note:
- * <ul>
- *    <li>{@code QueryRelation.WITHIN} queries are not yet supported</li>
- * </ul>
- * <p>
- * todo:
- * <ul>
- *   <li>Add distance support for buffered queries</li>
- * </ul>
- * <p>The field must be indexed using
- * {@link org.apache.lucene.document.XYShape#createIndexableFields} added per document.
- **/
-final class XYShapeLineQuery extends ShapeQuery {
-  final XYLine[] lines;
-  final private Component2D line2D;
-
-  /** construct a Line Query over cartesian geometries from the given line objects */
-  public XYShapeLineQuery(String field, QueryRelation queryRelation, XYLine... lines) {
-    super(field, queryRelation);
-    /** line queries do not support within relations, only intersects and disjoint */
-    if (queryRelation == QueryRelation.WITHIN) {
-      throw new IllegalArgumentException("XYShapeLineQuery does not support " + QueryRelation.WITHIN + " queries");
-    }
-
-    if (lines == null) {
-      throw new IllegalArgumentException("lines must not be null");
-    }
-    if (lines.length == 0) {
-      throw new IllegalArgumentException("lines must not be empty");
-    }
-    for (int i = 0; i < lines.length; ++i) {
-      if (lines[i] == null) {
-        throw new IllegalArgumentException("line[" + i + "] must not be null");
-      } else if (lines[i].minX > lines[i].maxX) {
-        throw new IllegalArgumentException("XYShapeLineQuery: minX cannot be greater than maxX.");
-      } else if (lines[i].minY > lines[i].maxY) {
-        throw new IllegalArgumentException("XYShapeLineQuery: minY cannot be greater than maxY.");
-      }
-    }
-    this.lines = lines.clone();
-    this.line2D = Line2D.create(lines);
-  }
-
-  @Override
-  protected Relation relateRangeBBoxToQuery(int minXOffset, int minYOffset, byte[] minTriangle,
-                                            int maxXOffset, int maxYOffset, byte[] maxTriangle) {
-    double minY = decode(NumericUtils.sortableBytesToInt(minTriangle, minYOffset));
-    double minX = decode(NumericUtils.sortableBytesToInt(minTriangle, minXOffset));
-    double maxY = decode(NumericUtils.sortableBytesToInt(maxTriangle, maxYOffset));
-    double maxX = decode(NumericUtils.sortableBytesToInt(maxTriangle, maxXOffset));
-
-    // check internal node against query
-    return line2D.relate(minX, maxX, minY, maxY);
-  }
-
-  @Override
-  protected boolean queryMatches(byte[] t, ShapeField.DecodedTriangle scratchTriangle, QueryRelation queryRelation) {
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double alat = decode(scratchTriangle.aY);
-    double alon = decode(scratchTriangle.aX);
-    double blat = decode(scratchTriangle.bY);
-    double blon = decode(scratchTriangle.bX);
-    double clat = decode(scratchTriangle.cY);
-    double clon = decode(scratchTriangle.cX);
-
-    switch (queryRelation) {
-      case INTERSECTS: return line2D.relateTriangle(alon, alat, blon, blat, clon, clat) != Relation.CELL_OUTSIDE_QUERY;
-      case WITHIN: return line2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_INSIDE_QUERY;
-      case DISJOINT: return line2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_OUTSIDE_QUERY;
-      default: throw new IllegalArgumentException("Unsupported query type :[" + queryRelation + "]");
-    }
-  }
-
-  @Override
-  protected Component2D.WithinRelation queryWithin(byte[] t, ShapeField.DecodedTriangle scratchTriangle) {
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double alat = decode(scratchTriangle.aY);
-    double alon = decode(scratchTriangle.aX);
-    double blat = decode(scratchTriangle.bY);
-    double blon = decode(scratchTriangle.bX);
-    double clat = decode(scratchTriangle.cY);
-    double clon = decode(scratchTriangle.cX);
-
-    return line2D.withinTriangle(alon, alat, scratchTriangle.ab, blon, blat, scratchTriangle.bc, clon, clat, scratchTriangle.ca);
-  }
-
-  @Override
-  public String toString(String field) {
-    final StringBuilder sb = new StringBuilder();
-    sb.append(getClass().getSimpleName());
-    sb.append(':');
-    if (this.field.equals(field) == false) {
-      sb.append(" field=");
-      sb.append(this.field);
-      sb.append(':');
-    }
-    sb.append("XYLine(").append(lines[0].toGeoJSON()).append(")");
-    return sb.toString();
-  }
-
-  @Override
-  protected boolean equalsTo(Object o) {
-    return super.equalsTo(o) && Arrays.equals(lines, ((XYShapeLineQuery)o).lines);
-  }
-
-  @Override
-  public int hashCode() {
-    int hash = super.hashCode();
-    hash = 31 * hash + Arrays.hashCode(lines);
-    return hash;
-  }
-}
diff --git a/lucene/core/src/java/org/apache/lucene/document/XYShapePointQuery.java b/lucene/core/src/java/org/apache/lucene/document/XYShapePointQuery.java
deleted file mode 100644
index dee7869..0000000
--- a/lucene/core/src/java/org/apache/lucene/document/XYShapePointQuery.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.document;
-
-import java.util.Arrays;
-
-import org.apache.lucene.geo.Component2D;
-import org.apache.lucene.geo.Point2D;
-import org.apache.lucene.geo.XYEncodingUtils;
-import org.apache.lucene.index.PointValues.Relation;
-import org.apache.lucene.util.NumericUtils;
-
-import static org.apache.lucene.geo.XYEncodingUtils.decode;
-
-/**
- * Finds all previously indexed shapes that intersect the specified bounding box.
- *
- * <p>The field must be indexed using
- * {@link XYShape#createIndexableFields} added per document.
- **/
-final class XYShapePointQuery extends ShapeQuery {
-  final Component2D point2D;
-  final float[][] points;
-
-  /** construct a Point or MultiPoint Query over cartesian geometries from the given point values */
-  public XYShapePointQuery(String field, ShapeField.QueryRelation queryRelation, float[][] points) {
-    super(field, queryRelation);
-    this.points = points;
-    this.point2D = Point2D.create(points);
-  }
-
-  @Override
-  protected Relation relateRangeBBoxToQuery(int minXOffset, int minYOffset, byte[] minTriangle,
-                                            int maxXOffset, int maxYOffset, byte[] maxTriangle) {
-    double minY = XYEncodingUtils.decode(NumericUtils.sortableBytesToInt(minTriangle, minYOffset));
-    double minX = XYEncodingUtils.decode(NumericUtils.sortableBytesToInt(minTriangle, minXOffset));
-    double maxY = XYEncodingUtils.decode(NumericUtils.sortableBytesToInt(maxTriangle, maxYOffset));
-    double maxX = XYEncodingUtils.decode(NumericUtils.sortableBytesToInt(maxTriangle, maxXOffset));
-
-    // check internal node against query
-    return point2D.relate(minX, maxX, minY, maxY);
-  }
-
-  /** returns true if the query matches the encoded triangle */
-  @Override
-  protected boolean queryMatches(byte[] t, ShapeField.DecodedTriangle scratchTriangle, ShapeField.QueryRelation queryRelation) {
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double aY = decode(scratchTriangle.aY);
-    double aX = decode(scratchTriangle.aX);
-    double bY = decode(scratchTriangle.bY);
-    double bX = decode(scratchTriangle.bX);
-    double cY = decode(scratchTriangle.cY);
-    double cX = decode(scratchTriangle.cX);
-
-    switch (queryRelation) {
-      case INTERSECTS:
-        return point2D.relateTriangle(aX, aY, bX, bY, cX, cY) != Relation.CELL_OUTSIDE_QUERY;
-      case WITHIN:
-        return point2D.relateTriangle(aX, aY, bX, bY, cX, cY) == Relation.CELL_INSIDE_QUERY;
-      case DISJOINT:
-        return point2D.relateTriangle(aX, aY, bX, bY, cX, cY) == Relation.CELL_OUTSIDE_QUERY;
-      default:
-        throw new IllegalArgumentException("Unsupported query type :[" + queryRelation + "]");
-    }
-  }
-
-  @Override
-  protected Component2D.WithinRelation queryWithin(byte[] t, ShapeField.DecodedTriangle scratchTriangle) {
-    ShapeField.decodeTriangle(t, scratchTriangle);
-
-    double aY = decode(scratchTriangle.aY);
-    double aX = decode(scratchTriangle.aX);
-    double bY = decode(scratchTriangle.bY);
-    double bX = decode(scratchTriangle.bX);
-    double cY = decode(scratchTriangle.cY);
-    double cX = decode(scratchTriangle.cX);
-
-    return point2D.withinTriangle(aX, aY, scratchTriangle.ab, bX, bY, scratchTriangle.bc, cX, cY, scratchTriangle.ca);
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return sameClassAs(o) && equalsTo(getClass().cast(o));
-  }
-
-  @Override
-  protected boolean equalsTo(Object o) {
-    return super.equalsTo(o) && Arrays.equals(points, ((XYShapePointQuery)o).points);
-  }
-
-  @Override
-  public int hashCode() {
-    int hash = super.hashCode();
-    hash = 31 * hash + Arrays.hashCode(points);
-    return hash;
-  }
-
-  @Override
-  public String toString(String field) {
-    final StringBuilder sb = new StringBuilder();
-    sb.append(getClass().getSimpleName());
-    sb.append(':');
-    if (this.field.equals(field) == false) {
-      sb.append(" field=");
-      sb.append(this.field);
-      sb.append(':');
-    }
-    sb.append("lat = " + points[0][0] + " , lon = " + points[0][1]);
-    return sb.toString();
-  }
-}
diff --git a/lucene/core/src/java/org/apache/lucene/document/XYShapePolygonQuery.java b/lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java
similarity index 62%
rename from lucene/core/src/java/org/apache/lucene/document/XYShapePolygonQuery.java
rename to lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java
index 11639c0..98be784 100644
--- a/lucene/core/src/java/org/apache/lucene/document/XYShapePolygonQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/XYShapeQuery.java
@@ -21,45 +21,29 @@ import java.util.Arrays;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.XYEncodingUtils;
-import org.apache.lucene.geo.XYPolygon;
-import org.apache.lucene.geo.XYPolygon2D;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.index.PointValues.Relation;
 import org.apache.lucene.util.NumericUtils;
 
 import static org.apache.lucene.geo.XYEncodingUtils.decode;
 
 /**
- * Finds all previously indexed cartesian shapes that intersect the specified arbitrary cartesian {@link XYPolygon}.
+ * Finds all previously indexed cartesian shapes that comply the given {@link QueryRelation} with
+ * the specified array of {@link XYGeometry}.
  *
- * <p>The field must be indexed using
- * {@link org.apache.lucene.document.XYShape#createIndexableFields} added per document.
+ * <p>The field must be indexed using {@link XYShape#createIndexableFields} added per document.
  **/
-final class XYShapePolygonQuery extends ShapeQuery {
-  final XYPolygon[] polygons;
-  final private Component2D poly2D;
+final class XYShapeQuery extends ShapeQuery {
+  final XYGeometry[] geometries;
+  final private Component2D component2D;
 
   /**
    * Creates a query that matches all indexed shapes to the provided polygons
    */
-  public XYShapePolygonQuery(String field, QueryRelation queryRelation, XYPolygon... polygons) {
+  XYShapeQuery(String field, QueryRelation queryRelation, XYGeometry... geometries) {
     super(field, queryRelation);
-    if (polygons == null) {
-      throw new IllegalArgumentException("polygons must not be null");
-    }
-    if (polygons.length == 0) {
-      throw new IllegalArgumentException("polygons must not be empty");
-    }
-    for (int i = 0; i < polygons.length; i++) {
-      if (polygons[i] == null) {
-        throw new IllegalArgumentException("polygon[" + i + "] must not be null");
-      } else if (polygons[i].minX > polygons[i].maxX) {
-        throw new IllegalArgumentException("XYShapePolygonQuery: minX cannot be greater than maxX.");
-      } else if (polygons[i].minY > polygons[i].maxY) {
-        throw new IllegalArgumentException("XYShapePolygonQuery: minY cannot be greater than maxY.");
-      }
-    }
-    this.polygons = polygons.clone();
-    this.poly2D = XYPolygon2D.create(polygons);
+    this.component2D = XYGeometry.create(geometries);
+    this.geometries = geometries.clone();
   }
 
   @Override
@@ -72,7 +56,7 @@ final class XYShapePolygonQuery extends ShapeQuery {
     double maxLon = XYEncodingUtils.decode(NumericUtils.sortableBytesToInt(maxTriangle, maxXOffset));
 
     // check internal node against query
-    return poly2D.relate(minLon, maxLon, minLat, maxLat);
+    return component2D.relate(minLon, maxLon, minLat, maxLat);
   }
 
   @Override
@@ -87,9 +71,9 @@ final class XYShapePolygonQuery extends ShapeQuery {
     double clon = decode(scratchTriangle.cX);
 
     switch (queryRelation) {
-      case INTERSECTS: return poly2D.relateTriangle(alon, alat, blon, blat, clon, clat) != Relation.CELL_OUTSIDE_QUERY;
-      case WITHIN: return poly2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_INSIDE_QUERY;
-      case DISJOINT: return poly2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_OUTSIDE_QUERY;
+      case INTERSECTS: return component2D.relateTriangle(alon, alat, blon, blat, clon, clat) != Relation.CELL_OUTSIDE_QUERY;
+      case WITHIN: return component2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_INSIDE_QUERY;
+      case DISJOINT: return component2D.relateTriangle(alon, alat, blon, blat, clon, clat) == Relation.CELL_OUTSIDE_QUERY;
       default: throw new IllegalArgumentException("Unsupported query type :[" + queryRelation + "]");
     }
   }
@@ -105,7 +89,7 @@ final class XYShapePolygonQuery extends ShapeQuery {
     double clat = decode(scratchTriangle.cY);
     double clon = decode(scratchTriangle.cX);
 
-    return poly2D.withinTriangle(alon, alat, scratchTriangle.ab, blon, blat, scratchTriangle.bc, clon, clat, scratchTriangle.ca);
+    return component2D.withinTriangle(alon, alat, scratchTriangle.ab, blon, blat, scratchTriangle.bc, clon, clat, scratchTriangle.ca);
   }
 
   @Override
@@ -118,19 +102,24 @@ final class XYShapePolygonQuery extends ShapeQuery {
       sb.append(this.field);
       sb.append(':');
     }
-    sb.append("XYPolygon(").append(polygons[0].toGeoJSON()).append(")");
+    sb.append("[");
+    for (int i = 0; i < geometries.length; i++) {
+      sb.append(geometries[i].toString());
+      sb.append(',');
+    }
+    sb.append(']');
     return sb.toString();
   }
 
   @Override
   protected boolean equalsTo(Object o) {
-    return super.equalsTo(o) && Arrays.equals(polygons, ((XYShapePolygonQuery)o).polygons);
+    return super.equalsTo(o) && Arrays.equals(geometries, ((XYShapeQuery)o).geometries);
   }
 
   @Override
   public int hashCode() {
     int hash = super.hashCode();
-    hash = 31 * hash + Arrays.hashCode(polygons);
+    hash = 31 * hash + Arrays.hashCode(geometries);
     return hash;
   }
 }
\ No newline at end of file
diff --git a/lucene/core/src/java/org/apache/lucene/geo/ComponentTree.java b/lucene/core/src/java/org/apache/lucene/geo/ComponentTree.java
index 8a2b5f3..c09bcdf 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/ComponentTree.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/ComponentTree.java
@@ -25,17 +25,15 @@ import org.apache.lucene.util.ArrayUtil;
  * 2D multi-component geometry implementation represented as an interval tree of components.
  * <p>
  * Construction takes {@code O(n log n)} time for sorting and tree construction.
- *
- * @lucene.internal
  */
 final class ComponentTree implements Component2D {
-  /** minimum latitude of this geometry's bounding box area */
+  /** minimum Y of this geometry's bounding box area */
   private double minY;
-  /** maximum latitude of this geometry's bounding box area */
+  /** maximum Y of this geometry's bounding box area */
   private double maxY;
-  /** minimum longitude of this geometry's bounding box area */
+  /** minimum X of this geometry's bounding box area */
   private double minX;
-  /** maximum longitude of this geometry's bounding box area */
+  /** maximum X of this geometry's bounding box area */
   private double maxX;
   // child components, or null. Note internal nodes might mot have
   // a consistent bounding box. Internal nodes should not be accessed
@@ -48,7 +46,7 @@ final class ComponentTree implements Component2D {
   /** root node of edge tree */
   final private Component2D component;
 
-  protected ComponentTree(Component2D component, boolean splitX) {
+  private ComponentTree(Component2D component, boolean splitX) {
     this.minY = component.getMinY();
     this.maxY = component.getMaxY();
     this.minX = component.getMinX();
@@ -97,7 +95,6 @@ final class ComponentTree implements Component2D {
     return false;
   }
 
-  /** Returns relation to the provided triangle */
   @Override
   public Relation relateTriangle(double minX, double maxX, double minY, double maxY,
                                  double ax, double ay, double bx, double by, double cx, double cy) {
@@ -131,7 +128,6 @@ final class ComponentTree implements Component2D {
     return component.withinTriangle(minX, maxX, minY, maxY, aX, aY, ab, bX, bY, bc, cX, cY, ca);
   }
 
-  /** Returns relation to the provided rectangle */
   @Override
   public Relation relate(double minX, double maxX, double minY, double maxY) {
     if (minY <= this.maxY && minX <= this.maxX) {
@@ -156,7 +152,7 @@ final class ComponentTree implements Component2D {
   }
 
   /** Creates tree from provided components */
-  public static Component2D create(Component2D[] components) {
+  static Component2D create(Component2D[] components) {
     if (components.length == 1) {
       return components[0];
     }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/EdgeTree.java b/lucene/core/src/java/org/apache/lucene/geo/EdgeTree.java
index f13e1a8..5e99506 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/EdgeTree.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/EdgeTree.java
@@ -23,45 +23,39 @@ import static org.apache.lucene.geo.GeoUtils.lineCrossesLineWithBoundary;
 import static org.apache.lucene.geo.GeoUtils.orient;
 
 /**
- * 2D line/polygon geometry implementation represented as a balanced interval tree of edges.
+ * Internal tree node: represents geometry edge from [x1, y1] to [x2, y2].
+ * The sort value is {@code low}, which is the minimum y of the edge.
+ * {@code max} stores the maximum y of this edge or any children.
  * <p>
  * Construction takes {@code O(n log n)} time for sorting and tree construction.
- * {@link #relate relate()} are {@code O(n)}, but for most
+ * Methods are {@code O(n)}, but for most
  * practical lines and polygons are much faster than brute force.
- * @lucene.internal
  */
-/**
- * Internal tree node: represents geometry edge from lat1,lon1 to lat2,lon2.
- * The sort value is {@code low}, which is the minimum latitude of the edge.
- * {@code max} stores the maximum latitude of this edge or any children.
- *
- * @lucene.internal
- */
-public class EdgeTree {
-    // lat-lon pair (in original order) of the two vertices
-    final double y1, y2;
-    final double x1, x2;
-    /** min of this edge */
-    final double low;
-    /** max latitude of this edge or any children */
-    double max;
-    /** left child edge, or null */
-    EdgeTree left;
-    /** right child edge, or null */
-    EdgeTree right;
-    /** helper bytes to signal if a point is on an edge, it is within the edge tree or disjoint */
-    final private static byte FALSE = 0x00;
-    final private static byte TRUE = 0x01;
-    final private static byte ON_EDGE = 0x02;
+final class EdgeTree {
+  // X-Y pair (in original order) of the two vertices
+  final double y1, y2;
+  final double x1, x2;
+  /** min Y of this edge */
+  final double low;
+  /** max Y of this edge or any children */
+  double max;
+  /** left child edge, or null */
+  EdgeTree left;
+  /** right child edge, or null */
+  EdgeTree right;
+  /** helper bytes to signal if a point is on an edge, it is within the edge tree or disjoint */
+  final private static byte FALSE = 0x00;
+  final private static byte TRUE = 0x01;
+  final private static byte ON_EDGE = 0x02;
 
-  EdgeTree(double x1, double y1, double x2, double y2, double low, double max) {
-      this.y1 = y1;
-      this.x1 = x1;
-      this.y2 = y2;
-      this.x2 = x2;
-      this.low = low;
-      this.max = max;
-    }
+  private EdgeTree(double x1, double y1, double x2, double y2, double low, double max) {
+    this.y1 = y1;
+    this.x1 = x1;
+    this.y2 = y2;
+    this.x2 = x2;
+    this.low = low;
+    this.max = max;
+  }
 
   /**
    * Returns true if the point is on an edge or crosses the edge subtree an odd number
@@ -135,7 +129,7 @@ public class EdgeTree {
   }
 
   /** returns true if the provided x, y point lies on the line */
-  protected boolean isPointOnLine(double x, double y) {
+  boolean isPointOnLine(double x, double y) {
     if (y <= max) {
       double a1x = x1;
       double a1y = y1;
@@ -160,7 +154,7 @@ public class EdgeTree {
 
 
   /** Returns true if the triangle crosses any edge in this edge subtree */
-  protected boolean crossesTriangle(double minX, double maxX, double minY, double maxY,
+  boolean crossesTriangle(double minX, double maxX, double minY, double maxY,
                           double ax, double ay, double bx, double by, double cx, double cy, boolean includeBoundary) {
       if (minY <= max) {
         double dy = y1;
@@ -204,7 +198,7 @@ public class EdgeTree {
     }
 
   /** Returns true if the box crosses any edge in this edge subtree */
-  protected boolean crossesBox(double minX, double maxX, double minY, double maxY, boolean includeBoundary) {
+  boolean crossesBox(double minX, double maxX, double minY, double maxY, boolean includeBoundary) {
     // we just have to cross one edge to answer the question, so we descend the tree and return when we do.
     if (minY <= max) {
       // we compute line intersections of every polygon edge with every box line.
@@ -261,7 +255,7 @@ public class EdgeTree {
   }
 
   /** Returns true if the line crosses any edge in this edge subtree */
-  protected boolean crossesLine(double minX, double maxX, double minY, double maxY, double a2x, double a2y, double b2x, double b2y, boolean includeBoundary) {
+  boolean crossesLine(double minX, double maxX, double minY, double maxY, double a2x, double a2y, double b2x, double b2y, boolean includeBoundary) {
     if (minY <= max) {
       double a1x = x1;
       double a1y = y1;
@@ -297,7 +291,7 @@ public class EdgeTree {
    * Creates an edge interval tree from a set of geometry vertices.
    * @return root node of the tree.
    */
-  protected static EdgeTree createTree(double[] x, double[] y) {
+  static EdgeTree createTree(double[] x, double[] y) {
     EdgeTree edges[] = new EdgeTree[x.length - 1];
     for (int i = 1; i < x.length; i++) {
       double x1 = x[i-1];
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Line2D.java b/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
index ed247bf..5c6593a 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Line2D.java
@@ -23,17 +23,16 @@ import org.apache.lucene.index.PointValues.Relation;
  * <p>
  * Line {@code Line2D} Construction takes {@code O(n log n)} time for sorting and tree construction.
  * {@link #relate relate()} are {@code O(n)}, but for most practical lines are much faster than brute force.
- * @lucene.internal
  */
-public final class Line2D implements Component2D {
+final class Line2D implements Component2D {
 
-  /** minimum latitude of this geometry's bounding box area */
+  /** minimum Y of this geometry's bounding box area */
   final private double minY;
-  /** maximum latitude of this geometry's bounding box area */
+  /** maximum Y of this geometry's bounding box area */
   final private double maxY;
-  /** minimum longitude of this geometry's bounding box area */
+  /** minimum X of this geometry's bounding box area */
   final private double minX;
-  /** maximum longitude of this geometry's bounding box area */
+  /** maximum X of this geometry's bounding box area */
   final private double maxX;
   /** lines represented as a 2-d interval tree.*/
   final private EdgeTree tree;
@@ -184,21 +183,13 @@ public final class Line2D implements Component2D {
     return relation;
   }
 
-  /** create a Line2D edge tree from provided array of Linestrings */
-  public static Component2D create(Line... lines) {
-    Component2D components[] = new Component2D[lines.length];
-    for (int i = 0; i < components.length; ++i) {
-      components[i] = new Line2D(lines[i]);
-    }
-    return ComponentTree.create(components);
+  /** create a Line2D from the provided LatLon Linestring */
+  static Component2D create(Line line) {
+    return new Line2D(line);
   }
 
-  /** create a Line2D edge tree from provided array of Linestrings */
-  public static Component2D create(XYLine... lines) {
-    Line2D components[] = new Line2D[lines.length];
-    for (int i = 0; i < components.length; ++i) {
-      components[i] = new Line2D(lines[i]);
-    }
-    return ComponentTree.create(components);
+  /** create a Line2D from the provided XY Linestring */
+  static Component2D create(XYLine line) {
+    return new Line2D(line);
   }
 }
\ No newline at end of file
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Point.java b/lucene/core/src/java/org/apache/lucene/geo/Point.java
index 859bed7..44845bd 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Point.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Point.java
@@ -56,9 +56,7 @@ public final class Point extends LatLonGeometry {
 
   @Override
   protected Component2D toComponent2D() {
-    double qLat = GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(lat));
-    double qLon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(lon));
-    return Point2D.create(new double[] {qLat, qLon});
+    return Point2D.create(this);
   }
 
   @Override
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Point2D.java b/lucene/core/src/java/org/apache/lucene/geo/Point2D.java
index d9865d4..f3e7909 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Point2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Point2D.java
@@ -21,15 +21,13 @@ import org.apache.lucene.index.PointValues;
 
 /**
  * 2D point implementation containing geo spatial logic.
- *
- * @lucene.internal
  */
-public class Point2D implements Component2D {
+final class Point2D implements Component2D {
 
   final private double x;
   final private double y;
 
-  Point2D(double x, double y) {
+  private Point2D(double x, double y) {
     this.x = x;
     this.y = y;
   }
@@ -88,22 +86,14 @@ public class Point2D implements Component2D {
     return WithinRelation.DISJOINT;
   }
 
-  /** create a Point2D component tree from provided array of LatLon points.  */
-  public static Component2D create(double[]... points) {
-    Point2D components[] = new Point2D[points.length];
-    for (int i = 0; i < components.length; ++i) {
-      components[i] = new Point2D(GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(points[i][1]))
-          , GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(points[i][0])));
-    }
-    return ComponentTree.create(components);
+  /** create a Point2D component tree from a LatLon point */
+  static Component2D create(Point point) {
+    return new Point2D(GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(point.getLon())),
+        GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(point.getLat())));
   }
 
-  /** create a Point2D component tree from provided array of XY points.  */
-  public static Component2D create(float[]... xyPoints) {
-    Point2D components[] = new Point2D[xyPoints.length];
-    for (int i = 0; i < components.length; ++i) {
-      components[i] = new Point2D(xyPoints[i][0], xyPoints[i][1]);
-    }
-    return ComponentTree.create(components);
+  /** create a Point2D component tree from a XY point */
+  static Component2D create(XYPoint xyPoint) {
+    return new Point2D(xyPoint.getX(), xyPoint.getY());
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java b/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
index c36d6aa..3e5fdb0 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/Polygon2D.java
@@ -23,24 +23,23 @@ import org.apache.lucene.index.PointValues.Relation;
  * <p>
  * Loosely based on the algorithm described in <a href="http://www-ma2.upc.es/geoc/Schirra-pointPolygon.pdf">
  * http://www-ma2.upc.es/geoc/Schirra-pointPolygon.pdf</a>.
- * @lucene.internal
  */
 
-public class Polygon2D implements Component2D {
-  /** minimum latitude of this geometry's bounding box area */
+final class Polygon2D implements Component2D {
+  /** minimum Y of this geometry's bounding box area */
   final private double minY;
-  /** maximum latitude of this geometry's bounding box area */
+  /** maximum Y of this geometry's bounding box area */
   final private double maxY;
-  /** minimum longitude of this geometry's bounding box area */
+  /** minimum X of this geometry's bounding box area */
   final private double minX;
-  /** maximum longitude of this geometry's bounding box area */
+  /** maximum X of this geometry's bounding box area */
   final private double maxX;
   /** tree of holes, or null */
   final protected Component2D holes;
   /** Edges of the polygon represented as a 2-d interval tree.*/
   final EdgeTree tree;
 
-  protected Polygon2D(final double minX, final double maxX, final double minY, final double maxY, double[] x, double[] y, Component2D holes) {
+  private Polygon2D(final double minX, final double maxX, final double minY, final double maxY, double[] x, double[] y, Component2D holes) {
     this.minY = minY;
     this.maxY = maxY;
     this.minX = minX;
@@ -49,6 +48,10 @@ public class Polygon2D implements Component2D {
     this.tree = EdgeTree.createTree(x, y);
   }
 
+  private Polygon2D(XYPolygon polygon, Component2D holes) {
+    this(polygon.minX, polygon.maxX, polygon.minY, polygon.maxY, polygon.getPolyX(), polygon.getPolyY(), holes);
+  }
+
   protected Polygon2D(Polygon polygon, Component2D holes) {
     this(polygon.minLon, polygon.maxLon, polygon.minLat, polygon.maxLat, polygon.getPolyLons(), polygon.getPolyLats(), holes);
   }
@@ -312,18 +315,24 @@ public class Polygon2D implements Component2D {
     return containsCount;
   }
 
-  /** Builds a Polygon2D from multipolygon */
-  public static Component2D create(Polygon... polygons) {
-    Component2D components[] = new Component2D[polygons.length];
-    for (int i = 0; i < components.length; i++) {
-      Polygon gon = polygons[i];
-      Polygon gonHoles[] = gon.getHoles();
-      Component2D holes = null;
-      if (gonHoles.length > 0) {
-        holes = create(gonHoles);
-      }
-      components[i] = new Polygon2D(gon, holes);
-    }
-    return ComponentTree.create(components);
+  /** Builds a Polygon2D from LatLon polygon */
+  static Component2D create(Polygon polygon) {
+    Polygon gonHoles[] = polygon.getHoles();
+    Component2D holes = null;
+    if (gonHoles.length > 0) {
+      holes = LatLonGeometry.create(gonHoles);
+    }
+    return new Polygon2D(polygon, holes);
   }
+
+  /** Builds a Polygon2D from XY polygon */
+  static Component2D create(XYPolygon polygon) {
+    XYPolygon gonHoles[] = polygon.getHoles();
+    Component2D holes = null;
+    if (gonHoles.length > 0) {
+      holes = XYGeometry.create(gonHoles);
+    }
+    return new Polygon2D(polygon, holes);
+  }
+
 }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYGeometry.java b/lucene/core/src/java/org/apache/lucene/geo/XYGeometry.java
new file mode 100644
index 0000000..a6bfca2
--- /dev/null
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYGeometry.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.lucene.geo;
+
+/**
+ * Cartesian Geometry object.
+ **/
+public abstract class XYGeometry {
+
+  /** get a Component2D from this object */
+  protected abstract Component2D toComponent2D();
+
+  /** Creates a Component2D from the provided XYGeometries array */
+  public static Component2D create(XYGeometry... xyGeometries) {
+    if (xyGeometries == null) {
+      throw new IllegalArgumentException("geometries must not be null");
+    }
+    if (xyGeometries.length == 0) {
+      throw new IllegalArgumentException("geometries must not be empty");
+    }
+    if (xyGeometries.length == 1) {
+      if (xyGeometries[0] == null) {
+        throw new IllegalArgumentException("geometries[0] must not be null");
+      }
+      return xyGeometries[0].toComponent2D();
+    }
+    Component2D[] components = new Component2D[xyGeometries.length];
+    for (int i = 0; i < xyGeometries.length; i++) {
+      if (xyGeometries[i] == null) {
+        throw new IllegalArgumentException("geometries[" + i + "] must not be null");
+      }
+      components[i] = xyGeometries[i].toComponent2D();
+    }
+    return ComponentTree.create(components);
+  }
+}
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYLine.java b/lucene/core/src/java/org/apache/lucene/geo/XYLine.java
index 02b957a..c3f59ac 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/XYLine.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYLine.java
@@ -19,10 +19,10 @@ package org.apache.lucene.geo;
 import java.util.Arrays;
 
 /**
- * Represents a line in cartesian space. You can construct the Line directly with {@code double[]}, {@code double[]} x, y arrays
+ * Represents a line in cartesian space. You can construct the Line directly with {@code float[]}, {@code float[]} x, y arrays
  * coordinates.
  */
-public class XYLine {
+public class XYLine extends XYGeometry {
   /** array of x coordinates */
   private final double[] x;
   /** array of y coordinates */
@@ -30,7 +30,7 @@ public class XYLine {
 
   /** minimum x of this line's bounding box */
   public final double minX;
-  /** maximum x of this line's bounding box */
+  /** maximum y of this line's bounding box */
   public final double maxX;
   /** minimum y of this line's bounding box */
   public final double minY;
@@ -38,7 +38,7 @@ public class XYLine {
   public final double maxY;
 
   /**
-   * Creates a new Line from the supplied x/y array.
+   * Creates a new Line from the supplied X/Y array.
    */
   public XYLine(float[] x, float[] y) {
     if (x == null) {
@@ -104,6 +104,19 @@ public class XYLine {
   }
 
   @Override
+  protected Component2D toComponent2D() {
+    return Line2D.create(this);
+  }
+
+  public String toGeoJSON() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("[");
+    sb.append(Polygon.verticesToGeoJSON(x, y));
+    sb.append("]");
+    return sb.toString();
+  }
+
+  @Override
   public boolean equals(Object o) {
     if (this == o) return true;
     if (!(o instanceof XYLine)) return false;
@@ -132,13 +145,4 @@ public class XYLine {
     sb.append(')');
     return sb.toString();
   }
-
-  /** prints polygons as geojson */
-  public String toGeoJSON() {
-    StringBuilder sb = new StringBuilder();
-    sb.append("[");
-    sb.append(Polygon.verticesToGeoJSON(x, y));
-    sb.append("]");
-    return sb.toString();
-  }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/Point.java b/lucene/core/src/java/org/apache/lucene/geo/XYPoint.java
similarity index 68%
copy from lucene/core/src/java/org/apache/lucene/geo/Point.java
copy to lucene/core/src/java/org/apache/lucene/geo/XYPoint.java
index 859bed7..9b6d0ee 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/Point.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYPoint.java
@@ -27,52 +27,48 @@ package org.apache.lucene.geo;
  *   <li>For more advanced GeoSpatial indexing and query operations see the {@code spatial-extras} module
  * </ol>
  */
-public final class Point extends LatLonGeometry {
+public final class XYPoint extends XYGeometry {
 
   /** latitude coordinate */
-  private final double lat;
+  private final double x;
   /** longitude coordinate */
-  private final double lon;
+  private final double y;
 
   /**
    * Creates a new Point from the supplied latitude/longitude.
    */
-  public Point(double lat, double lon) {
-    GeoUtils.checkLatitude(lat);
-    GeoUtils.checkLongitude(lon);
-    this.lat = lat;
-    this.lon = lon;
+  public XYPoint(float x, float y) {
+    this.x = x;
+    this.y = y;
   }
 
   /** Returns latitude value at given index */
-  public double getLat() {
-    return lat;
+  public double getX() {
+    return x;
   }
 
   /** Returns longitude value at given index */
-  public double getLon() {
-    return lon;
+  public double getY() {
+    return y;
   }
 
   @Override
   protected Component2D toComponent2D() {
-    double qLat = GeoEncodingUtils.decodeLatitude(GeoEncodingUtils.encodeLatitude(lat));
-    double qLon = GeoEncodingUtils.decodeLongitude(GeoEncodingUtils.encodeLongitude(lon));
-    return Point2D.create(new double[] {qLat, qLon});
+    return Point2D.create(this);
   }
 
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;
-    if (!(o instanceof Point)) return false;
-    Point point = (Point) o;
-    return point.lat == lat && point.lon == lon;
+    if (!(o instanceof XYPoint)) return false;
+    XYPoint point = (XYPoint) o;
+    return point.x == x && point.y == y;
   }
 
   @Override
   public int hashCode() {
-    int result = Double.hashCode(lat);
-    result = 31 * result + Double.hashCode(lon);
+    int result = Double.hashCode(x);
+    result = 31 * result + Double.hashCode(y);
     return result;
   }
 
@@ -80,9 +76,9 @@ public final class Point extends LatLonGeometry {
   public String toString() {
     StringBuilder sb = new StringBuilder();
     sb.append("Point(");
-    sb.append(lon);
+    sb.append(x);
     sb.append(",");
-    sb.append(lat);
+    sb.append(y);
     sb.append(')');
     return sb.toString();
   }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYPolygon.java b/lucene/core/src/java/org/apache/lucene/geo/XYPolygon.java
index f44fe9c..00ec377 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/XYPolygon.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYPolygon.java
@@ -19,10 +19,10 @@ package org.apache.lucene.geo;
 import java.util.Arrays;
 
 /**
- * Represents a polygon in cartesian space. You can construct the Polygon directly with {@code double[]}, {@code double[]} x, y arrays
+ * Represents a polygon in cartesian space. You can construct the Polygon directly with {@code float[]}, {@code float[]} x, y arrays
  * coordinates.
  */
-public class XYPolygon {
+public final class XYPolygon extends XYGeometry {
   private final double[] x;
   private final double[] y;
   private final XYPolygon[] holes;
@@ -146,6 +146,23 @@ public class XYPolygon {
   }
 
   @Override
+  protected Component2D toComponent2D() {
+    return Polygon2D.create(this);
+  }
+
+  public String toGeoJSON() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("[");
+    sb.append(Polygon.verticesToGeoJSON(y, x));
+    for (XYPolygon hole : holes) {
+      sb.append(",");
+      sb.append(Polygon.verticesToGeoJSON(hole.y, hole.x));
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+
+  @Override
   public int hashCode() {
     final int prime = 31;
     int result = 1;
@@ -183,17 +200,4 @@ public class XYPolygon {
     }
     return sb.toString();
   }
-
-  /** prints polygons as geojson */
-  public String toGeoJSON() {
-    StringBuilder sb = new StringBuilder();
-    sb.append("[");
-    sb.append(Polygon.verticesToGeoJSON(y, x));
-    for (XYPolygon hole : holes) {
-      sb.append(",");
-      sb.append(Polygon.verticesToGeoJSON(hole.y, hole.x));
-    }
-    sb.append("]");
-    return sb.toString();
-  }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYPolygon2D.java b/lucene/core/src/java/org/apache/lucene/geo/XYPolygon2D.java
deleted file mode 100644
index cf5b174..0000000
--- a/lucene/core/src/java/org/apache/lucene/geo/XYPolygon2D.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.lucene.geo;
-
-/**
- * 2D cartesian polygon implementation represented as a balanced interval tree of edges.
- *
- * @lucene.internal
- */
-public class XYPolygon2D extends Polygon2D {
-
-  protected XYPolygon2D(XYPolygon polygon, Component2D holes) {
-    super(polygon.minX, polygon.maxX, polygon.minY, polygon.maxY, polygon.getPolyX(), polygon.getPolyY(), holes);
-  }
-
-  /** Builds a Polygon2D from multipolygon */
-  public static Component2D create(XYPolygon... polygons) {
-    XYPolygon2D components[] = new XYPolygon2D[polygons.length];
-    for (int i = 0; i < components.length; i++) {
-      XYPolygon gon = polygons[i];
-      XYPolygon gonHoles[] = gon.getHoles();
-      Component2D holes = null;
-      if (gonHoles.length > 0) {
-        holes = create(gonHoles);
-      }
-      components[i] = new XYPolygon2D(gon, holes);
-    }
-    return ComponentTree.create(components);
-  }
-}
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYRectangle.java b/lucene/core/src/java/org/apache/lucene/geo/XYRectangle.java
index 4751cfc..23175b1 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/XYRectangle.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYRectangle.java
@@ -17,7 +17,7 @@
 package org.apache.lucene.geo;
 
 /** Represents a x/y cartesian rectangle. */
-public class XYRectangle {
+public final class XYRectangle extends XYGeometry {
   /** minimum x value */
   public final double minX;
   /** minimum y value */
@@ -38,6 +38,11 @@ public class XYRectangle {
   }
 
   @Override
+  protected Component2D toComponent2D() {
+    return XYRectangle2D.create(this);
+  }
+
+  @Override
   public boolean equals(Object o) {
     if (this == o) return true;
     if (o == null || getClass() != o.getClass()) return false;
diff --git a/lucene/core/src/java/org/apache/lucene/geo/XYRectangle2D.java b/lucene/core/src/java/org/apache/lucene/geo/XYRectangle2D.java
index 54b5078..b15d797 100644
--- a/lucene/core/src/java/org/apache/lucene/geo/XYRectangle2D.java
+++ b/lucene/core/src/java/org/apache/lucene/geo/XYRectangle2D.java
@@ -24,17 +24,15 @@ import static org.apache.lucene.geo.GeoUtils.orient;
 
 /**
  * 2D rectangle implementation containing cartesian spatial logic.
- *
- * @lucene.internal
  */
-public class XYRectangle2D implements Component2D {
+final class XYRectangle2D implements Component2D {
 
   private final double minX;
   private final double maxX;
   private final double minY;
   private final double maxY;
 
-  protected XYRectangle2D(double minX, double maxX, double minY, double maxY) {
+  private XYRectangle2D(double minX, double maxX, double minY, double maxY) {
     this.minX =  minX;
     this.maxX =  maxX;
     this.minY =  minY;
@@ -235,15 +233,11 @@ public class XYRectangle2D implements Component2D {
     return sb.toString();
   }
 
-  /** create a component2D from provided array of rectangles */
-  public static Component2D create(XYRectangle... rectangles) {
-    XYRectangle2D[] components = new XYRectangle2D[rectangles.length];
-    for (int i = 0; i < components.length; ++i) {
-      components[i] = new XYRectangle2D(XYEncodingUtils.decode(XYEncodingUtils.encode(rectangles[i].minX)),
-          XYEncodingUtils.decode(XYEncodingUtils.encode(rectangles[i].maxX)),
-          XYEncodingUtils.decode(XYEncodingUtils.encode(rectangles[i].minY)),
-          XYEncodingUtils.decode(XYEncodingUtils.encode(rectangles[i].maxY)));
-    }
-    return ComponentTree.create(components);
+  /** create a component2D from the provided XY rectangle */
+  static Component2D create(XYRectangle rectangle) {
+    return new XYRectangle2D(XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.minX)),
+        XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.maxX)),
+        XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.minY)),
+        XYEncodingUtils.decode(XYEncodingUtils.encode(rectangle.maxY)));
   }
 }
\ No newline at end of file
diff --git a/lucene/core/src/test/org/apache/lucene/document/BaseLatLonShapeTestCase.java b/lucene/core/src/test/org/apache/lucene/document/BaseLatLonShapeTestCase.java
index 6208b9e..c49496a 100644
--- a/lucene/core/src/test/org/apache/lucene/document/BaseLatLonShapeTestCase.java
+++ b/lucene/core/src/test/org/apache/lucene/document/BaseLatLonShapeTestCase.java
@@ -22,11 +22,9 @@ import com.carrotsearch.randomizedtesting.generators.RandomPicks;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.GeoTestUtil;
+import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Line;
-import org.apache.lucene.geo.Line2D;
-import org.apache.lucene.geo.Point2D;
 import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.Polygon2D;
 import org.apache.lucene.geo.Rectangle;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryUtils;
@@ -75,17 +73,22 @@ public abstract class BaseLatLonShapeTestCase extends BaseShapeTestCase {
 
   @Override
   protected Component2D toLine2D(Object... lines) {
-    return Line2D.create(Arrays.stream(lines).toArray(Line[]::new));
+    return LatLonGeometry.create(Arrays.stream(lines).toArray(Line[]::new));
   }
 
   @Override
   protected Component2D toPolygon2D(Object... polygons) {
-    return Polygon2D.create(Arrays.stream(polygons).toArray(Polygon[]::new));
+    return LatLonGeometry.create(Arrays.stream(polygons).toArray(Polygon[]::new));
   }
 
   @Override
   protected Component2D toPoint2D(Object... points) {
-    return Point2D.create(Arrays.stream(points).toArray(double[][]::new));
+    double[][] p = Arrays.stream(points).toArray(double[][]::new);
+    org.apache.lucene.geo.Point[] pointArray = new org.apache.lucene.geo.Point[points.length];
+    for (int i =0; i < points.length; i++) {
+      pointArray[i] = new org.apache.lucene.geo.Point(p[i][0], p[i][1]);
+    }
+    return LatLonGeometry.create(pointArray);
   }
 
   @Override
@@ -388,5 +391,4 @@ public abstract class BaseLatLonShapeTestCase extends BaseShapeTestCase {
       return sb.toString();
     }
   }
-
 }
diff --git a/lucene/core/src/test/org/apache/lucene/document/BaseXYShapeTestCase.java b/lucene/core/src/test/org/apache/lucene/document/BaseXYShapeTestCase.java
index 9ec78c0..40bca2b 100644
--- a/lucene/core/src/test/org/apache/lucene/document/BaseXYShapeTestCase.java
+++ b/lucene/core/src/test/org/apache/lucene/document/BaseXYShapeTestCase.java
@@ -22,12 +22,11 @@ import java.util.Random;
 import com.carrotsearch.randomizedtesting.generators.RandomPicks;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
-import org.apache.lucene.geo.Line2D;
-import org.apache.lucene.geo.Point2D;
 import org.apache.lucene.geo.ShapeTestUtil;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYLine;
+import org.apache.lucene.geo.XYPoint;
 import org.apache.lucene.geo.XYPolygon;
-import org.apache.lucene.geo.XYPolygon2D;
 import org.apache.lucene.geo.XYRectangle;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.TestUtil;
@@ -68,17 +67,22 @@ public abstract class BaseXYShapeTestCase extends BaseShapeTestCase {
 
   @Override
   protected Component2D toPoint2D(Object... points) {
-    return Point2D.create(Arrays.stream(points).toArray(float[][]::new));
+    float[][] p = Arrays.stream(points).toArray(float[][]::new);
+    XYPoint[] pointArray = new XYPoint[points.length];
+    for (int i =0; i < points.length; i++) {
+      pointArray[i] = new XYPoint(p[i][0], p[i][1]);
+    }
+    return XYGeometry.create(pointArray);
   }
 
   @Override
   protected Component2D toLine2D(Object... lines) {
-    return Line2D.create(Arrays.stream(lines).toArray(XYLine[]::new));
+    return XYGeometry.create(Arrays.stream(lines).toArray(XYLine[]::new));
   }
 
   @Override
   protected Component2D toPolygon2D(Object... polygons) {
-    return XYPolygon2D.create(Arrays.stream(polygons).toArray(XYPolygon[]::new));
+    return XYGeometry.create(Arrays.stream(polygons).toArray(XYPolygon[]::new));
   }
 
   @Override
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
index 0746d02..28c4382 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShape.java
@@ -21,10 +21,9 @@ import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.GeoEncodingUtils;
 import org.apache.lucene.geo.GeoTestUtil;
+import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Line;
-import org.apache.lucene.geo.Line2D;
 import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.Polygon2D;
 import org.apache.lucene.geo.Rectangle;
 import org.apache.lucene.geo.Rectangle2D;
 import org.apache.lucene.geo.Tessellator;
@@ -515,7 +514,7 @@ public class TestLatLonShape extends LuceneTestCase {
     double blon = -52.67048754768767;
     Polygon polygon = new Polygon(new double[] {-14.448264200949083, 0, 0, -14.448264200949083, -14.448264200949083},
         new double[] {0.9999999403953552, 0.9999999403953552, 124.50086371762484, 124.50086371762484, 0.9999999403953552});
-    Component2D polygon2D = Polygon2D.create(polygon);
+    Component2D polygon2D = LatLonGeometry.create(polygon);
     PointValues.Relation rel = polygon2D.relateTriangle(
         quantizeLon(alon), quantizeLat(blat),
         quantizeLon(blon), quantizeLat(blat),
@@ -533,7 +532,7 @@ public class TestLatLonShape extends LuceneTestCase {
 
   public void testTriangleTouchingEdges() {
     Polygon p = new Polygon(new double[] {0, 0, 1, 1, 0}, new double[] {0, 1, 1, 0, 0});
-    Component2D polygon2D = Polygon2D.create(p);
+    Component2D polygon2D = LatLonGeometry.create(p);
     //3 shared points
     PointValues.Relation rel = polygon2D.relateTriangle(
         quantizeLon(0.5), quantizeLat(0),
@@ -633,7 +632,7 @@ public class TestLatLonShape extends LuceneTestCase {
 
   public void testTriangleCrossingPolygonVertices() {
     Polygon p = new Polygon(new double[] {0, 0, -5, -10, -5, 0}, new double[] {-1, 1, 5, 0, -5, -1});
-    Component2D polygon2D = Polygon2D.create(p);
+    Component2D polygon2D = LatLonGeometry.create(p);
     PointValues.Relation rel = polygon2D.relateTriangle(
         quantizeLon(-5), quantizeLat(0),
         quantizeLon(10), quantizeLat(0),
@@ -643,7 +642,7 @@ public class TestLatLonShape extends LuceneTestCase {
 
   public void testLineCrossingPolygonVertices() {
     Polygon p = new Polygon(new double[] {0, -1, 0, 1, 0}, new double[] {-1, 0, 1, 0, -1});
-    Component2D polygon2D = Polygon2D.create(p);
+    Component2D polygon2D = LatLonGeometry.create(p);
     PointValues.Relation rel = polygon2D.relateTriangle(
         quantizeLon(-1.5), quantizeLat(0),
         quantizeLon(1.5), quantizeLat(0),
@@ -653,7 +652,7 @@ public class TestLatLonShape extends LuceneTestCase {
 
   public void testLineSharedLine() {
     Line l = new Line(new double[] {0, 0, 0, 0}, new double[] {-2, -1, 0, 1});
-    Component2D l2d = Line2D.create(l);
+    Component2D l2d = LatLonGeometry.create(l);
     PointValues.Relation r = l2d.relateTriangle(
         quantizeLon(-5), quantizeLat(0),
         quantizeLon(5), quantizeLat(0),
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShapeEncoding.java b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShapeEncoding.java
index 5dc37ab..b100e82 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestLatLonShapeEncoding.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestLatLonShapeEncoding.java
@@ -19,8 +19,8 @@ package org.apache.lucene.document;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.GeoEncodingUtils;
 import org.apache.lucene.geo.GeoTestUtil;
+import org.apache.lucene.geo.LatLonGeometry;
 import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.Polygon2D;
 
 /** Test case for LatLonShape encoding */
 public class TestLatLonShapeEncoding extends BaseShapeEncodingTestCase {
@@ -62,6 +62,6 @@ public class TestLatLonShapeEncoding extends BaseShapeEncodingTestCase {
 
   @Override
   protected Component2D createPolygon2D(Object polygon) {
-    return Polygon2D.create((Polygon)polygon);
+    return LatLonGeometry.create((Polygon)polygon);
   }
 }
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYLineShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYLineShapeQueries.java
index 0306b0e..6c884a4 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYLineShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYLineShapeQueries.java
@@ -23,9 +23,9 @@ import java.util.Random;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.ShapeTestUtil;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYLine;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
 import org.apache.lucene.index.PointValues.Relation;
 
 /** random cartesian bounding box, line, and polygon query tests for random generated cartesian {@link XYLine} types */
@@ -80,7 +80,7 @@ public class TestXYLineShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiLineShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiLineShapeQueries.java
index 6e153c3..399eea9 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiLineShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiLineShapeQueries.java
@@ -21,9 +21,9 @@ import java.util.List;
 
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYLine;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
 
 /** random cartesian bounding box, line, and polygon query tests for random indexed arrays of cartesian {@link XYLine} types */
 public class TestXYMultiLineShapeQueries extends BaseXYShapeTestCase {
@@ -76,7 +76,7 @@ public class TestXYMultiLineShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPointShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPointShapeQueries.java
index 0c2f50c..8b6db65 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPointShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPointShapeQueries.java
@@ -21,8 +21,8 @@ import java.util.List;
 
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
 
 /** random cartesian bounding box, line, and polygon query tests for random indexed arrays of {@code x, y} points */
 public class TestXYMultiPointShapeQueries extends BaseXYShapeTestCase {
@@ -75,7 +75,7 @@ public class TestXYMultiPointShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPolygonShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPolygonShapeQueries.java
index 62ea204..d45c029 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPolygonShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYMultiPolygonShapeQueries.java
@@ -24,7 +24,7 @@ import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.Tessellator;
 import org.apache.lucene.geo.XYPolygon;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.util.LuceneTestCase;
 
 /** random cartesian bounding box, line, and polygon query tests for random indexed arrays of cartesian {@link XYPolygon} types */
@@ -115,7 +115,7 @@ public class TestXYMultiPolygonShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYPointShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYPointShapeQueries.java
index cea0ff5..2085095 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYPointShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYPointShapeQueries.java
@@ -23,9 +23,9 @@ import java.util.Random;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.ShapeTestUtil;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYLine;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
 import org.apache.lucene.index.PointValues.Relation;
 
 /** random cartesian bounding box, line, and polygon query tests for random generated {@code x, y} points */
@@ -80,7 +80,7 @@ public class TestXYPointShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYPolygonShapeQueries.java b/lucene/core/src/test/org/apache/lucene/document/TestXYPolygonShapeQueries.java
index e61e350..80b3436 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYPolygonShapeQueries.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYPolygonShapeQueries.java
@@ -21,9 +21,9 @@ import java.util.List;
 import org.apache.lucene.document.ShapeField.QueryRelation;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.Tessellator;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYPolygon;
 import org.apache.lucene.geo.XYRectangle;
-import org.apache.lucene.geo.XYRectangle2D;
 import org.apache.lucene.index.PointValues.Relation;
 
 /** random cartesian bounding box, line, and polygon query tests for random indexed {@link XYPolygon} types */
@@ -66,7 +66,7 @@ public class TestXYPolygonShapeQueries extends BaseXYShapeTestCase {
 
     @Override
     public boolean testBBoxQuery(double minY, double maxY, double minX, double maxX, Object shape) {
-      Component2D rectangle2D = XYRectangle2D.create(new XYRectangle(minX, maxX, minY, maxY));
+      Component2D rectangle2D = XYGeometry.create(new XYRectangle(minX, maxX, minY, maxY));
       return testComponentQuery(rectangle2D, shape);
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/document/TestXYShapeEncoding.java b/lucene/core/src/test/org/apache/lucene/document/TestXYShapeEncoding.java
index 5aa7a38..5d3e201 100644
--- a/lucene/core/src/test/org/apache/lucene/document/TestXYShapeEncoding.java
+++ b/lucene/core/src/test/org/apache/lucene/document/TestXYShapeEncoding.java
@@ -19,8 +19,8 @@ package org.apache.lucene.document;
 import org.apache.lucene.geo.Component2D;
 import org.apache.lucene.geo.ShapeTestUtil;
 import org.apache.lucene.geo.XYEncodingUtils;
+import org.apache.lucene.geo.XYGeometry;
 import org.apache.lucene.geo.XYPolygon;
-import org.apache.lucene.geo.XYPolygon2D;
 
 /** tests XYShape encoding */
 public class TestXYShapeEncoding extends BaseShapeEncodingTestCase {
@@ -61,6 +61,6 @@ public class TestXYShapeEncoding extends BaseShapeEncodingTestCase {
 
   @Override
   protected Component2D createPolygon2D(Object polygon) {
-    return XYPolygon2D.create((XYPolygon)polygon);
+    return XYGeometry.create((XYPolygon)polygon);
   }
 }
diff --git a/lucene/core/src/test/org/apache/lucene/geo/TestPoint2D.java b/lucene/core/src/test/org/apache/lucene/geo/TestPoint2D.java
index bc4c135..d398a4f 100644
--- a/lucene/core/src/test/org/apache/lucene/geo/TestPoint2D.java
+++ b/lucene/core/src/test/org/apache/lucene/geo/TestPoint2D.java
@@ -23,7 +23,7 @@ import org.apache.lucene.util.LuceneTestCase;
 public class TestPoint2D extends LuceneTestCase {
 
   public void testTriangleDisjoint() {
-    Component2D point2D = Point2D.create(new double[] {0, 0});
+    Component2D point2D = Point2D.create(new Point(0, 0));
     double ax = 4;
     double ay = 4;
     double bx = 5;
@@ -36,7 +36,7 @@ public class TestPoint2D extends LuceneTestCase {
   }
 
   public void testTriangleIntersects() {
-    Component2D point2D = Point2D.create(new double[] {0, 0});
+    Component2D point2D = Point2D.create(new Point(0, 0));
     double ax = 0.0;
     double ay = 0.0;
     double bx = 1;
@@ -49,7 +49,7 @@ public class TestPoint2D extends LuceneTestCase {
   }
 
   public void testTriangleContains() {
-    Component2D point2D = Point2D.create(new double[] {0, 0});
+    Component2D point2D = Point2D.create(new Point(0, 0));
     double ax = 0.0;
     double ay = 0.0;
     double bx = 0;
@@ -63,7 +63,7 @@ public class TestPoint2D extends LuceneTestCase {
 
 
   public void testRandomTriangles() {
-    Component2D point2D = Point2D.create(new double[] {GeoTestUtil.nextLatitude(), GeoTestUtil.nextLongitude()});
+    Component2D point2D = Point2D.create(new Point(GeoTestUtil.nextLatitude(), GeoTestUtil.nextLongitude()));
 
     for (int i =0; i < 100; i++) {
       double ax = GeoTestUtil.nextLongitude();
diff --git a/lucene/core/src/test/org/apache/lucene/geo/TestPolygon2D.java b/lucene/core/src/test/org/apache/lucene/geo/TestPolygon2D.java
index 710c6a6..c91519e 100644
--- a/lucene/core/src/test/org/apache/lucene/geo/TestPolygon2D.java
+++ b/lucene/core/src/test/org/apache/lucene/geo/TestPolygon2D.java
@@ -35,7 +35,7 @@ public class TestPolygon2D extends LuceneTestCase {
     Polygon hole = new Polygon(new double[] { -10, -10, 10, 10, -10 }, new double[] { -10, 10, 10, -10, -10 });
     Polygon outer = new Polygon(new double[] { -50, -50, 50, 50, -50 }, new double[] { -50, 50, 50, -50, -50 }, hole);
     Polygon island = new Polygon(new double[] { -5, -5, 5, 5, -5 }, new double[] { -5, 5, 5, -5, -5 } );
-    Component2D polygon = Polygon2D.create(outer, island);
+    Component2D polygon = LatLonGeometry.create(outer, island);
     
     // contains(point)
     assertTrue(polygon.contains(-2, 2)); // on the island