Skip to content

Conversation

@JKamsker
Copy link
Collaborator

@JKamsker JKamsker commented Oct 5, 2025

This pull request introduces comprehensive support for spatial queries in LiteDB, including new spatial query methods, LINQ integration, and corresponding tests and benchmarks. The changes add spatial document models and generators for benchmarks, implement spatial query translation in the LINQ provider, define new BSON expression methods for spatial operations, and ensure spatial predicates are optimized during query planning.

Key changes include:

Spatial Query Support and Integration:

  • Added a new SpatialQueryBenchmarks class with multiple spatial query benchmarks (near, bounding box, polygon containment, route intersection) using new spatial document models and data generators. (SpatialQueryBenchmarks.cs, SpatialDocument.cs, SpatialDocumentGenerator.cs) [1] [2] [3]
  • Implemented a SpatialResolver to map spatial method calls in LINQ queries to corresponding database expressions, enabling LINQ queries to use spatial operators. (SpatialResolver.cs, LinqExpressionVisitor.cs) [1] [2]

Spatial Expression Methods:

  • Added new BSON expression methods for spatial operations including SPATIAL_NEAR, SPATIAL_WITHIN, SPATIAL_INTERSECTS, SPATIAL_CONTAINS_POINT, and bounding box intersection. These methods handle conversion from BSON to spatial types and call the appropriate spatial logic. (Document/Expression/Methods/Spatial.cs)

Query Optimization:

  • Updated query optimization logic to recognize and properly handle spatial predicates, ensuring they are included in the list of terms for optimization. (QueryOptimization.cs) [1] [2]

Testing:

  • Added comprehensive tests for spatial queries, including near queries, bounding box queries, polygon containment, intersection, GeoJSON round-trip, geohash updates, LINQ integration, and validation of coordinates. (SpatialTests.cs)

- Implemented GeoBoundingBox for spatial bounding box calculations.
- Added GeoJson for serialization and deserialization of GeoShape objects.
- Introduced GeoMath for geographical calculations including distance metrics.
- Created GeoShape as an abstract base class with derived types: GeoPoint, GeoLineString, and GeoPolygon.
- Added GeoValidation for coordinate validation.
- Developed Geometry utility class for geometric operations like point containment and intersection checks.
- Implemented LongitudeRange for handling longitude ranges with wrapping.
- Created Spatial class for spatial indexing and querying capabilities.
- Added SpatialIndexing for Morton code computation for spatial indexing.
- Introduced SpatialOptions for configuration of spatial operations.
…ial-patch1-and-spatial-patch3

Add tolerance-aware spatial helpers and expressions
@JKamsker
Copy link
Collaborator Author

JKamsker commented Oct 6, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting

Comment on lines 103 to 121
internal static GeoBoundingBox BoundingBoxForCircle(GeoPoint center, double radiusMeters)
{
if (center == null)
{
throw new ArgumentNullException(nameof(center));
}

if (radiusMeters < 0d)
{
throw new ArgumentOutOfRangeException(nameof(radiusMeters));
}

var angularDistance = radiusMeters / EarthRadiusMeters;

var minLat = ClampLatitude(center.Lat - angularDistance / DegToRad);
var maxLat = ClampLatitude(center.Lat + angularDistance / DegToRad);

var minLon = NormalizeLongitude(center.Lon - angularDistance / DegToRad);
var maxLon = NormalizeLongitude(center.Lon + angularDistance / DegToRad);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Compute lon span for near queries using latitude

The circle bounding box helper uses the same angular distance for latitude and longitude (GeoMath.BoundingBoxForCircle). Longitudinal distance shrinks with cos(latitude), so near the poles the computed minLon/maxLon will be far too narrow. Spatial.Near relies on this box both for index range construction and to pre‑filter candidates (queryBoundingBox.Contains(point)), so points that are actually within radiusMeters but lie just east/west of the center at high latitudes will be skipped before distance is checked, yielding false negatives. The longitude delta should be divided by Math.Cos(center.Lat) (with a clamp around the poles) before converting back to degrees.

Useful? React with 👍 / 👎.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Compute lon span for near queries using latitude

The circle bounding box helper uses the same angular distance for latitude and longitude (GeoMath.BoundingBoxForCircle). Longitudinal distance shrinks with cos(latitude), so near the poles the computed minLon/maxLon will be far too narrow. Spatial.Near relies on this box both for index range construction and to pre‑filter candidates (queryBoundingBox.Contains(point)), so points that are actually within radiusMeters but lie just east/west of the center at high latitudes will be skipped before distance is checked, yielding false negatives. The longitude delta should be divided by Math.Cos(center.Lat) (with a clamp around the poles) before converting back to degrees.

Useful? React with 👍 / 👎.

@codex please fix the problem

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

  • Adjusted the circle bounding box calculation to scale longitude span by the cosine of the center latitude and clamp the range near the poles, preventing high-latitude near queries from excluding valid points. LiteDB/Spatial/GeoMath.csL115-L138

Testing

  • ⚠️ not run (not requested)

View task →

* Add GeographicLib polar regression tests

* Merged regressions

* Improve spatial accuracy near poles (#47)
@JKamsker
Copy link
Collaborator Author

JKamsker commented Oct 9, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting

Comment on lines 32 to 37
[typeof(Regex)] = new RegexResolver(),
[typeof(ObjectId)] = new ObjectIdResolver(),
[typeof(String)] = new StringResolver(),
[typeof(Nullable)] = new NullableResolver()
[typeof(Nullable)] = new NullableResolver(),
[typeof(LiteDB.Spatial.Spatial)] = new SpatialResolver()
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add resolver for SpatialExpressions LINQ methods

The new SpatialResolver handles both Spatial and SpatialExpressions methods, but the resolver table only registers typeof(LiteDB.Spatial.Spatial). Calls written as SpatialExpressions.Near/Within/Intersects in LINQ will therefore hit the VisitMethodCall path with no resolver, where ParameterExpressionVisitor.Test will see a query parameter and the visitor throws NotSupportedException. Users who import LiteDB and use the SpatialExpressions helpers directly—rather than the Spatial API—will not be able to translate these queries. The resolver table should also register typeof(LiteDB.SpatialExpressions) so both entry points work as intended.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant