GeoWithinFilterBean returning inaccurate results

When using the GeoWithinFilterBean, the returned results aren’t restricted to inside the given polygon, specifically at the top and bottom. Here’s an image depicting what’s happening, blue dots are those returned by the query and red dots are those returned by the negated query. The blue box is where the limits of the polygon are.

Here’s the filter that the query is running:

location: [{
  geometry: {
    coordinates: [[
        [0.849607, 43.447224],
        [23.23242, 43.447224],
        [23.23242, 49.873922],
        [0.849607, 49.873922],
        [0.849607, 43.447224]
    ]],
    type: "Polygon"
  }
  negated: false
  objectType: "GeoWithinFilterBean"
  propertyIdentifier: "location"
}]

I also know that it’s not an issue with rendering the points because I manually checked the returned data and the points were outside the polygon range. What could be causing this?

  1. Are you able to share one of the DataObjects which falls outside this bbox but is included by the GeoWithinFilter?

  2. Which database is backing your DataObjectService?

I’ll also note here the difference between LEAF’s two geospatial filters:

GeoIntersectsFilterBean: Filter for DataObjects whose IGeometry property shares any space with a given Polygon/MultiPolygon.

GeoWithinFilterBean: Filter for DataObjects whose IGeometry property is completely inside a given Polygon/MultiPolygon.

For Point fields, both filters’ behavior is effectively identical. However, for LineString or Polygon field types, the boundary overlap condition will result in objects being included or excluded (respectively) from the bbox.

Edit: I initially typed these backwards, apologies for any confusion!

location: {
  coordinates: [
    11.84,
    50.1588,
    9433.56
  ],
  type: "Point"
}

This is the location field of one of the DataObjects that is returned by the query. And the DataObjectService is backed by MongoDB.

I managed to mitigate the behavior by making it so that no two points that formed an edge were further than 10 degrees apart and interpolating edges that were with in-between points. I don’t know if this is intended but I found that making longer edges just a set of smaller edges in a row fixed the problem.

Hi Nick,

We agree that this is not expected behavior, but it is indeed the response from MongoDB. I created BeanMetadata and a DataObject with your specified Point. I issued a query using LEAF’s Java API:

        Polygon bbox = Polygon.newBuilder()
                .withExterior(List.of(
                        Position.of(0.849607, 43.447224),
                        Position.of(23.23242, 43.447224),
                        Position.of(23.23242, 49.873922),
                        Position.of(0.849607, 49.873922),
                        Position.of(0.849607, 43.447224)
                ))
                .build();
        DataObjectQuery query1 = dataObjectQuery(types("GeoType"), geoWithin("location", bbox));
        List<DataObject> results1 = dataObjectService.load(query1, Context.makeSystemContext());

And the DataObject with your outside Point coordinate was unexpectedly returned as a result. Changing its latitude to 50.5 places it sufficiently outside the bounding Polygon that it is no longer returned.

I directly queried the MongoDB database with the equivalent Mongo query:

{
    "$and": [
      {
        "location": {
          "$geoWithin": {
            "$geometry": {
              "type": "Polygon",
              "coordinates": [
                [
                    [ 0.849607, 43.447224],
                    [23.23242,  43.447224],
                    [23.23242,  49.873922],
                    [ 0.849607, 49.873922],
                    [ 0.849607, 43.447224]
                ]
              ]
            }
          }
        }
      },
      {
        "type": {
          "$in": [
            "GeoType"
          ]
        }
      }
    ]
  }

And, sure enough, Mongo returns this DataObject, which is unquestionably outside that bounding rectangular Polygon. I’ve confirmed the same results whether the location field is indexed or not (LEAF creates a 2dsphere index). And I have confirmed that you specified the positions of the bounding Polygon in the correct counter-clockwise order. I tested with MongoDB 4.0 and 4.2.

I tried your mitigation technique - adding additional points to the bounding Polygon - and directly queried MongoDB:

              "coordinates": [
                [
                    [ 0.849607, 43.447224],
                    [10.0,      43.447224],
                    [20.0,      43.447224],
                    [23.23242,  43.447224],
                    [23.23242,  49.873922],
                    [20.0,      49.873922],
                    [10.0,      49.873922],
                    [ 0.849607, 49.873922],
                    [ 0.849607, 43.447224]
                ]
              ]

…and now your outside-Point is correctly excluded!

LEAF relies on the database for geospatial querying, and in this case - as best as we’re able to tell - it appears as if Mongo’s $geoWithin query operator is inaccurate with some edge cases.

I switched to a SQL-backed LEAF data service, and - with the original code - your outside Point is correctly excluded.

We’ll investigate further to see if we can come up with a more satisfactory explanation for MongoDB’s behavior here, but in the meantime it looks like its accuracy may be related to the sparseness of the bounding Polygon, and your mitigation - defining additional positions when covering large areas, even for a rectangle(!) - is advised. Or, if it meets your application’s requirements, you may wish to use a SQL database backed DataObjectService (eg: PostgreSQL) instead.

3 Likes