17
17
import org .elasticsearch .common .geo .GeometryNormalizer ;
18
18
import org .elasticsearch .common .geo .Orientation ;
19
19
import org .elasticsearch .geo .GeometryTestUtils ;
20
+ import org .elasticsearch .geometry .Circle ;
20
21
import org .elasticsearch .geometry .Geometry ;
22
+ import org .elasticsearch .geometry .GeometryCollection ;
23
+ import org .elasticsearch .geometry .GeometryVisitor ;
21
24
import org .elasticsearch .geometry .LinearRing ;
25
+ import org .elasticsearch .geometry .MultiLine ;
22
26
import org .elasticsearch .geometry .MultiPoint ;
27
+ import org .elasticsearch .geometry .MultiPolygon ;
28
+ import org .elasticsearch .geometry .Rectangle ;
23
29
import org .elasticsearch .test .ESTestCase ;
24
30
import org .elasticsearch .xpack .spatial .util .GeoTestUtils ;
25
31
@@ -135,6 +141,18 @@ public void testContainedPolygons() throws Exception {
135
141
}
136
142
}
137
143
144
+ /** Explicitly test failure found in <a href="https://github.com/elastic/elasticsearch/issues/98063">#98063</a> */
145
+ public void testOriginPointInMultipoint () throws Exception {
146
+ ArrayList <org .elasticsearch .geometry .Point > points = new ArrayList <>();
147
+ points .add (new org .elasticsearch .geometry .Point (0.0 , 0.0 ));
148
+ points .add (new org .elasticsearch .geometry .Point (0.0 , 0.0 ));
149
+ points .add (new org .elasticsearch .geometry .Point (0.0 , 1.401298464324817E-45 ));
150
+ Geometry geometry = new MultiPoint (points );
151
+ GeoShapeValues .GeoShapeValue geoShapeValue = GeoTestUtils .geoShapeValue (geometry );
152
+ GeometryDocValueReader reader = GeoTestUtils .geometryDocValueReader (geometry , CoordinateEncoder .GEO );
153
+ doTestShape (geometry , geoShapeValue , reader , new Point (0 , 0 ));
154
+ }
155
+
138
156
private <T extends LatLonGeometry > void doTestShapes (Supplier <T > supplier ) throws Exception {
139
157
Geometry geometry = GeometryNormalizer .apply (Orientation .CCW , GeometryTestUtils .randomGeometryWithoutCircle (0 , false ));
140
158
GeoShapeValues .GeoShapeValue geoShapeValue = GeoTestUtils .geoShapeValue (geometry );
@@ -161,18 +179,7 @@ private void doTestShape(Geometry geometry, GeometryDocValueReader reader, LatLo
161
179
162
180
private boolean isIdenticalPoint (Geometry geometry , LatLonGeometry latLonGeometry ) {
163
181
if (latLonGeometry instanceof Point latLonPoint ) {
164
- if (geometry instanceof org .elasticsearch .geometry .Point point ) {
165
- return encodeLatitude (point .getLat ()) == encodeLatitude (latLonPoint .getLat ())
166
- && encodeLongitude (point .getLon ()) == encodeLongitude (latLonPoint .getLon ());
167
- } else if (geometry instanceof org .elasticsearch .geometry .Line line ) {
168
- for (int i = 0 ; i < line .length (); i ++) {
169
- if (encodeLatitude (line .getLat (i )) != encodeLatitude (latLonPoint .getLat ())
170
- || encodeLongitude (line .getLon (i )) != encodeLongitude (latLonPoint .getLon ())) {
171
- return false ;
172
- }
173
- }
174
- return true ;
175
- }
182
+ return geometry .visit (new TestIdenticalPointVisitor (latLonPoint ));
176
183
}
177
184
return false ;
178
185
}
@@ -280,4 +287,113 @@ private double quantizeLat(double lat) {
280
287
private double quantizeLon (double lon ) {
281
288
return decodeLongitude (encodeLongitude (lon ));
282
289
}
290
+
291
+ /**
292
+ * This visitor returns false if any point in the geometry is not identical to the provided point.
293
+ * Identical means that the encoded lat and lon values are the same.
294
+ */
295
+ private static class TestIdenticalPointVisitor implements GeometryVisitor <Boolean , RuntimeException > {
296
+ private final int encodedLat ;
297
+ private final int encodedLon ;
298
+
299
+ private TestIdenticalPointVisitor (Point latLonPoint ) {
300
+ encodedLat = encodeLatitude (latLonPoint .getLat ());
301
+ encodedLon = encodeLongitude (latLonPoint .getLon ());
302
+ }
303
+
304
+ private boolean isIdenticalPoint (double lat , double lon ) {
305
+ return encodeLatitude (lat ) == encodedLat && encodeLongitude (lon ) == encodedLon ;
306
+ }
307
+
308
+ @ Override
309
+ public Boolean visit (Circle circle ) {
310
+ if (circle .getRadiusMeters () == 0 ) {
311
+ return isIdenticalPoint (circle .getLat (), circle .getLon ());
312
+ }
313
+ return false ;
314
+ }
315
+
316
+ @ Override
317
+ public Boolean visit (GeometryCollection <?> collection ) {
318
+ for (Geometry shape : collection ) {
319
+ if (shape .visit (this ) == false ) {
320
+ return false ;
321
+ }
322
+ }
323
+ return collection .size () > 0 ;
324
+ }
325
+
326
+ @ Override
327
+ public Boolean visit (org .elasticsearch .geometry .Line line ) {
328
+ for (int i = 0 ; i < line .length (); i ++) {
329
+ if (isIdenticalPoint (line .getLat (i ), line .getLon (i )) == false ) {
330
+ return false ;
331
+ }
332
+ }
333
+ return line .length () > 0 ;
334
+ }
335
+
336
+ @ Override
337
+ public Boolean visit (LinearRing ring ) {
338
+ return visit ((org .elasticsearch .geometry .Line ) ring );
339
+ }
340
+
341
+ @ Override
342
+ public Boolean visit (MultiLine multiLine ) {
343
+ for (org .elasticsearch .geometry .Line line : multiLine ) {
344
+ if (visit (line ) == false ) {
345
+ return false ;
346
+ }
347
+ }
348
+ return multiLine .size () > 0 ;
349
+ }
350
+
351
+ @ Override
352
+ public Boolean visit (MultiPoint multiPoint ) {
353
+ for (org .elasticsearch .geometry .Point point : multiPoint ) {
354
+ if (visit (point ) == false ) {
355
+ return false ;
356
+ }
357
+ }
358
+ return multiPoint .size () > 0 ;
359
+ }
360
+
361
+ @ Override
362
+ public Boolean visit (MultiPolygon multiPolygon ) {
363
+ for (org .elasticsearch .geometry .Polygon polygon : multiPolygon ) {
364
+ if (visit (polygon ) == false ) {
365
+ return false ;
366
+ }
367
+ }
368
+ return multiPolygon .size () > 0 ;
369
+ }
370
+
371
+ @ Override
372
+ public Boolean visit (org .elasticsearch .geometry .Point point ) {
373
+ return isIdenticalPoint (point .getLat (), point .getLon ());
374
+ }
375
+
376
+ @ Override
377
+ public Boolean visit (org .elasticsearch .geometry .Polygon polygon ) {
378
+ if (visit (polygon .getPolygon ()) == false ) {
379
+ return false ;
380
+ }
381
+ for (int i = 0 ; i < polygon .getNumberOfHoles (); i ++) {
382
+ LinearRing hole = polygon .getHole (i );
383
+ if (visit (hole ) == false ) {
384
+ return false ;
385
+ }
386
+ }
387
+ return polygon .getPolygon ().length () > 0 ;
388
+ }
389
+
390
+ @ Override
391
+ public Boolean visit (Rectangle rectangle ) {
392
+ int eMinX = encodeLongitude (rectangle .getMinX ());
393
+ int eMaxX = encodeLongitude (rectangle .getMaxX ());
394
+ int eMinY = encodeLatitude (rectangle .getMinY ());
395
+ int eMaxY = encodeLatitude (rectangle .getMaxY ());
396
+ return eMinX == eMaxX && eMinY == eMaxY && isIdenticalPoint (rectangle .getMinLat (), rectangle .getMinLon ());
397
+ }
398
+ }
283
399
}
0 commit comments