|
| 1 | +import 'package:dart_jts/dart_jts.dart'; |
| 2 | +import 'package:nitrite/nitrite.dart' hide where; |
| 3 | +import 'package:nitrite_spatial/nitrite_spatial.dart'; |
| 4 | +import 'package:test/test.dart'; |
| 5 | + |
| 6 | +import 'base_test_loader.dart'; |
| 7 | +import 'test_utils.dart'; |
| 8 | + |
| 9 | +void main() { |
| 10 | + group(retry: 3, 'Spatial Intersects False Positive Test Suite', () { |
| 11 | + var reader = WKTReader(); |
| 12 | + |
| 13 | + setUp(() async { |
| 14 | + setUpLog(); |
| 15 | + await setUpNitriteTest(); |
| 16 | + }); |
| 17 | + |
| 18 | + tearDown(() async { |
| 19 | + await tearDownNitriteTest(); |
| 20 | + }); |
| 21 | + |
| 22 | + test('Test Intersects - Polygon and MultiPoint with overlapping bounding boxes but no intersection', () async { |
| 23 | + // This is the test case from the issue report |
| 24 | + // The polygon and multipoint have overlapping bounding boxes |
| 25 | + // but the geometries themselves do not intersect |
| 26 | + var polygon = reader.read('POLYGON ((40486.563 45036.319, 40084.108 44545.927, 39496.171 44938.774, 39889.018 45526.712, 40486.563 45036.319))') as Polygon; |
| 27 | + var multipoint = reader.read('MULTIPOINT ((40933.744 45423.275), (40395.332 45612.623), (40574.536 45576.665))') as MultiPoint; |
| 28 | + |
| 29 | + // Insert the multipoint into the collection |
| 30 | + final doc = createDocument("geometry", multipoint); |
| 31 | + await collection.insert([doc]); |
| 32 | + |
| 33 | + // Create spatial index |
| 34 | + await collection.createIndex(["geometry"], indexOptions(spatialIndex)); |
| 35 | + |
| 36 | + // Query for geometries that intersect the polygon |
| 37 | + final result = await collection |
| 38 | + .find(filter: where('geometry').intersects(polygon)) |
| 39 | + .toList(); |
| 40 | + |
| 41 | + // The multipoint does not intersect the polygon, so result should be empty |
| 42 | + expect(result.length, 0, reason: 'MultiPoint does not intersect Polygon, should return no results'); |
| 43 | + }); |
| 44 | + |
| 45 | + test('Test Intersects - Polygon and Point inside bounding box but outside geometry', () async { |
| 46 | + // Create a polygon and a point that is inside the bounding box |
| 47 | + // but outside the actual polygon |
| 48 | + var polygon = reader.read('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))') as Polygon; |
| 49 | + var pointOutside = reader.read('POINT (15 15)') as Point; // Outside bounding box |
| 50 | + var pointInsideBBoxButOutsidePolygon = reader.read('POINT (12 5)') as Point; // Would be in bbox if expanded |
| 51 | + |
| 52 | + // Actually, let's use a non-convex polygon to make this clearer |
| 53 | + // L-shaped polygon |
| 54 | + var lShapedPolygon = reader.read('POLYGON ((0 0, 10 0, 10 5, 5 5, 5 10, 0 10, 0 0))') as Polygon; |
| 55 | + var pointInBBoxButOutsidePolygon = reader.read('POINT (7 7)') as Point; // In bbox but outside L-shape |
| 56 | + |
| 57 | + // Insert the point |
| 58 | + final doc = createDocument("geometry", pointInBBoxButOutsidePolygon); |
| 59 | + await collection.insert([doc]); |
| 60 | + |
| 61 | + // Create spatial index |
| 62 | + await collection.createIndex(["geometry"], indexOptions(spatialIndex)); |
| 63 | + |
| 64 | + // Query for geometries that intersect the L-shaped polygon |
| 65 | + final result = await collection |
| 66 | + .find(filter: where('geometry').intersects(lShapedPolygon)) |
| 67 | + .toList(); |
| 68 | + |
| 69 | + // The point is inside the bounding box but outside the polygon |
| 70 | + expect(result.length, 0, reason: 'Point is in bounding box but outside polygon geometry'); |
| 71 | + }); |
| 72 | + |
| 73 | + test('Test Intersects - Actual intersection should return results', () async { |
| 74 | + // Create geometries that actually intersect |
| 75 | + var polygon = reader.read('POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))') as Polygon; |
| 76 | + var pointInside = reader.read('POINT (5 5)') as Point; |
| 77 | + var lineIntersecting = reader.read('LINESTRING (-5 5, 15 5)') as LineString; |
| 78 | + |
| 79 | + // Insert the geometries |
| 80 | + await collection.insert([ |
| 81 | + createDocument("id", 1).put("geometry", pointInside), |
| 82 | + createDocument("id", 2).put("geometry", lineIntersecting), |
| 83 | + ]); |
| 84 | + |
| 85 | + // Create spatial index |
| 86 | + await collection.createIndex(["geometry"], indexOptions(spatialIndex)); |
| 87 | + |
| 88 | + // Query for geometries that intersect the polygon |
| 89 | + final result = await collection |
| 90 | + .find(filter: where('geometry').intersects(polygon)) |
| 91 | + .toList(); |
| 92 | + |
| 93 | + // Both geometries intersect the polygon |
| 94 | + expect(result.length, 2, reason: 'Point and LineString both intersect the polygon'); |
| 95 | + }); |
| 96 | + |
| 97 | + test('Test Within - Point in bounding box but outside geometry', () async { |
| 98 | + // L-shaped polygon |
| 99 | + var lShapedPolygon = reader.read('POLYGON ((0 0, 10 0, 10 5, 5 5, 5 10, 0 10, 0 0))') as Polygon; |
| 100 | + var pointInBBoxButOutsidePolygon = reader.read('POINT (7 7)') as Point; |
| 101 | + |
| 102 | + // Insert the point |
| 103 | + final doc = createDocument("geometry", pointInBBoxButOutsidePolygon); |
| 104 | + await collection.insert([doc]); |
| 105 | + |
| 106 | + // Create spatial index |
| 107 | + await collection.createIndex(["geometry"], indexOptions(spatialIndex)); |
| 108 | + |
| 109 | + // Query for geometries within the L-shaped polygon |
| 110 | + final result = await collection |
| 111 | + .find(filter: where('geometry').within(lShapedPolygon)) |
| 112 | + .toList(); |
| 113 | + |
| 114 | + // The point is not within the polygon |
| 115 | + expect(result.length, 0, reason: 'Point is in bounding box but not within polygon geometry'); |
| 116 | + }); |
| 117 | + }); |
| 118 | +} |
0 commit comments