summaryrefslogtreecommitdiff
path: root/docs/ref/contrib/gis/geos.txt
blob: fda1b5cc3df75a89a200a6048fa0e625f5fb017d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
========
GEOS API
========

.. module:: django.contrib.gis.geos
    :synopsis: GeoDjango's high-level interface to the GEOS library.

Background
==========

What is GEOS?
-------------

`GEOS`__ stands for **Geometry Engine - Open Source**,
and is a C++ library, ported from the  `Java Topology Suite`__.  GEOS
implements the OpenGIS `Simple Features for SQL`__ spatial predicate functions
and spatial operators. GEOS, now an OSGeo project, was initially developed and
maintained by `Refractions Research`__ of Victoria, Canada.

__ https://trac.osgeo.org/geos/
__ https://sourceforge.net/projects/jts-topo-suite/
__ https://www.opengeospatial.org/standards/sfs
__ http://www.refractions.net/

Features
--------

GeoDjango implements a high-level Python wrapper for the GEOS library, its
features include:

* A BSD-licensed interface to the GEOS geometry routines, implemented purely
  in Python using ``ctypes``.
* Loosely-coupled to GeoDjango.  For example, :class:`GEOSGeometry` objects
  may be used outside of a Django project/application.  In other words,
  no need to have ``DJANGO_SETTINGS_MODULE`` set or use a database, etc.
* Mutability: :class:`GEOSGeometry` objects may be modified.
* Cross-platform and tested; compatible with Windows, Linux, Solaris, and
  macOS platforms.

.. _geos-tutorial:

Tutorial
========

This section contains a brief introduction and tutorial to using
:class:`GEOSGeometry` objects.

Creating a Geometry
-------------------

:class:`GEOSGeometry` objects may be created in a few ways.  The first is
to simply instantiate the object on some spatial input -- the following
are examples of creating the same geometry from WKT, HEX, WKB, and GeoJSON::

    >>> from django.contrib.gis.geos import GEOSGeometry
    >>> pnt = GEOSGeometry('POINT(5 23)') # WKT
    >>> pnt = GEOSGeometry('010100000000000000000014400000000000003740') # HEX
    >>> pnt = GEOSGeometry(buffer('\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x007@'))
    >>> pnt = GEOSGeometry('{ "type": "Point", "coordinates": [ 5.000000, 23.000000 ] }') # GeoJSON

Another option is to use the constructor for the specific geometry type
that you wish to create.  For example, a :class:`Point` object may be
created by passing in the X and Y coordinates into its constructor::

    >>> from django.contrib.gis.geos import Point
    >>> pnt = Point(5, 23)

All these constructors take the keyword argument ``srid``. For example::

    >>> from django.contrib.gis.geos import GEOSGeometry, LineString, Point
    >>> print(GEOSGeometry('POINT (0 0)', srid=4326))
    SRID=4326;POINT (0 0)
    >>> print(LineString((0, 0), (1, 1), srid=4326))
    SRID=4326;LINESTRING (0 0, 1 1)
    >>> print(Point(0, 0, srid=32140))
    SRID=32140;POINT (0 0)

Finally, there is the :func:`fromfile` factory method which returns a
:class:`GEOSGeometry` object from a file::

    >>> from django.contrib.gis.geos import fromfile
    >>> pnt = fromfile('/path/to/pnt.wkt')
    >>> pnt = fromfile(open('/path/to/pnt.wkt'))

.. _geos-exceptions-in-logfile:

.. admonition:: My logs are filled with GEOS-related errors

    You find many ``TypeError`` or ``AttributeError`` exceptions filling your
    Web server's log files. This generally means that you are creating GEOS
    objects at the top level of some of your Python modules. Then, due to a race
    condition in the garbage collector, your module is garbage collected before
    the GEOS object. To prevent this, create :class:`GEOSGeometry` objects
    inside the local scope of your functions/methods.

Geometries are Pythonic
-----------------------
:class:`GEOSGeometry` objects are 'Pythonic', in other words components may
be accessed, modified, and iterated over using standard Python conventions.
For example, you can iterate over the coordinates in a :class:`Point`::

    >>> pnt = Point(5, 23)
    >>> [coord for coord in pnt]
    [5.0, 23.0]

With any geometry object, the :attr:`GEOSGeometry.coords` property
may be used to get the geometry coordinates as a Python tuple::

    >>> pnt.coords
    (5.0, 23.0)

You can get/set geometry components using standard Python indexing
techniques.  However, what is returned depends on the geometry type
of the object.  For example, indexing on a :class:`LineString`
returns a coordinate tuple::

    >>> from django.contrib.gis.geos import LineString
    >>> line = LineString((0, 0), (0, 50), (50, 50), (50, 0), (0, 0))
    >>> line[0]
    (0.0, 0.0)
    >>> line[-2]
    (50.0, 0.0)

