@@ -2158,4 +2158,191 @@ public function testSpatialDistanceInMeter(): void
21582158 $ database ->deleteCollection ($ collectionName );
21592159 }
21602160 }
2161+
2162+ public function testSpatialDistanceInMeterForMultiDimensionGeometry (): void
2163+ {
2164+ /** @var Database $database */
2165+ $ database = static ::getDatabase ();
2166+ if (!$ database ->getAdapter ()->getSupportForSpatialAttributes ()) {
2167+ $ this ->markTestSkipped ('Adapter does not support spatial attributes ' );
2168+ }
2169+
2170+ if (!$ database ->getAdapter ()->getSupportForDistanceBetweenMultiDimensionGeometryInMeters ()) {
2171+ $ this ->markTestSkipped ('Adapter does not support spatial distance(in meter) for multidimension ' );
2172+ }
2173+
2174+ $ multiCollection = 'spatial_distance_meters_multi_ ' ;
2175+ try {
2176+ $ database ->createCollection ($ multiCollection );
2177+
2178+ // Create spatial attributes
2179+ $ this ->assertEquals (true , $ database ->createAttribute ($ multiCollection , 'loc ' , Database::VAR_POINT , 0 , true ));
2180+ $ this ->assertEquals (true , $ database ->createAttribute ($ multiCollection , 'line ' , Database::VAR_LINESTRING , 0 , true ));
2181+ $ this ->assertEquals (true , $ database ->createAttribute ($ multiCollection , 'poly ' , Database::VAR_POLYGON , 0 , true ));
2182+
2183+ // Create indexes
2184+ $ this ->assertEquals (true , $ database ->createIndex ($ multiCollection , 'idx_loc ' , Database::INDEX_SPATIAL , ['loc ' ]));
2185+ $ this ->assertEquals (true , $ database ->createIndex ($ multiCollection , 'idx_line ' , Database::INDEX_SPATIAL , ['line ' ]));
2186+ $ this ->assertEquals (true , $ database ->createIndex ($ multiCollection , 'idx_poly ' , Database::INDEX_SPATIAL , ['poly ' ]));
2187+
2188+ // Geometry sets: near origin and far east
2189+ $ docNear = $ database ->createDocument ($ multiCollection , new Document ([
2190+ '$id ' => 'near ' ,
2191+ 'loc ' => [0.0000 , 0.0000 ],
2192+ 'line ' => [[0.0000 , 0.0000 ], [0.0010 , 0.0000 ]], // ~111m
2193+ 'poly ' => [[
2194+ [-0.0010 , -0.0010 ],
2195+ [-0.0010 , 0.0010 ],
2196+ [ 0.0010 , 0.0010 ],
2197+ [ 0.0010 , -0.0010 ],
2198+ [-0.0010 , -0.0010 ] // closed
2199+ ]],
2200+ '$permissions ' => [Permission::read (Role::any ()), Permission::update (Role::any ())]
2201+ ]));
2202+
2203+ $ docFar = $ database ->createDocument ($ multiCollection , new Document ([
2204+ '$id ' => 'far ' ,
2205+ 'loc ' => [0.2000 , 0.0000 ], // ~22 km east
2206+ 'line ' => [[0.2000 , 0.0000 ], [0.2020 , 0.0000 ]],
2207+ 'poly ' => [[
2208+ [0.1980 , -0.0020 ],
2209+ [0.1980 , 0.0020 ],
2210+ [0.2020 , 0.0020 ],
2211+ [0.2020 , -0.0020 ],
2212+ [0.1980 , -0.0020 ] // closed
2213+ ]],
2214+ '$permissions ' => [Permission::read (Role::any ()), Permission::update (Role::any ())]
2215+ ]));
2216+
2217+ $ this ->assertInstanceOf (Document::class, $ docNear );
2218+ $ this ->assertInstanceOf (Document::class, $ docFar );
2219+
2220+ // polygon vs polygon (~1 km from near, ~22 km from far)
2221+ $ polyPolyWithin3km = $ database ->find ($ multiCollection , [
2222+ Query::distanceLessThan ('poly ' , [[
2223+ [0.0080 , -0.0010 ],
2224+ [0.0080 , 0.0010 ],
2225+ [0.0110 , 0.0010 ],
2226+ [0.0110 , -0.0010 ],
2227+ [0.0080 , -0.0010 ] // closed
2228+ ]], 3000 , true )
2229+ ], Database::PERMISSION_READ );
2230+ $ this ->assertCount (1 , $ polyPolyWithin3km );
2231+ $ this ->assertEquals ('near ' , $ polyPolyWithin3km [0 ]->getId ());
2232+
2233+ $ polyPolyGreater3km = $ database ->find ($ multiCollection , [
2234+ Query::distanceGreaterThan ('poly ' , [[
2235+ [0.0080 , -0.0010 ],
2236+ [0.0080 , 0.0010 ],
2237+ [0.0110 , 0.0010 ],
2238+ [0.0110 , -0.0010 ],
2239+ [0.0080 , -0.0010 ] // closed
2240+ ]], 3000 , true )
2241+ ], Database::PERMISSION_READ );
2242+ $ this ->assertCount (1 , $ polyPolyGreater3km );
2243+ $ this ->assertEquals ('far ' , $ polyPolyGreater3km [0 ]->getId ());
2244+
2245+ // point vs polygon (~0 km near, ~22 km far)
2246+ $ ptPolyWithin500 = $ database ->find ($ multiCollection , [
2247+ Query::distanceLessThan ('loc ' , [[
2248+ [-0.0010 , -0.0010 ],
2249+ [-0.0010 , 0.0020 ],
2250+ [ 0.0020 , 0.0020 ],
2251+ [-0.0010 , -0.0010 ]
2252+ ]], 500 , true )
2253+ ], Database::PERMISSION_READ );
2254+ $ this ->assertCount (1 , $ ptPolyWithin500 );
2255+ $ this ->assertEquals ('near ' , $ ptPolyWithin500 [0 ]->getId ());
2256+
2257+ $ ptPolyGreater500 = $ database ->find ($ multiCollection , [
2258+ Query::distanceGreaterThan ('loc ' , [[
2259+ [-0.0010 , -0.0010 ],
2260+ [-0.0010 , 0.0020 ],
2261+ [ 0.0020 , 0.0020 ],
2262+ [-0.0010 , -0.0010 ]
2263+ ]], 500 , true )
2264+ ], Database::PERMISSION_READ );
2265+ $ this ->assertCount (1 , $ ptPolyGreater500 );
2266+ $ this ->assertEquals ('far ' , $ ptPolyGreater500 [0 ]->getId ());
2267+
2268+ // Zero-distance checks
2269+ $ lineEqualZero = $ database ->find ($ multiCollection , [
2270+ Query::distanceEqual ('line ' , [[0.0000 , 0.0000 ], [0.0010 , 0.0000 ]], 0 , true )
2271+ ], Database::PERMISSION_READ );
2272+ $ this ->assertNotEmpty ($ lineEqualZero );
2273+ $ this ->assertEquals ('near ' , $ lineEqualZero [0 ]->getId ());
2274+
2275+ $ polyEqualZero = $ database ->find ($ multiCollection , [
2276+ Query::distanceEqual ('poly ' , [[
2277+ [-0.0010 , -0.0010 ],
2278+ [-0.0010 , 0.0010 ],
2279+ [ 0.0010 , 0.0010 ],
2280+ [ 0.0010 , -0.0010 ],
2281+ [-0.0010 , -0.0010 ]
2282+ ]], 0 , true )
2283+ ], Database::PERMISSION_READ );
2284+ $ this ->assertNotEmpty ($ polyEqualZero );
2285+ $ this ->assertEquals ('near ' , $ polyEqualZero [0 ]->getId ());
2286+
2287+ } finally {
2288+ $ database ->deleteCollection ($ multiCollection );
2289+ }
2290+ }
2291+
2292+ public function testSpatialDistanceInMeterError (): void
2293+ {
2294+ /** @var Database $database */
2295+ $ database = static ::getDatabase ();
2296+ if (!$ database ->getAdapter ()->getSupportForSpatialAttributes ()) {
2297+ $ this ->markTestSkipped ('Adapter does not support spatial attributes ' );
2298+ }
2299+
2300+ if ($ database ->getAdapter ()->getSupportForDistanceBetweenMultiDimensionGeometryInMeters ()) {
2301+ $ this ->markTestSkipped ('Adapter supports spatial distance (in meter) for multidimension geometries ' );
2302+ }
2303+
2304+ $ collection = 'spatial_distance_error_test ' ;
2305+ $ database ->createCollection ($ collection );
2306+ $ this ->assertEquals (true , $ database ->createAttribute ($ collection , 'loc ' , Database::VAR_POINT , 0 , true ));
2307+ $ this ->assertEquals (true , $ database ->createAttribute ($ collection , 'line ' , Database::VAR_LINESTRING , 0 , true ));
2308+ $ this ->assertEquals (true , $ database ->createAttribute ($ collection , 'poly ' , Database::VAR_POLYGON , 0 , true ));
2309+
2310+ $ doc = $ database ->createDocument ($ collection , new Document ([
2311+ '$id ' => 'doc1 ' ,
2312+ 'loc ' => [0.0 , 0.0 ],
2313+ 'line ' => [[0.0 , 0.0 ], [0.001 , 0.0 ]],
2314+ 'poly ' => [[[ -0.001 , -0.001 ], [ -0.001 , 0.001 ], [ 0.001 , 0.001 ], [ -0.001 , -0.001 ]]],
2315+ '$permissions ' => []
2316+ ]));
2317+ $ this ->assertInstanceOf (Document::class, $ doc );
2318+
2319+ // Invalid geometry pairs
2320+ $ cases = [
2321+ ['attr ' => 'line ' , 'geom ' => [0.002 , 0.0 ], 'expected ' => ['linestring ' , 'point ' ]],
2322+ ['attr ' => 'poly ' , 'geom ' => [0.002 , 0.0 ], 'expected ' => ['polygon ' , 'point ' ]],
2323+ ['attr ' => 'loc ' , 'geom ' => [[0.0 , 0.0 ], [0.001 , 0.001 ]], 'expected ' => ['point ' , 'linestring ' ]],
2324+ ['attr ' => 'poly ' , 'geom ' => [[0.0 , 0.0 ], [0.001 , 0.001 ]], 'expected ' => ['polygon ' , 'linestring ' ]],
2325+ ['attr ' => 'loc ' , 'geom ' => [[[0.0 , 0.0 ], [0.001 , 0.0 ], [0.001 , 0.001 ], [0.0 , 0.0 ]]], 'expected ' => ['point ' , 'polygon ' ]],
2326+ ['attr ' => 'line ' , 'geom ' => [[[0.0 , 0.0 ], [0.001 , 0.0 ], [0.001 , 0.001 ], [0.0 , 0.0 ]]], 'expected ' => ['linestring ' , 'polygon ' ]],
2327+ ['attr ' => 'poly ' , 'geom ' => [[[0.002 , -0.001 ], [0.002 , 0.001 ], [0.004 , 0.001 ], [0.002 , -0.001 ]]], 'expected ' => ['polygon ' , 'polygon ' ]],
2328+ ['attr ' => 'line ' , 'geom ' => [[0.002 , 0.0 ], [0.003 , 0.0 ]], 'expected ' => ['linestring ' , 'linestring ' ]],
2329+ ];
2330+
2331+ foreach ($ cases as $ case ) {
2332+ try {
2333+ $ database ->find ($ collection , [
2334+ Query::distanceLessThan ($ case ['attr ' ], $ case ['geom ' ], 1000 , true )
2335+ ]);
2336+ $ this ->fail ('Expected Exception not thrown for ' . implode (' vs ' , $ case ['expected ' ]));
2337+ } catch (\Exception $ e ) {
2338+ $ this ->assertInstanceOf (\Exception::class, $ e );
2339+
2340+ // Validate exception message contains correct type names
2341+ $ msg = strtolower ($ e ->getMessage ());
2342+ var_dump ($ msg );
2343+ $ this ->assertStringContainsString ($ case ['expected ' ][0 ], $ msg , 'Attr type missing in exception ' );
2344+ $ this ->assertStringContainsString ($ case ['expected ' ][1 ], $ msg , 'Geom type missing in exception ' );
2345+ }
2346+ }
2347+ }
21612348}
0 commit comments