@@ -7,6 +7,384 @@ description: >-
77 accelerated by geo-spatial indexes
88archetype : default
99---
10+ ## Geo-spatial data representations
11+
12+ You can model geo-spatial information in different ways using the data types
13+ available in ArangoDB. The recommended way is to use objects with ** GeoJSON**
14+ geometry but you can also use ** longitude and latitude coordinate pairs**
15+ for points. Both models are supported by
16+ [ Geo-Spatial Indexes] ( ../../index-and-search/indexing/working-with-indexes/geo-spatial-indexes.md ) .
17+
18+ ### Coordinate pairs
19+
20+ Longitude and latitude coordinates are numeric values and can be stored in the
21+ following ways:
22+
23+ - Coordinates using an array with two numbers in ` [longitude, latitude] ` order,
24+ for example, in a user-chosen attribute called ` location ` :
25+
26+ ``` json
27+ {
28+ "location" : [ -73.983 , 40.764 ]
29+ }
30+ ```
31+
32+ - Coordinates using an array with two numbers in ` [latitude, longitude] ` order,
33+ for example, in a user-chosen attribute called ` location ` :
34+
35+ ``` json
36+ {
37+ "location" : [ 40.764 , -73.983 ]
38+ }
39+ ```
40+
41+ - Coordinates using two separate numeric attributes, for example, in two
42+ user-chosen attributes called ` lat ` and ` lng ` as sub-attributes of a ` location `
43+ attribute:
44+
45+ ``` json
46+ {
47+ "location" : {
48+ "lat" : 40.764 ,
49+ "lng" : -73.983
50+ }
51+ }
52+ ```
53+
54+ ### GeoJSON
55+
56+ GeoJSON is a geospatial data format based on JSON. It defines several different
57+ types of JSON objects and the way in which they can be combined to represent
58+ data about geographic shapes on the Earth surface.
59+
60+ Example of a document with a GeoJSON Point stored in a user-chosen attribute
61+ called ` location ` (with coordinates in ` [longitude, latitude] ` order):
62+
63+ ``` json
64+ {
65+ "location" : {
66+ "type" : " Point" ,
67+ "coordinates" : [ -73.983 , 40.764 ]
68+ }
69+ }
70+ ```
71+
72+ GeoJSON uses a geographic coordinate reference system,
73+ World Geodetic System 1984 (WGS 84), and units of decimal degrees.
74+
75+ Internally ArangoDB maps all coordinate pairs onto a unit sphere. Distances are
76+ projected onto a sphere with the Earth's * Volumetric mean radius* of * 6371
77+ km* . ArangoDB implements a useful subset of the GeoJSON format
78+ [ (RFC 7946)] ( https://tools.ietf.org/html/rfc7946 ) .
79+ Feature Objects and the GeometryCollection type are not supported.
80+ Supported geometry object types are:
81+
82+ - Point
83+ - MultiPoint
84+ - LineString
85+ - MultiLineString
86+ - Polygon
87+ - MultiPolygon
88+
89+ #### Point
90+
91+ A [ GeoJSON Point] ( https://tools.ietf.org/html/rfc7946#section-3.1.2 ) is a
92+ [ position] ( https://tools.ietf.org/html/rfc7946#section-3.1.1 ) comprised of
93+ a longitude and a latitude:
94+
95+ ``` json
96+ {
97+ "type" : " Point" ,
98+ "coordinates" : [100.0 , 0.0 ]
99+ }
100+ ```
101+
102+ #### MultiPoint
103+
104+ A [ GeoJSON MultiPoint] ( https://tools.ietf.org/html/rfc7946#section-3.1.7 ) is
105+ an array of positions:
106+
107+ ``` json
108+ {
109+ "type" : " MultiPoint" ,
110+ "coordinates" : [
111+ [100.0 , 0.0 ],
112+ [101.0 , 1.0 ]
113+ ]
114+ }
115+ ```
116+
117+ #### LineString
118+
119+ A [ GeoJSON LineString] ( https://tools.ietf.org/html/rfc7946#section-3.1.4 ) is
120+ an array of two or more positions:
121+
122+ ``` json
123+ {
124+ "type" : " LineString" ,
125+ "coordinates" : [
126+ [100.0 , 0.0 ],
127+ [101.0 , 1.0 ]
128+ ]
129+ }
130+ ```
131+
132+ #### MultiLineString
133+
134+ A [ GeoJSON MultiLineString] ( https://tools.ietf.org/html/rfc7946#section-3.1.5 ) is
135+ an array of LineString coordinate arrays:
136+
137+ ``` json
138+ {
139+ "type" : " MultiLineString" ,
140+ "coordinates" : [
141+ [
142+ [100.0 , 0.0 ],
143+ [101.0 , 1.0 ]
144+ ],
145+ [
146+ [102.0 , 2.0 ],
147+ [103.0 , 3.0 ]
148+ ]
149+ ]
150+ }
151+ ```
152+
153+ #### Polygon
154+
155+ A [ GeoJSON Polygon] ( https://tools.ietf.org/html/rfc7946#section-3.1.6 ) consists
156+ of a series of closed ` LineString ` objects (ring-like). These * Linear Ring*
157+ objects consist of four or more coordinate pairs with the first and last
158+ coordinate pair being equal. Coordinate pairs of a Polygon are an array of
159+ linear ring coordinate arrays. The first element in the array represents
160+ the exterior ring. Any subsequent elements represent interior rings
161+ (holes within the surface).
162+
163+ The orientation of the first linear ring is crucial: the right-hand-rule
164+ is applied, so that the area to the left of the path of the linear ring
165+ (when walking on the surface of the Earth) is considered to be the
166+ "interior" of the polygon. All other linear rings must be contained
167+ within this interior. According to the GeoJSON standard, the subsequent
168+ linear rings must be oriented following the right-hand-rule, too,
169+ that is, they must run ** clockwise** around the hole (viewed from
170+ above). However, ArangoDB is tolerant here (as suggested by the
171+ [ GeoJSON standard] ( https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6 ) ),
172+ all but the first linear ring are inverted if the orientation is wrong.
173+
174+ In the end, a point is considered to be in the interior of the polygon,
175+ if and only if one has to cross an odd number of linear rings to reach the
176+ exterior of the polygon prescribed by the first linear ring.
177+
178+ A number of additional rules apply (and are enforced by the GeoJSON
179+ parser):
180+
181+ - A polygon must contain at least one linear ring, i.e., it must not be
182+ empty.
183+ - A linear ring may not be empty, it needs at least three _ distinct_
184+ coordinate pairs, that is, at least 4 coordinate pairs (since the first and
185+ last must be the same).
186+ - No two edges of linear rings in the polygon must intersect, in
187+ particular, no linear ring may be self-intersecting.
188+ - Within the same linear ring, consecutive coordinate pairs may be the same,
189+ otherwise all coordinate pairs need to be distinct (except the first and last one).
190+ - Linear rings of a polygon must not share edges, but they may share coordinate pairs.
191+ - A linear ring defines two regions on the sphere. ArangoDB always
192+ interprets the region that lies to the left of the boundary ring (in
193+ the direction of its travel on the surface of the Earth) as the
194+ interior of the ring. This is in contrast to earlier versions of
195+ ArangoDB before 3.10, which always took the ** smaller** of the two
196+ regions as the interior. Therefore, from 3.10 on one can now have
197+ polygons whose outer ring encloses more than half the Earth's surface.
198+ - The interior rings must be contained in the (interior) of the outer ring.
199+ - Interior rings should follow the above rule for orientation
200+ (counterclockwise external rings, clockwise internal rings, interior
201+ always to the left of the line).
202+
203+ Here is an example with no holes:
204+
205+ ``` json
206+ {
207+ "type" : " Polygon" ,
208+ "coordinates" : [
209+ [
210+ [100.0 , 0.0 ],
211+ [101.0 , 0.0 ],
212+ [101.0 , 1.0 ],
213+ [100.0 , 1.0 ],
214+ [100.0 , 0.0 ]
215+ ]
216+ ]
217+ }
218+ ```
219+
220+ Here is an example with a hole:
221+
222+ ``` json
223+ {
224+ "type" : " Polygon" ,
225+ "coordinates" : [
226+ [
227+ [100.0 , 0.0 ],
228+ [101.0 , 0.0 ],
229+ [101.0 , 1.0 ],
230+ [100.0 , 1.0 ],
231+ [100.0 , 0.0 ]
232+ ],
233+ [
234+ [100.8 , 0.8 ],
235+ [100.8 , 0.2 ],
236+ [100.2 , 0.2 ],
237+ [100.2 , 0.8 ],
238+ [100.8 , 0.8 ]
239+ ]
240+ ]
241+ }
242+ ```
243+
244+ #### MultiPolygon
245+
246+ A [ GeoJSON MultiPolygon] ( https://tools.ietf.org/html/rfc7946#section-3.1.6 ) consists
247+ of multiple polygons. The "coordinates" member is an array of
248+ _ Polygon_ coordinate arrays. See [ above] ( #polygon ) for the rules and
249+ the meaning of polygons.
250+
251+ If the polygons in a MultiPolygon are disjoint, then a point is in the
252+ interior of the MultiPolygon if and only if it is
253+ contained in one of the polygons. If some polygon P2 in a MultiPolygon
254+ is contained in another polygon P1, then P2 is treated like a hole
255+ in P1 and containment of points is defined with the even-odd-crossings rule
256+ (see [ Polygon] ( #polygon ) ).
257+
258+ Additionally, the following rules apply and are enforced for
259+ MultiPolygons:
260+
261+ - No two edges in the linear rings of the polygons of a MultiPolygon
262+ may intersect.
263+ - Polygons in the same MultiPolygon may not share edges, but they may share
264+ coordinate pairs.
265+
266+ Example with two polygons, the second one with a hole:
267+
268+ ``` json
269+ {
270+ "type" : " MultiPolygon" ,
271+ "coordinates" : [
272+ [
273+ [
274+ [102.0 , 2.0 ],
275+ [103.0 , 2.0 ],
276+ [103.0 , 3.0 ],
277+ [102.0 , 3.0 ],
278+ [102.0 , 2.0 ]
279+ ]
280+ ],
281+ [
282+ [
283+ [100.0 , 0.0 ],
284+ [101.0 , 0.0 ],
285+ [101.0 , 1.0 ],
286+ [100.0 , 1.0 ],
287+ [100.0 , 0.0 ]
288+ ],
289+ [
290+ [100.2 , 0.2 ],
291+ [100.2 , 0.8 ],
292+ [100.8 , 0.8 ],
293+ [100.8 , 0.2 ],
294+ [100.2 , 0.2 ]
295+ ]
296+ ]
297+ ]
298+ }
299+ ```
300+
301+ ## GeoJSON interpretation
302+
303+ Note the following technical detail about GeoJSON: The
304+ [ GeoJSON standard, Section 3.1.1 Position] ( https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.1 )
305+ prescribes that lines are ** cartesian lines in cylindrical coordinates**
306+ (longitude/latitude). However, this definition is inconvenient in practice,
307+ since such lines are not geodesic on the surface of the Earth.
308+ Furthermore, the best available algorithms for geospatial computations on Earth
309+ typically use geodesic lines as the boundaries of polygons on Earth.
310+
311+ Therefore, ArangoDB uses the ** syntax of the GeoJSON** standard,
312+ but then interprets lines (and boundaries of polygons) as
313+ ** geodesic lines (pieces of great circles) on Earth** . This is a
314+ violation of the GeoJSON standard, but serving a practical purpose.
315+
316+ Note in particular that this can sometimes lead to unexpected results.
317+ Consider the following polygon (remember that GeoJSON has
318+ ** longitude before latitude** in coordinate pairs):
319+
320+ ``` json
321+ { "type" : " Polygon" , "coordinates" : [[
322+ [4 , 54 ], [4 , 47 ], [16 , 47 ], [16 , 54 ], [4 , 54 ]
323+ ]] }
324+ ```
325+
326+ ![ GeoJSON Polygon Geodesic] ( ../../../images/geojson-polygon-geodesic.webp )
327+
328+ It does not contain the point ` [10, 47] ` since the shortest path (geodesic)
329+ from ` [4, 47] ` to ` [16, 47] ` lies North relative to the parallel of latitude at
330+ 47 degrees. On the contrary, the polygon does contain the point ` [10, 54] ` as it
331+ lies South of the parallel of latitude at 54 degrees.
332+
333+ {{< info >}}
334+ ArangoDB version before 3.10 did an inconsistent special detection of "rectangle"
335+ polygons that later versions from 3.10 onward no longer do, see
336+ [ Legacy Polygons] ( ../../index-and-search/indexing/working-with-indexes/geo-spatial-indexes.md#legacy-polygons ) .
337+ {{< /info >}}
338+
339+ Furthermore, there is an issue with the interpretation of linear rings
340+ (boundaries of polygons) according to
341+ [ GeoJSON standard, Section 3.1.6 Polygon] ( https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6 ) .
342+ This section states explicitly:
343+
344+ > A linear ring MUST follow the right-hand rule with respect to the
345+ > area it bounds, i.e., exterior rings are counter-clockwise, and
346+ > holes are clockwise.
347+
348+ This rather misleading phrase means that when a linear ring is used as
349+ the boundary of a polygon, the "interior" of the polygon lies ** to the left**
350+ of the boundary when one travels on the surface of the Earth and
351+ along the linear ring. For
352+ example, the polygon below travels ** counter-clockwise** around the point
353+ ` [10, 50] ` , and thus the interior of the polygon contains this point and
354+ its surroundings, but not, for example, the North Pole and the South
355+ Pole.
356+
357+ ``` json
358+ { "type" : " Polygon" , "coordinates" : [[
359+ [4 , 54 ], [4 , 47 ], [16 , 47 ], [16 , 54 ], [4 , 54 ]
360+ ]] }
361+ ```
362+
363+ ![ GeoJSON Polygon Counter-clockwise] ( ../../../images/geojson-polygon-ccw.webp )
364+
365+ On the other hand, the following polygon travels ** clockwise** around the point
366+ ` [10, 50] ` , and thus its "interior" does not contain ` [10, 50] ` , but does
367+ contain the North Pole and the South Pole:
368+
369+ ``` json
370+ { "type" : " Polygon" , "coordinates" : [[
371+ [4 , 54 ], [16 , 54 ], [16 , 47 ], [4 , 47 ], [4 , 54 ]
372+ ]] }
373+ ```
374+
375+ ![ GeoJSON Polygon Clockwise] ( ../../../images/geojson-polygon-cw.webp )
376+
377+ Remember that the "interior" is to the left of the given
378+ linear ring, so this second polygon is basically the complement on Earth
379+ of the previous polygon!
380+
381+ ArangoDB versions before 3.10 did not follow this rule and always took the
382+ "smaller" connected component of the surface as the "interior" of the polygon.
383+ This made it impossible to specify polygons which covered more than half of the
384+ sphere. From version 3.10 onward, ArangoDB recognizes this correctly.
385+ See [ Legacy Polygons] ( ../../index-and-search/indexing/working-with-indexes/geo-spatial-indexes.md#legacy-polygons )
386+ for how to deal with this issue.
387+
10388## Geo utility functions
11389
12390The following helper functions ** can** use geo indexes, but do not have to in
0 commit comments