Whereas indexing on a :class:`Polygon` will return the ring
(a :class:`LinearRing` object) corresponding to the index::

    >>> from django.contrib.gis.geos import Polygon
    >>> poly = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )
    >>> poly[0]
    <LinearRing object at 0x1044395b0>
    >>> poly[0][-2] # second-to-last coordinate of external ring
    (50.0, 0.0)

In addition, coordinates/components of the geometry may added or modified,
just like a Python list::

    >>> line[0] = (1.0, 1.0)
    >>> line.pop()
    (0.0, 0.0)
    >>> line.append((1.0, 1.0))
    >>> line.coords
    ((1.0, 1.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (1.0, 1.0))

Geometries support set-like operators::

    >>> from django.contrib.gis.geos import LineString
    >>> ls1 = LineString((0, 0), (2, 2))
    >>> ls2 = LineString((1, 1), (3, 3))
    >>> print(ls1 | ls2)  # equivalent to `ls1.union(ls2)`
    MULTILINESTRING ((0 0, 1 1), (1 1, 2 2), (2 2, 3 3))
    >>> print(ls1 & ls2)  # equivalent to `ls1.intersection(ls2)`
    LINESTRING (1 1, 2 2)
    >>> print(ls1 - ls2)  # equivalent to `ls1.difference(ls2)`
    LINESTRING(0 0, 1 1)
    >>> print(ls1 ^ ls2)  # equivalent to `ls1.sym_difference(ls2)`
    MULTILINESTRING ((0 0, 1 1), (2 2, 3 3))

.. admonition:: Equality operator doesn't check spatial equality

    The :class:`~GEOSGeometry` equality operator uses
    :meth:`~GEOSGeometry.equals_exact`, not :meth:`~GEOSGeometry.equals`, i.e.
    it requires the compared geometries to have the same coordinates in the
    same positions with the same SRIDs::

        >>> from django.contrib.gis.geos import LineString
        >>> ls1 = LineString((0, 0), (1, 1))
        >>> ls2 = LineString((1, 1), (0, 0))
        >>> ls3 = LineString((1, 1), (0, 0), srid=4326)
        >>> ls1.equals(ls2)
        True
        >>> ls1 == ls2
        False
        >>> ls3 == ls2  # different SRIDs
        False

Geometry Objects
================

``GEOSGeometry``
----------------

.. class:: GEOSGeometry(geo_input, srid=None)

    :param geo_input: Geometry input value (string or buffer)
    :param srid: spatial reference identifier
    :type srid: int

This is the base class for all GEOS geometry objects.  It initializes on the
given ``geo_input`` argument, and then assumes the proper geometry subclass
(e.g., ``GEOSGeometry('POINT(1 1)')`` will create a :class:`Point` object).

The ``srid`` parameter, if given, is set as the SRID of the created geometry if
``geo_input`` doesn't have an SRID. If different SRIDs are provided through the
``geo_input`` and ``srid`` parameters, ``ValueError`` is raised::

    >>> from django.contrib.gis.geos import GEOSGeometry
    >>> GEOSGeometry('POINT EMPTY', srid=4326).ewkt
    'SRID=4326;POINT EMPTY'
    >>> GEOSGeometry('SRID=4326;POINT EMPTY', srid=4326).ewkt
    'SRID=4326;POINT EMPTY'
    >>> GEOSGeometry('SRID=1;POINT EMPTY', srid=4326)
    Traceback (most recent call last):
    ...
    ValueError: Input geometry already has SRID: 1.

The following input formats, along with their corresponding Python types,
are accepted:

=======================  ==========
Format                   Input Type
=======================  ==========
WKT / EWKT               ``str``
HEX / HEXEWKB            ``str``
WKB / EWKB               ``buffer``
GeoJSON_                 ``str``
=======================  ==========

For the GeoJSON format, the SRID is set based on the ``crs`` member. If ``crs``
isn't provided, the SRID defaults to 4326.

.. _GeoJSON: https://tools.ietf.org/html/rfc7946

.. classmethod:: GEOSGeometry.from_gml(gml_string)

    Constructs a :class:`GEOSGeometry` from the given GML string.

Properties
~~~~~~~~~~

.. attribute:: GEOSGeometry.coords

    Returns the coordinates of the geometry as a tuple.

.. attribute:: GEOSGeometry.dims

    Returns the dimension of the geometry:

    * ``0`` for :class:`Point`\s and :class:`MultiPoint`\s
    * ``1`` for :class:`LineString`\s and :class:`MultiLineString`\s
    * ``2`` for :class:`Polygon`\s and :class:`MultiPolygon`\s
    * ``-1`` for empty :class:`GeometryCollection`\s
    * the maximum dimension of its elements for non-empty
      :class:`GeometryCollection`\s

.. attribute:: GEOSGeometry.empty

    Returns whether or not the set of points in the geometry is empty.

.. attribute:: GEOSGeometry.geom_type

    Returns a string corresponding to the type of geometry.  For example::

        >>> pnt = GEOSGeometry('POINT(5 23)')
        >>> pnt.geom_type
        'Point'

.. attribute:: GEOSGeometry.geom_typeid

    Returns the GEOS geometry type identification number.  The following table
    shows the value for each geometry type:

    ===========================  ========
    Geometry                     ID
    ===========================  ========
    :class:`Point`               0
    :class:`LineString`          1
    :class:`LinearRing`          2
    :class:`Polygon`             3
    :class:`MultiPoint`          4
    :class:`MultiLineString`     5
    :class:`MultiPolygon`        6
    :class:`GeometryCollection`  7
    ===========================  ========

.. attribute:: GEOSGeometry.num_coords

    Returns the number of coordinates in the geometry.

.. attribute:: GEOSGeometry.num_geom

    Returns the number of geometries in this geometry.  In other words, will
    return 1 on anything but geometry collections.

.. attribute:: GEOSGeometry.hasz

    Returns a boolean indicating whether the geometry is three-dimensional.

.. attribute:: GEOSGeometry.ring

    Returns a boolean indicating whether the geometry is a ``LinearRing``.

.. attribute:: GEOSGeometry.simple

    Returns a boolean indicating whether the geometry is 'simple'. A geometry
    is simple if and only if it does not intersect itself (except at boundary
    points).  For example, a :class:`LineString` object is not simple if it
    intersects itself. Thus, :class:`LinearRing` and :class:`Polygon` objects
    are always simple because they do cannot intersect themselves, by
    definition.

.. attribute:: GEOSGeometry.valid

    Returns a boolean indicating whether the geometry is valid.

.. attribute:: GEOSGeometry.valid_reason

    Returns a string describing the reason why a geometry is invalid.

.. attribute:: GEOSGeometry.srid

    Property that may be used to retrieve or set the SRID associated with the
    geometry.  For example::

        >>> pnt = Point(5, 23)
        >>> print(pnt.srid)
        None
        >>> pnt.srid = 4326
        >>> pnt.srid
        4326

Output Properties
~~~~~~~~~~~~~~~~~

The properties in this section export the :class:`GEOSGeometry` object into
a different.  This output may be in the form of a string, buffer, or even
another object.

.. attribute:: GEOSGeometry.ewkt

    Returns the "extended" Well-Known Text of the geometry.  This representation
    is specific to PostGIS and is a superset of the OGC WKT standard. [#fnogc]_
    Essentially the SRID is prepended to the WKT representation, for example
    ``SRID=4326;POINT(5 23)``.

    .. note::

        The output from this property does not include the 3dm, 3dz, and 4d
        information that PostGIS supports in its EWKT representations.

.. attribute:: GEOSGeometry.hex

    Returns the WKB of this Geometry in hexadecimal form.  Please note
    that the SRID value is not included in this representation
    because it is not a part of the OGC specification (use the
    :attr:`GEOSGeometry.hexewkb` property instead).

.. attribute:: GEOSGeometry.hexewkb

    Returns the EWKB of this Geometry in hexadecimal form.  This is an
    extension of the WKB specification that includes the SRID value
    that are a part of this geometry.

.. attribute:: GEOSGeometry.json

    Returns the GeoJSON representation of the geometry. Note that the result is
    not a complete GeoJSON structure but only the ``geometry`` key content of a
    GeoJSON structure. See also :doc:`/ref/contrib/gis/serializers`.

.. attribute:: GEOSGeometry.geojson

    Alias for :attr:`GEOSGeometry.json`.

.. attribute:: GEOSGeometry.kml

    Returns a `KML`__ (Keyhole Markup Language) representation of the
    geometry.  This should only be used for geometries with an SRID of
    4326 (WGS84), but this restriction is not enforced.

.. attribute:: GEOSGeometry.ogr

    Returns an :class:`~django.contrib.gis.gdal.OGRGeometry` object
    corresponding to the GEOS geometry.

.. _wkb:

.. attribute:: GEOSGeometry.wkb

    Returns the WKB (Well-Known Binary) representation of this Geometry
    as a Python buffer.  SRID value is not included, use the
    :attr:`GEOSGeometry.ewkb` property instead.

.. _ewkb:

.. attribute:: GEOSGeometry.ewkb

    Return the EWKB representation of this Geometry as a Python buffer.
    This is an extension of the WKB specification that includes any SRID
    value that are a part of this geometry.

.. attribute:: GEOSGeometry.wkt

    Returns the Well-Known Text of the geometry (an OGC standard).

__ https://developers.google.com/kml/documentation/

Spatial Predicate Methods
~~~~~~~~~~~~~~~~~~~~~~~~~

All of the following spatial predicate methods take another
:class:`GEOSGeometry` instance (``other``) as a parameter, and
return a boolean.

.. method:: GEOSGeometry.contains(other)

    Returns ``True`` if :meth:`other.within(this) <GEOSGeometry.within>` returns
    ``True``.

.. method:: GEOSGeometry.covers(other)

    Returns ``True`` if this geometry covers the specified geometry.

    The ``covers`` predicate has the following equivalent definitions:

    * Every point of the other geometry is a point of this geometry.
    * The DE-9IM Intersection Matrix for the two geometries is
      ``T*****FF*``, ``*T****FF*``, ``***T**FF*``, or ``****T*FF*``.

    If either geometry is empty, returns ``False``.

    This predicate is similar to :meth:`GEOSGeometry.contains`, but is more
    inclusive (i.e. returns ``True`` for more cases). In particular, unlike
    :meth:`~GEOSGeometry.contains` it does not distinguish between points in the
    boundary and in the interior of geometries. For most situations,
    ``covers()`` should be preferred to :meth:`~GEOSGeometry.contains`. As an
    added benefit, ``covers()`` is more amenable to optimization and hence
    should outperform :meth:`~GEOSGeometry.contains`.

.. method:: GEOSGeometry.crosses(other)

    Returns ``True`` if the DE-9IM intersection matrix for the two Geometries
    is ``T*T******`` (for a point and a curve,a point and an area or a line
    and an area) ``0********`` (for two curves).

.. method:: GEOSGeometry.disjoint(other)

    Returns ``True`` if the DE-9IM intersection matrix for the two geometries
    is ``FF*FF****``.

.. method:: GEOSGeometry.equals(other)

    Returns ``True`` if the DE-9IM intersection matrix for the two geometries
    is ``T*F**FFF*``.

.. method:: GEOSGeometry.equals_exact(other, tolerance=0)

    Returns true if the two geometries are exactly equal, up to a
    specified tolerance.  The ``tolerance`` value should be a floating
    point number representing the error tolerance in the comparison, e.g.,
    ``poly1.equals_exact(poly2, 0.001)`` will compare equality to within
    one thousandth of a unit.

.. method:: GEOSGeometry.intersects(other)

    Returns ``True`` if :meth:`GEOSGeometry.disjoint` is ``False``.

.. method:: GEOSGeometry.overlaps(other)

    Returns true if the DE-9IM intersection matrix for the two geometries
    is ``T*T***T**`` (for two points or two surfaces) ``1*T***T**``
    (for two curves).

.. method:: GEOSGeometry.relate_pattern(other, pattern)

    Returns ``True`` if the elements in the DE-9IM intersection matrix
    for this geometry and the other matches the given ``pattern`` --
    a string of nine characters from the alphabet: {``T``, ``F``, ``*``, ``0``}.

.. method:: GEOSGeometry.touches(other)

    Returns ``True`` if the DE-9IM intersection matrix for the two geometries
    is ``FT*******``, ``F**T*****`` or ``F***T****``.

.. method:: GEOSGeometry.within(other)

    Returns ``True`` if the DE-9IM intersection matrix for the two geometries
    is ``T*F**F***``.

Topological Methods
~~~~~~~~~~~~~~~~~~~

.. method:: GEOSGeometry.buffer(width, quadsegs=8)

    Returns a :class:`GEOSGeometry` that represents all points whose distance
    from this geometry is less than or equal to the given ``width``. The
    optional ``quadsegs`` keyword sets the number of segments used to
    approximate a quarter circle (defaults is 8).

.. method:: GEOSGeometry.buffer_with_style(width, quadsegs=8, end_cap_style=1, join_style=1, mitre_limit=5.0)

    Same as :meth:`buffer`, but allows customizing the style of the buffer.

    * ``end_cap_style`` can be round (``1``), flat (``2``), or square (``3``).
    * ``join_style`` can be round (``1``), mitre (``2``), or bevel (``3``).
    * Mitre ratio limit (``mitre_limit``) only affects mitered join style.

.. method:: GEOSGeometry.difference(other)

    Returns a :class:`GEOSGeometry` representing the points making up this
    geometry that do not make up other.

.. method:: GEOSGeometry.interpolate(distance)
.. method:: GEOSGeometry.interpolate_normalized(distance)

    Given a distance (float), returns the point (or closest point) within the
    geometry (:class:`LineString` or :class:`MultiLineString`) at that distance.
    The normalized version takes the distance as a float between 0 (origin) and
    1 (endpoint).

    Reverse of :meth:`GEOSGeometry.project`.

.. method:: GEOSGeometry.intersection(other)

    Returns a :class:`GEOSGeometry` representing the points shared by this
    geometry and other.

.. method:: GEOSGeometry.project(point)
.. method:: GEOSGeometry.project_normalized(point)

    Returns the distance (float) from the origin of the geometry
    (:class:`LineString` or :class:`MultiLineString`) to the point projected on
    the geometry (that is to a point of the line the closest to the given
    point). The normalized version returns the distance as a float between 0
    (origin) and 1 (endpoint).

    Reverse of :meth:`GEOSGeometry.interpolate`.

.. method:: GEOSGeometry.relate(other)

    Returns the DE-9IM intersection matrix (a string) representing the
    topological relationship between this geometry and the other.

.. method:: GEOSGeometry.simplify(tolerance=0.0, preserve_topology=False)

    Returns a new :class:`GEOSGeometry`, simplified to the specified tolerance
    using the Douglas-Peucker algorithm. A higher tolerance value implies
    fewer points in the output. If no tolerance is provided, it defaults to 0.

    By default, this function does not preserve topology. For example,
    :class:`Polygon` objects can be split, be collapsed into lines, or
    disappear. :class:`Polygon` holes can be created or disappear, and lines may
    cross. By specifying ``preserve_topology=True``, the result will have the
    same dimension and number of components as the input; this is significantly
    slower, however.

.. method:: GEOSGeometry.sym_difference(other)

    Returns a :class:`GEOSGeometry` combining the points in this geometry
    not in other, and the points in other not in this geometry.

.. method:: GEOSGeometry.union(other)

    Returns a :class:`GEOSGeometry` representing all the points in this
    geometry and the other.

Topological Properties
~~~~~~~~~~~~~~~~~~~~~~

.. attribute:: GEOSGeometry.boundary

    Returns the boundary as a newly allocated Geometry object.

.. attribute:: GEOSGeometry.centroid

    Returns a :class:`Point` object representing the geometric center of
    the geometry.  The point is not guaranteed to be on the interior
    of the geometry.

.. attribute:: GEOSGeometry.convex_hull

    Returns the smallest :class:`Polygon` that contains all the points in
    the geometry.

.. attribute:: GEOSGeometry.envelope

    Returns a :class:`Polygon` that represents the bounding envelope of
    this geometry. Note that it can also return a :class:`Point` if the input
    geometry is a point.

.. attribute:: GEOSGeometry.point_on_surface

    Computes and returns a :class:`Point` guaranteed to be on the interior
    of this geometry.

.. attribute:: GEOSGeometry.unary_union

    Computes the union of all the elements of this geometry.

    The result obeys the following contract:

    * Unioning a set of :class:`LineString`\s has the effect of fully noding and
      dissolving the linework.

    * Unioning a set of :class:`Polygon`\s will always return a :class:`Polygon`
      or :class:`MultiPolygon` geometry (unlike :meth:`GEOSGeometry.union`,
      which may return geometries of lower dimension if a topology collapse
      occurs).

Other Properties & Methods
~~~~~~~~~~~~~~~~~~~~~~~~~~

.. attribute:: GEOSGeometry.area

    This property returns the area of the Geometry.

.. attribute:: GEOSGeometry.extent

    This property returns the extent of this geometry as a 4-tuple,
    consisting of ``(xmin, ymin, xmax, ymax)``.

.. method:: GEOSGeometry.clone()

    This method returns a :class:`GEOSGeometry` that is a clone of the original.

.. method:: GEOSGeometry.distance(geom)

    Returns the distance between the closest points on this geometry and the
    given ``geom`` (another :class:`GEOSGeometry` object).

    .. note::

        GEOS distance calculations are  linear -- in other words, GEOS does not
        perform a spherical calculation even if the SRID specifies a geographic
        coordinate system.

.. attribute:: GEOSGeometry.length

    Returns the length of this geometry (e.g., 0 for a :class:`Point`,
    the length of a :class:`LineString`, or the circumference of
    a :class:`Polygon`).

.. attribute:: GEOSGeometry.prepared

    Returns a GEOS ``PreparedGeometry`` for the contents of this geometry.
    ``PreparedGeometry`` objects are optimized for the contains, intersects,
    covers, crosses, disjoint, overlaps, touches and within operations. Refer to
    the :ref:`prepared-geometries` documentation for more information.

.. attribute:: GEOSGeometry.srs

    Returns a :class:`~django.contrib.gis.gdal.SpatialReference` object
    corresponding to the SRID of the geometry or ``None``.

.. method:: GEOSGeometry.transform(ct, clone=False)

    Transforms the geometry according to the given coordinate transformation
    parameter (``ct``), which may be an integer SRID, spatial reference WKT
    string, a PROJ.4 string, a
    :class:`~django.contrib.gis.gdal.SpatialReference` object, or a
    :class:`~django.contrib.gis.gdal.CoordTransform` object. By default, the
    geometry is transformed in-place and nothing is returned. However if the
    ``clone`` keyword is set, then the geometry is not modified and a
    transformed clone of the geometry is returned instead.

    .. note::

        Raises :class:`~django.contrib.gis.geos.GEOSException` if GDAL is not
        available or if the geometry's SRID is ``None`` or less than 0. It
        doesn't impose any constraints on the geometry's SRID if called with a
        :class:`~django.contrib.gis.gdal.CoordTransform` object.

.. method:: GEOSGeometry.normalize()

    Converts this geometry to canonical form::

        >>> g = MultiPoint(Point(0, 0), Point(2, 2), Point(1, 1))
        >>> print(g)
        MULTIPOINT (0 0, 2 2, 1 1)
        >>> g.normalize()
        >>> print(g)
        MULTIPOINT (2 2, 1 1, 0 0)

``Point``
---------

.. class:: Point(x=None, y=None, z=None, srid=None)

    ``Point`` objects are instantiated using arguments that represent the
    component coordinates of the point or with a single sequence coordinates.
    For example, the following are equivalent::

        >>> pnt = Point(5, 23)
        >>> pnt = Point([5, 23])

    Empty ``Point`` objects may be instantiated by passing no arguments or an
    empty sequence. The following are equivalent::

        >>> pnt = Point()
        >>> pnt = Point([])

``LineString``
--------------

.. class:: LineString(*args, **kwargs)

    ``LineString`` objects are instantiated using arguments that are either a
    sequence of coordinates or :class:`Point` objects. For example, the
    following are equivalent::

        >>> ls = LineString((0, 0), (1, 1))
        >>> ls = LineString(Point(0, 0), Point(1, 1))

    In addition, ``LineString`` objects may also be created by passing in a
    single sequence of coordinate or :class:`Point` objects::

        >>> ls = LineString( ((0, 0), (1, 1)) )
        >>> ls = LineString( [Point(0, 0), Point(1, 1)] )

    Empty ``LineString`` objects may be instantiated by passing no arguments
    or an empty sequence. The following are equivalent::

        >>> ls = LineString()
        >>> ls = LineString([])

    .. attribute:: closed

        Returns whether or not this ``LineString`` is closed.

``LinearRing``
--------------

.. class:: LinearRing(*args, **kwargs)

    ``LinearRing`` objects are constructed in the exact same way as
    :class:`LineString` objects, however the coordinates must be *closed*, in
    other words, the first coordinates must be the same as the last
    coordinates. For example::

        >>> ls = LinearRing((0, 0), (0, 1), (1, 1), (0, 0))

    Notice that ``(0, 0)`` is the first and last coordinate -- if they were not
    equal, an error would be raised.

``Polygon``
-----------

.. class:: Polygon(*args, **kwargs)

    ``Polygon`` objects may be instantiated by passing in parameters that
    represent the rings of the polygon.  The parameters must either be
    :class:`LinearRing` instances, or a sequence that may be used to construct a
    :class:`LinearRing`::

        >>> ext_coords = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))
        >>> int_coords = ((0.4, 0.4), (0.4, 0.6), (0.6, 0.6), (0.6, 0.4), (0.4, 0.4))
        >>> poly = Polygon(ext_coords, int_coords)
        >>> poly = Polygon(LinearRing(ext_coords), LinearRing(int_coords))

    .. classmethod:: from_bbox(bbox)

        Returns a polygon object from the given bounding-box, a 4-tuple
        comprising ``(xmin, ymin, xmax, ymax)``.

    .. attribute:: num_interior_rings

        Returns the number of interior rings in this geometry.

