Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ Improvements

* GITHUB#15332: Add PhraseQuery.Builder.setMaxTerms() method to limit the maximum number of terms and excessive memory use (linyunanit)

* GITHUB#15356: Improve docs for 4 internal classes in geo package (Matt Baranowski)

Optimizations
---------------------
* GITHUB#15140: Optimize TopScoreDocCollector with TernaryLongHeap for improved performance over Binary-LongHeap. (Ramakrishna Chilaka)
Expand Down
85 changes: 84 additions & 1 deletion lucene/core/src/java/org/apache/lucene/geo/Circle2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,90 @@
import org.apache.lucene.index.PointValues.Relation;
import org.apache.lucene.util.SloppyMath;

/** 2D circle implementation containing spatial logic. */
/**
* Internal 2D representation of a circle for spatial query operations.
*
* <p>This class provides spatial logic for circle-based queries, converting high-level {@link
* Circle} or {@link XYCircle} geometries into 2D representations. It is used internally by Lucene's
* spatial search implementation.
*
* <p>Key Features:
*
* <ul>
* <li>Efficient point containment checks
* <li>Line and triangle intersection tests
* <li>Bounding box relationship calculations
* <li>Support for both geographic (lat/lon) and Cartesian coordinate systems
* <li>Handles dateline crossing for geographic circles
* </ul>
*
* <p>Distance Calculation Modes:
*
* <ul>
* <li><strong>Haversin Distance</strong> - For geographic circles (lat/lon coordinates), uses
* spherical Earth model
* <li><strong>Cartesian Distance</strong> - For XY circles (planar coordinates), uses Euclidean
* distance
* </ul>
*
* <p>Usage:
*
* <p>This class is created through the {@link Circle#toComponent2D()} or {@link
* XYCircle#toComponent2D()} methods:
*
* <pre>{@code
* // Geographic circle (lat/lon) - uses Haversin distance
* double eiffelTowerLat = 48.8584;
* double eiffelTowerLon = 2.2945;
* double radiusMeters = 1000; // 1km radius
* Circle geoCircle = new Circle(eiffelTowerLat, eiffelTowerLon, radiusMeters);
* Component2D geoComponent = geoCircle.toComponent2D(); // Creates Circle2D internally
*
* // Cartesian circle (XY) - uses Euclidean distance
* float centerX = 100.0f;
* float centerY = 200.0f;
* float radius = 50.0f;
* XYCircle xyCircle = new XYCircle(centerX, centerY, radius);
* Component2D xyComponent = xyCircle.toComponent2D(); // Creates Circle2D internally
* }</pre>
*
* <p>Spatial Operations:
*
* <p>Circle2D provides several spatial relationship methods:
*
* <ul>
* <li>{@link #contains(double, double)} - Tests if a point is inside the circle
* <li>{@link #relate(double, double, double, double)} - Determines relationship with a bounding
* box
* <li>{@link #intersectsLine} - Tests if a line segment intersects the circle
* <li>{@link #intersectsTriangle} - Tests if a triangle intersects the circle
* <li>{@link #containsLine} - Tests if a line segment is fully contained within the circle
* <li>{@link #containsTriangle} - Tests if a triangle is fully contained within the circle
* </ul>
*
* <p>Performance Considerations:
*
* <ul>
* <li>Uses bounding box checks to eliminate non-intersecting geometries
* <li>Cartesian distance calculations are faster than Haversin (geographic) calculations
* <li>For geographic circles near poles or crossing the dateline, additional logic ensures
* correctness
* </ul>
*
* <p>Implementation Details:
*
* <p>Circle2D uses a strategy pattern with {@link DistanceCalculator} implementations:
*
* <ul>
* <li>{@link CartesianDistance} - For XY coordinate systems
* <li>{@link HaversinDistance} - For geographic coordinate systems (lat/lon)
* </ul>
*
* @lucene.internal
* @see Circle
* @see XYCircle
* @see Component2D
*/
class Circle2D implements Component2D {

private final DistanceCalculator calculator;
Expand Down
137 changes: 136 additions & 1 deletion lucene/core/src/java/org/apache/lucene/geo/Component2D.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,144 @@
import org.apache.lucene.index.PointValues;

/**
* 2D Geometry object that supports spatial relationships with bounding boxes, triangles and points.
* Interface for 2D geometric components that support spatial relationship queries.
*
* <p>Component2D defines the contract for testing spatial relationships between geometric shapes
* and index structures (points, lines, triangles, bounding boxes). This interface is central to
* Lucene's spatial search implementation, enabling filtering of documents during geospatial
* queries.
*
* <p>Key Features:
*
* <ul>
* <li>Point containment testing
* <li>Line and triangle intersection detection
* <li>Line and triangle containment testing
* <li>Bounding box relationship computation
* <li>"Within" relationship evaluation for spatial queries
* </ul>
*
* <p>Implementations:
*
* <p>Component2D is implemented by geometric shapes classes:
*
* <ul>
* <li>{@link Circle2D} - Circular regions (both geographic and Cartesian)
* <li>{@link Polygon2D} - Polygonal regions with hole support
* <li>{@link Rectangle2D} - Rectangular bounding boxes
* <li>{@link Line2D} - Line segments and polylines
* <li>{@link Point2D} - Point geometries
* </ul>
*
* <p>Usage:
*
* <p>Component2D instances are created by calling {@code toComponent2D()} on high-level geometry
* objects:
*
* <pre>{@code
* // Create from a Circle
* double nycLat = 40.7128;
* double nycLon = -74.0060;
* double radiusMeters = 5000; // 5km radius
* Circle circle = new Circle(nycLat, nycLon, radiusMeters);
* Component2D component = circle.toComponent2D();
*
* // Test if a point is contained
* double xCoordinate = -74.0060;
* double yCoordinate = 40.7128;
* boolean contained = component.contains(xCoordinate, yCoordinate);
*
* // Test relationship with a bounding box
* double minX = -74.01;
* double maxX = -74.00;
* double minY = 40.71;
* double maxY = 40.72;
* PointValues.Relation relation = component.relate(minX, maxX, minY, maxY);
* }</pre>
*
* <p>Spatial Relationship Methods:
*
* <p><strong>Containment:</strong>
*
* <ul>
* <li>{@link #contains(double, double)} - Tests if a point is inside the geometry
* <li>{@link #containsLine} - Tests if a line segment is fully contained
* <li>{@link #containsTriangle} - Tests if a triangle is fully contained
* </ul>
*
* <p><strong>Intersection:</strong>
*
* <ul>
* <li>{@link #intersectsLine} - Tests if a line segment intersects the geometry
* <li>{@link #intersectsTriangle} - Tests if a triangle intersects the geometry
* </ul>
*
* <p><strong>Relationship:</strong>
*
* <ul>
* <li>{@link #relate} - Determines spatial relationship with a bounding box (INSIDE, OUTSIDE, or
* CROSSES)
* <li>{@link #withinPoint} - Computes "within" relationship for a point
* <li>{@link #withinLine} - Computes "within" relationship for a line
* <li>{@link #withinTriangle} - Computes "within" relationship for a triangle
* </ul>
*
* <p>Bounding Box:
*
* <p>Every Component2D has an associated bounding box defined by:
*
* <ul>
* <li>{@link #getMinX()}, {@link #getMaxX()} - Horizontal bounds
* <li>{@link #getMinY()}, {@link #getMaxY()} - Vertical bounds
* </ul>
*
* <p><strong>Within Relationship:</strong>
*
* <p>The "within" relationship is used to determine if the query shape is contained within an
* indexed shape. The {@link WithinRelation} enum provides three possible outcomes:
*
* <ul>
* <li>{@link WithinRelation#CANDIDATE} - The shape might be within (requires further validation)
* <li>{@link WithinRelation#NOTWITHIN} - The shape is definitely not within
* <li>{@link WithinRelation#DISJOINT} - The shapes don't intersect at all
* </ul>
*
* <p>Performance Considerations:
*
* <ul>
* <li>Bounding box checks ({@link #getMinX()}, etc.) enable elimination of non-intersecting
* geometries
* <li>Methods accepting pre-computed bounding boxes (minX, maxX, minY, maxY) avoid redundant
* calculations
* <li>Default methods compute bounding boxes automatically for convenience
* <li>Implementations should optimize for the most common query patterns in their domain
* </ul>
*
* <p>Coordinate Systems:
*
* <p>Component2D works with encoded coordinate values:
*
* <ul>
* <li><strong>Geographic</strong> - X represents longitude, Y represents latitude (both encoded)
* <li><strong>Cartesian</strong> - X and Y represent planar coordinates
* </ul>
*
* <p>Utility Methods:
*
* <p>Component2D provides several static utility methods for common spatial operations:
*
* <ul>
* <li>{@link #disjoint} - Tests if two bounding boxes don't overlap
* <li>{@link #within} - Tests if one bounding box is fully contained within another
* <li>{@link #containsPoint} - Tests if a point is inside a rectangle
* <li>{@link #pointInTriangle} - Tests if a point is inside a triangle using winding order
* </ul>
*
* @lucene.internal
* @see Circle2D
* @see Polygon2D
* @see LatLonGeometry
* @see XYGeometry
*/
public interface Component2D {

Expand Down
Loading
Loading