Polygon rejected as self-intersecting, but it does not self-intersect

Elasticsearch 8.15.2 is refusing to index a polygon which, as far as I can tell, is perfectly valid. Here is an image of the polygon on a map. Notice that it is just a trapezoid with nothing funny going on, and it does not cross the anti-meridian.

image

To reproduce, run the following cURL commands.

curl "localhost:9200/self_intersection?pretty" -X PUT --json '{
    "mappings": {"properties": {"shape": {"type": "geo_shape"}}}
}'
curl "localhost:9200/self_intersection/_doc/?pretty" --json '{
    "shape": {
        "type": "Polygon",
        "coordinates": [
            [
                [-30, 50],
                [160, 50],
                [160, 0],
                [0, 0],
                [-30, 50]
            ]
        ]
    }
}'
curl -X DELETE "localhost:9200/self_intersection"

The second cURL call produces this error:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "document_parsing_exception",
        "reason" : "[13:5] failed to parse field [shape] of type [geo_shape]"
      }
    ],
    "type" : "document_parsing_exception",
    "reason" : "[13:5] failed to parse field [shape] of type [geo_shape]",
    "caused_by" : {
      "type" : "illegal_argument_exception",
      "reason" : "Polygon self-intersection at lat=24.24242424242424 lon=160.0"
    }
  },
  "status" : 400
}

Is this a bug in Elasticsearch?

The problem is the orientation of the geojson polygon. This is what Elasticsearch is trying to do:

Your polygon is wide as it expands more than half of the world (max longitude - min longitude > 180) and therefore Elasticsearch needs to decide if the polygon crosses the dateline or not.

For doing so, it uses the orientation of the polygon's coordinates. In case of Geojson, the standard is very clear about it:

Polygon rings MUST follow the right-hand rule for orientation
(counterclockwise external rings, clockwise internal rings).

And therefore Elasticsearch tries to build a CCW polygon. The coordinates of your polygon are in clockwise order, therefore Elasticsearch tries to build the polygon across the dateline but it fails because in that case the polygon is self-intersecting.

If you build the polygon with points in counterclockwise order, then it succeeds:

curl "localhost:9200/self_intersection/_doc/?pretty" --json '{
    "shape": {
        "type": "Polygon",
        "coordinates": [
            [
                [-30, 50],
                [0, 0],
                [160, 0],
                [160, 50],
                [-30, 50]
            ]
        ]
    }
}'

In summary, if you want to index wide Geojson polygons, then you need to make sure the coordinates are in counterclockwise order.

I can't believe I missed that. Thanks very much!