.. admonition:: Comparing Polygons

    Note that it is possible to compare ``Polygon`` objects directly with ``<``
    or ``>``, but as the comparison is made through Polygon's
    :class:`LineString`, it does not mean much (but is consistent and quick).
    You can always force the comparison with the :attr:`~GEOSGeometry.area`
    property::

        >>> if poly_1.area > poly_2.area:
        >>>     pass

Geometry Collections
====================

``MultiPoint``
--------------

.. class:: MultiPoint(*args, **kwargs)

    ``MultiPoint`` objects may be instantiated by passing in :class:`Point`
    objects as arguments, or a single sequence of :class:`Point` objects::

        >>> mp = MultiPoint(Point(0, 0), Point(1, 1))
        >>> mp = MultiPoint( (Point(0, 0), Point(1, 1)) )

``MultiLineString``
-------------------

.. class:: MultiLineString(*args, **kwargs)

    ``MultiLineString`` objects may be instantiated by passing in
    :class:`LineString` objects as arguments, or a single sequence of
    :class:`LineString` objects::

        >>> ls1 = LineString((0, 0), (1, 1))
        >>> ls2 = LineString((2, 2), (3, 3))
        >>> mls = MultiLineString(ls1, ls2)
        >>> mls = MultiLineString([ls1, ls2])

    .. attribute:: merged

        Returns a :class:`LineString` representing the line merge of
        all the components in this ``MultiLineString``.

    .. attribute:: closed

        Returns ``True`` if and only if all elements are closed. Requires GEOS 3.5.

``MultiPolygon``
----------------

.. class:: MultiPolygon(*args, **kwargs)

    ``MultiPolygon`` objects may be instantiated by passing :class:`Polygon`
    objects as arguments, or a single sequence of :class:`Polygon` objects::

        >>> p1 = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) )
        >>> p2 = Polygon( ((1, 1), (1, 2), (2, 2), (1, 1)) )
        >>> mp = MultiPolygon(p1, p2)
        >>> mp = MultiPolygon([p1, p2])

``GeometryCollection``
----------------------

.. class:: GeometryCollection(*args, **kwargs)

    ``GeometryCollection`` objects may be instantiated by passing in other
    :class:`GEOSGeometry` as arguments, or a single sequence of
    :class:`GEOSGeometry` objects::

        >>> poly = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) )
        >>> gc = GeometryCollection(Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly)
        >>> gc = GeometryCollection((Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly))

.. _prepared-geometries:

Prepared Geometries
===================

In order to obtain a prepared geometry, access the
:attr:`GEOSGeometry.prepared` property.  Once you have a
``PreparedGeometry`` instance its spatial predicate methods, listed below,
may be used with other ``GEOSGeometry`` objects.  An operation with a prepared
geometry can be orders of magnitude faster -- the more complex the geometry
that is prepared, the larger the speedup in the operation.  For more information,
please consult the `GEOS wiki page on prepared geometries <https://trac.osgeo.org/geos/wiki/PreparedGeometry>`_.

For example::

    >>> from django.contrib.gis.geos import Point, Polygon
    >>> poly = Polygon.from_bbox((0, 0, 5, 5))
    >>> prep_poly = poly.prepared
    >>> prep_poly.contains(Point(2.5, 2.5))
    True

``PreparedGeometry``
--------------------

.. class:: PreparedGeometry

    All methods on ``PreparedGeometry`` take an ``other`` argument, which
    must be a :class:`GEOSGeometry` instance.

    .. method:: contains(other)

    .. method:: contains_properly(other)

    .. method:: covers(other)

    .. method:: crosses(other)

    .. method:: disjoint(other)

    .. method:: intersects(other)

    .. method:: overlaps(other)

    .. method:: touches(other)

    .. method:: within(other)

Geometry Factories
==================

.. function:: fromfile(file_h)

    :param file_h: input file that contains spatial data
    :type file_h: a Python ``file`` object or a string path to the file
    :rtype: a :class:`GEOSGeometry` corresponding to the spatial data in the file

    Example::

        >>> from django.contrib.gis.geos import fromfile
        >>> g = fromfile('/home/bob/geom.wkt')

.. function:: fromstr(string, srid=None)

    :param string: string that contains spatial data
    :type string: str
    :param srid: spatial reference identifier
    :type srid: int
    :rtype: a :class:`GEOSGeometry` corresponding to the spatial data in the string

    ``fromstr(string, srid)`` is equivalent to
    :class:`GEOSGeometry(string, srid) <GEOSGeometry>`.

    Example::

        >>> from django.contrib.gis.geos import fromstr
        >>> pnt = fromstr('POINT(-90.5 29.5)', srid=4326)

I/O Objects
===========

Reader Objects
--------------

The reader I/O classes return a :class:`GEOSGeometry` instance from the WKB
and/or WKT input given to their ``read(geom)`` method.

.. class:: WKBReader

    Example::

        >>> from django.contrib.gis.geos import WKBReader
        >>> wkb_r = WKBReader()
        >>> wkb_r.read('0101000000000000000000F03F000000000000F03F')
        <Point object at 0x103a88910>

.. class:: WKTReader

    Example::

        >>> from django.contrib.gis.geos import WKTReader
        >>> wkt_r = WKTReader()
        >>> wkt_r.read('POINT(1 1)')
        <Point object at 0x103a88b50>

Writer Objects
--------------

All writer objects have a ``write(geom)`` method that returns either the
WKB or WKT of the given geometry.  In addition, :class:`WKBWriter` objects
also have properties that may be used to change the byte order, and or
include the SRID value (in other words, EWKB).

.. class:: WKBWriter(dim=2)

    ``WKBWriter`` provides the most control over its output.  By default it
    returns OGC-compliant WKB when its ``write`` method is called.  However,
    it has properties that allow for the creation of EWKB, a superset of the
    WKB standard that includes additional information. See the
    :attr:`WKBWriter.outdim` documentation for more details about the ``dim``
    argument.

    .. method:: WKBWriter.write(geom)

    Returns the WKB of the given geometry as a Python ``buffer`` object.
    Example::

        >>> from django.contrib.gis.geos import Point, WKBWriter
        >>> pnt = Point(1, 1)
        >>> wkb_w = WKBWriter()
        >>> wkb_w.write(pnt)
        <read-only buffer for 0x103a898f0, size -1, offset 0 at 0x103a89930>

    .. method:: WKBWriter.write_hex(geom)

    Returns WKB of the geometry in hexadecimal.  Example::

        >>> from django.contrib.gis.geos import Point, WKBWriter
        >>> pnt = Point(1, 1)
        >>> wkb_w = WKBWriter()
        >>> wkb_w.write_hex(pnt)
        '0101000000000000000000F03F000000000000F03F'

    .. attribute:: WKBWriter.byteorder

    This property may be set to change the byte-order of the geometry
    representation.

    =============== =================================================
    Byteorder Value Description
    =============== =================================================
    0               Big Endian (e.g., compatible with RISC systems)
    1               Little Endian (e.g., compatible with x86 systems)
    =============== =================================================

    Example::

        >>> from django.contrib.gis.geos import Point, WKBWriter
        >>> wkb_w = WKBWriter()
        >>> pnt = Point(1, 1)
        >>> wkb_w.write_hex(pnt)
        '0101000000000000000000F03F000000000000F03F'
        >>> wkb_w.byteorder = 0
        '00000000013FF00000000000003FF0000000000000'

    .. attribute:: WKBWriter.outdim

    This property may be set to change the output dimension of the geometry
    representation.  In other words, if you have a 3D geometry then set to 3
    so that the Z value is included in the WKB.

    ============ ===========================
    Outdim Value Description
    ============ ===========================
    2            The default, output 2D WKB.
    3            Output 3D WKB.
    ============ ===========================

    Example::

        >>> from django.contrib.gis.geos import Point, WKBWriter
        >>> wkb_w = WKBWriter()
        >>> wkb_w.outdim
        2
        >>> pnt = Point(1, 1, 1)
        >>> wkb_w.write_hex(pnt) # By default, no Z value included:
        '0101000000000000000000F03F000000000000F03F'
        >>> wkb_w.outdim = 3 # Tell writer to include Z values
        >>> wkb_w.write_hex(pnt)
        '0101000080000000000000F03F000000000000F03F000000000000F03F'

    .. attribute:: WKBWriter.srid

    Set this property with a boolean to indicate whether the SRID of the
    geometry should be included with the WKB representation.  Example::

        >>> from django.contrib.gis.geos import Point, WKBWriter
        >>> wkb_w = WKBWriter()
        >>> pnt = Point(1, 1, srid=4326)
        >>> wkb_w.write_hex(pnt) # By default, no SRID included:
        '0101000000000000000000F03F000000000000F03F'
        >>> wkb_w.srid = True # Tell writer to include SRID
        >>> wkb_w.write_hex(pnt)
        '0101000020E6100000000000000000F03F000000000000F03F'

.. class:: WKTWriter(dim=2, trim=False, precision=None)

    This class allows outputting the WKT representation of a geometry. See the
    :attr:`WKBWriter.outdim`, :attr:`trim`, and :attr:`precision` attributes for
    details about the constructor arguments.

    .. method:: WKTWriter.write(geom)

    Returns the WKT of the given geometry. Example::

        >>> from django.contrib.gis.geos import Point, WKTWriter
        >>> pnt = Point(1, 1)
        >>> wkt_w = WKTWriter()
        >>> wkt_w.write(pnt)
        'POINT (1.0000000000000000 1.0000000000000000)'

    .. attribute:: WKTWriter.outdim

        See :attr:`WKBWriter.outdim`.

    .. attribute:: WKTWriter.trim

    This property is used to enable or disable trimming of
    unnecessary decimals.

        >>> from django.contrib.gis.geos import Point, WKTWriter
        >>> pnt = Point(1, 1)
        >>> wkt_w = WKTWriter()
        >>> wkt_w.trim
        False
        >>> wkt_w.write(pnt)
        'POINT (1.0000000000000000 1.0000000000000000)'
        >>> wkt_w.trim = True
        >>> wkt_w.write(pnt)
        'POINT (1 1)'

    .. attribute:: WKTWriter.precision

    This property controls the rounding precision of coordinates;
    if set to ``None`` rounding is disabled.

        >>> from django.contrib.gis.geos import Point, WKTWriter
        >>> pnt = Point(1.44, 1.66)
        >>> wkt_w = WKTWriter()
        >>> print(wkt_w.precision)
        None
        >>> wkt_w.write(pnt)
        'POINT (1.4399999999999999 1.6599999999999999)'
        >>> wkt_w.precision = 0
        >>> wkt_w.write(pnt)
        'POINT (1 2)'
        >>> wkt_w.precision = 1
        >>> wkt_w.write(pnt)
        'POINT (1.4 1.7)'

.. rubric:: Footnotes
.. [#fnogc] *See* `PostGIS EWKB, EWKT and Canonical Forms <https://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT>`_, PostGIS documentation at Ch. 4.1.2.

Settings
========

.. setting:: GEOS_LIBRARY_PATH

``GEOS_LIBRARY_PATH``
---------------------

A string specifying the location of the GEOS C library.  Typically,
this setting is only used if the GEOS C library is in a non-standard
location (e.g., ``/home/bob/lib/libgeos_c.so``).

.. note::

    The setting must be the *full* path to the **C** shared library; in
    other words you want to use ``libgeos_c.so``, not ``libgeos.so``.

Exceptions
==========

.. exception:: GEOSException

    The base GEOS exception, indicates a GEOS-related error.