======================
GeoDjango Database API
======================

.. currentmodule:: django.contrib.gis.db.models

GeoDjango's lookup types may be used with any manager method like
``filter()``, ``exclude()``, etc.  However, the lookup types unique to
GeoDjango are only available with geographic fields.
Filters on 'normal' fields (e.g. ``CharField``) may be chained with those on 
geographic fields.  Thus, geographic queries take the following form (assuming 
the ``Zipcode`` model used in the `GeoDjango Model API`_)::

    >>> qs = Zipcode.objects.filter(<field>__<lookup_type>=<parameter>)
    >>> qs = Zipcode.objects.exclude(...)

For example::

    >>> qs = Zipcode.objects.filter(poly__contains=pnt)

In this case, ``poly`` is the geographic field, ``contains`` is the lookup type, 
and ``pnt`` is the parameter (which may be a ``GEOSGeometry`` object or a string
of GeoJSON , WKT, or HEXEWKB).

.. note::

    GeoDjango constructs spatial SQL with the ``GeoQuerySet``, a 
    subclass of Django's ``QuerySet``.  The ``GeoManager`` instance
    attached to your model allows it to use ``GeoQuerySet``.

.. _GeoDjango Model API: model-api.html

Creating and Saving Geographic Models
=====================================
Here is an example of how to create a geometry object (assuming the ``Zipcode``
model)::

    >>> from zipcode.models import Zipcode
    >>> z = Zipcode(code=77096, poly='POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))')
    >>> z.save()

`GEOS geometry objects`_ may also be used to save geometric models::

    >>> from django.contrib.gis.geos import GEOSGeometry
    >>> z = Zipcode(code=77096, poly=GEOSGeometry('POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))'))
    >>> z.save()

Moreover, if the ``GEOSGeometry`` is in a different coordinate system (has a
different SRID value) than that of the field, then it will be implicitly 
transformed into the SRID of the model's field, using the spatial database's 
transform procedure::

    >>> poly_3084 = GEOSGeometry('POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))', srid=3084)  # SRID 3084 is 'NAD83(HARN) / Texas Centric Lambert Conformal'
    >>> z = Zipcode(code=78212, poly=poly_3084)
    >>> z.save()
    >>> from django.db import connection
    >>> print connection.queries[-1]['sql'] # printing the last SQL statement executed (requires DEBUG=True)
    INSERT INTO "geoapp_zipcode" ("code", "poly") VALUES (78212, ST_Transform(ST_GeomFromWKB('\\001 ... ', 3084), 4326))

Thus, geometry parameters may be passed in using the ``GEOSGeometry`` object, WKT
(Well Known Text [#]_), HEXEWKB (PostGIS specific -- a WKB geometry in
hexadecimal [#]_), and GeoJSON [#]_ (requires GDAL).  Essentially, if the input is not a 
``GEOSGeometry`` object, the geometry field will attempt to create a ``GEOSGeometry``
instance from the input.

Below are some examples of GEOS Geometry objects, WKT, and HEXEWKB, and
GeoJSON:

* GEOS Geometry::

    >>> from django.contrib.gis.geos import *
    >>> pnt  = Point(5, 23)
    >>> ls   = LineString((0, 0), (5, 23))
    >>> poly = GEOSGeometry('POLYGON (( 10 10, 10 20, 20 20, 20 15, 10 10))')

* WKT Polygon: ``'POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))'``
* HEXEWKB Polygon : ``'0103000000010000000 ... 00000000000002440'``
* GeoJSON Point: ``{ "type": "Point", "coordinates": [100.0, 0.0] }``

.. _GEOS geometry objects: geos.html

Spatial Lookup Types
====================

PostGIS
-------

Spatial Operators
^^^^^^^^^^^^^^^^^

The following lookup types correspond to PostGIS spatial operators. [#]_

    :lookup:`bbcontains`
        Tests if the geometry field's bounding box completely contains the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__bbcontains=geom)

        PostGIS equivalent::
  
            SELECT ... WHERE poly ~ geom

    :lookup:`bboverlaps`
        Tests if the geometry field's bounding box overlaps the lookup geometry's 
        bounding box.

        Example::

            Zipcode.objects.filter(poly__bboverlaps=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly && geom

    :lookup:`contained`
        Tests if the geometry field's bounding box is completely contained by the 
        lookup geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__contained=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly @ geom

    :lookup:`exact` or :lookup:`same_as`
        Tests actual geometric equality of the geometry field against the the given
        lookup geometry, vertex-by-vertex.

        The following examples are equivalent::

            Zipcode.objects.filter(poly__exact=geom)
            Zipcode.objects.filter(poly=geom)
            Zipcode.objects.filter(poly__same_as=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly ~= geom

    :lookup:`left`
        Tests if the geometry field's bounding box is strictly to the left of the
        lookup geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__left=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly << geom

    :lookup:`right`
        Tests if the geometry field's bounding box is strictly to the right of the
        lookup geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__right=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly >> geom

    lookup:`overlaps_left`
        Tests if the geometry field's bounding box overlaps or is to the left of the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__overlaps_left=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly &< geom

    :lookup:`overlaps_right`
        Tests if the geometry field's bounding box overlaps or is to the right of the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__overlaps_right=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly &> geom

    :lookup:`overlaps_above`
        Tests if the geometry field's bounding box overlaps or is above the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__overlaps_above=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly |&> geom

    :lookup:`overlaps_below`
        Tests if the geometry field's bounding box overlaps or is below the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__overlaps_below=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly &<| geom

    :lookup:`strictly_above`
        Tests if the geometry field's bounding box is strictly above the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__strictly_above=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly |>> geom

    :lookup:`strictly_below`
        Tests if the geometry field's bounding box is strictly below the lookup 
        geometry's bounding box.

        Example::

            Zipcode.objects.filter(poly__strictly_below=geom)

        PostGIS equivalent::

            SELECT ... WHERE poly <<| geom

Geometry Relationship Functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The following lookup types correspond to PostGIS geometry relationship 
functions. [#]_  Please note that when using PostGIS 1.3.1 and above, index
support is automatically "inlined" -- in other words, the bounding box 
equivalent is automatically evaluated prior to calling these, more 
computationally expensive, functions.

    :lookup:`contains`
        Tests if the geometry field spatially contains the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__contains=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Contains(poly, geom)

    :lookup:`coveredby`
        Tests if no point in the geometry field is outside the lookup geometry. [#]_
        Only available in PostGIS 1.3.1 and above.

        Example::

            Zipcode.objects.filter(poly__coveredby=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_CoveredBy(poly, geom)

    :lookup:`covers`
        Tests if no point in the lookup geometry is outside the geometry field. [#]_
        Only available in PostGIS 1.3.1 and above.

        Example::

            Zipcode.objects.filter(poly__covers=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Covers(poly, geom)

    :lookup:`crosses`
        Tests if the geometry field spatially crosses the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__crosses=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Crosses(poly, geom)

    :lookup:`disjoint`
        Tests if the geometry field is spatially disjoint from the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__disjoint=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Disjoint(poly, geom)

.. _dwithin_postgis:

    :lookup:`dwithin`
        Tests if the geometry field is within the specified distance of the lookup
        geometry; uses indexes if available.  The lookup parameter is a two-element
        tuple: ``(geom, distance)``, where ``distance`` is a ``Distance`` object or a
        numeric value in units.   Only available in PostGIS versions 1.3.1 and above.

        .. admonition:: Distance Parameters and Geographic Coordinate Systems

            The ``dwithin`` lookup is meant for projected coordinate systems
            because PostGIS uses ``ST_Distance``, which calculates the 
            Cartesian distance between geometries.  In other words,
            this will not return accurate results for geographic coordinate
            systems such as WGS84.  Thus, an exception will be raised if a
            ``Distance`` object is used on a geometry field in a geographic
            coordinate system.
            
            However, a numeric value is allowed for geometry fields in geographic
            coordinate systems.  This advanced usage allows users to limit
            querysets by distance more efficiently using units of degrees.

        Example::

            # If Zipcode uses a projected coordinate system, this is allowed.
            Zipcode.objects.filter(poly__dwithin=(geom, D(mi=5)))

            # If Zipcode uses a geographic coordinate system, then the
            # distance unit must be a numeric value in units of degrees.
            Zipcode.objects.filter(poly__dwithin=(geom, 0.5))

        PostGIS equivalent::

            SELECT ... WHERE ST_DWithin(poly, geom, <units value>)

    :lookup:`equals`
        Tests if the geometry field is spatially equal to the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__equals=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Equals(poly, geom)

    :lookup:`intersects`
        Tests if the geometry field spatially intersects the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__intersects=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Intersects(poly, geom)

    :lookup:`overlaps`
        Tests if the geometry field spatially overlaps the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__overlaps=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Overlaps(poly, geom)

    :lookup:`relate`
        Tests if the geometry field is spatially related to the the lookup geometry by
        the values given in the intersection pattern matrix.  The intersection pattern
        matrix is a string comprising nine characters, which  define intersections between 
        the interior, boundary, and exterior of the geometry field and the lookup geometry.  
        The intersection pattern matrix may only use the following characters:
        ``1``, ``2``, ``T``, ``F``, or ``*``.  This lookup type allows users to "fine tune"
        a specific geometric relationship consistent with the DE-9IM model. [#]_

        Example::

            # A tuple lookup parameter is used to specify the geometry and
            # the intersection pattern (the pattern here is for 'contains').
            Zipcode.objects.filter(poly__relate(geom, 'T*T***FF*'))

        PostGIS equivalent::

            SELECT ... WHERE ST_Relate(poly, geom, 'T*T***FF*')

    :lookup:`touches`
        Tests if the geometry field spatially touches the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__touches=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Touches(poly, geom)

    :lookup:`within`
        Tests if the geometry field is spatially within the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__within=geom)

        PostGIS equivalent::

            SELECT ... WHERE ST_Within(poly, geom)


Oracle
------
For more information, see Oracle's `Spatial Operators`__ documentation. [#]_

__ http://download.oracle.com/docs/html/B14255_01/sdo_operat.htm

    :lookup:`contains`
        Tests if the geometry field spatially contains the lookup geometry.

        Example::

            Zipcode.objects.filter(poly__contains=geom)

        Oracle equivalent::

            SELECT ... WHERE SDO_CONTAINS(poly, geom)

    :lookup:`covers`
        Tests if no point in the lookup geometry is outside the geometry field.

        Oracle equivalent::

            SELECT ... WHERE SDO_COVERS(poly, geom)
 
    :lookup:`coveredby`
        Tests if no point in the geometry field is outside the lookup geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_COVEREDBY(poly, geom)
  
    :lookup:`disjoint`
        Tests if the geometry field is spatially disjoint from the lookup geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_GEOM.RELATE(poly, 'DISJOINT', geom, 0.05)

    :lookup:`dwithin`
        Tests if the geometry field is within the specified distance of the lookup
        geometry; uses indexes if available.  The lookup parameter is a two-element
        tuple: ``(geom, distance)``, where ``distance`` is a ``Distance`` object or a
        numeric value in units.

        Oracle equivalent::

            SELECT ... WHERE SDO_WITHIN_DISTANCE(poly, geom, 'distance=distance')

    :lookup:`equals`, :lookup:`exact`, :lookup:`same_as`
        Tests if the geometry field is spatially equal to the lookup geometry.
        The following examples are equivalent on Oracle::

            Zipcode.objects.filter(poly=geom)
            Zipcode.objects.filter(poly__exact=geom)
            Zipcode.objects.filter(poly__equals=geom)
            Zipcode.objects.filter(poly__same_as=geom)

        Oracle equivalent::

            SELECT ... WHERE SDO_EQUALS(poly, geom)

    :lookup:`intersects`
        Tests if the geometry field spatially intersects the lookup geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_OVERLAPBDYINTERSECT(poly, geom)

    :lookup:`overlaps`
        Tests if the geometry field spatially overlaps the lookup geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_OVERLAPS(poly, geom)

    :lookup:`relate`
        Tests if the geometry field is spatially related to the the lookup geometry by
        the given mask component.  This lookup requires a tuple parameter, 
        ``(geom, mask)``, where ``mask`` is at least one of the nine-intersection 
        patterns: ``TOUCH``, ``OVERLAPBDYDISJOINT``, ``OVERLAPBDYINTERSECT``, 
        ``EQUAL``, ``INSIDE``, ``COVEREDBY``, ``CONTAINS``, ``COVERS``, ``ANYINTERACT``, 
        and ``ON``.  Multiple masks may be combined with the logical Boolean operator 
        OR, for example, ``'inside+touch'``. [#]_  The mask relation strings are 
        case-insensitive.

        Example::

            # A tuple lookup parameter is used to specify the geometry and
            # the mask component.
            Zipcode.objects.filter(poly__relate(geom, 'anyinteract'))

        Oracle equivalent:: 

            SELECT ... WHERE SDO_RELATE(poly, geom, 'anyinteract')
   
    :lookup:`touches`
        Tests if the geometry field spatially touches the lookup geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_TOUCH(poly, geom)

    :lookup:`within`
        Tests if the geometry field is spatially within (inside) the lookup
        geometry.

        Oracle equivalent::

            SELECT ... WHERE SDO_INSIDE(poly, geom)

MySQL
-----
For more information, see `Relations on Geometry Minimal Bounding Rectangles (MBRs)`__. [#]_

__ http://dev.mysql.com/doc/refman/5.0/en/relations-on-geometry-mbr.html

    :lookup:`bbcontains`, :lookup:`contains`
        * MySQL equivalent ``MBRContains(g1, g2)``

    :lookup:`contained`, :lookup:`within`
        * MySQL equivalent ``MBRWithin(g1, g2)``

    :lookup:`disjoint`
        * MySQL equivalent ``MBRDisjoint(g1, g2)``

    :lookup:`equals`, :lookup:`exact`, :lookup:`same_as`
        * MySQL equivalent ``MBREqual(g1, g2)``

    :lookup:`intersects`
        * MySQL equivalent ``MBRIntersects(g1, g2)``

    :lookup:`overlaps`
        * MySQL equivalent ``MBROverlaps(g1, g2)``

    :lookup:`touches`
        * MySQL equivalent ``MBRTouches(g1, g2)`` 

SpatiaLite
----------

For more information consult the `SpatiaLite SQL functions reference list`__.

__ http://www.gaia-gis.it/spatialite/spatialite-sql-2.3.1.html

    :lookup:`bbcontains`
        * SpatiaLite equivalient ``MbrContains(g1, g2)``

    :lookup:`bboverlaps`
        * SpatiaLite equivalent ``MbrOverlaps(g1, g2)``

    :lookup:`contained`
        * SpatiaLite equivalent ``MbrWithin(g1, g2)``

    :lookup:`contains`
        * SpatiaLite equivalent ``Contains(g1, g2)``

    :lookup:`crosses`
        * SpatiaLite equivalent ``Crosses(g1, g2)``

    :lookup:`disjoint`
        * SpatiaLite equivalent ``Disjoint(g1, g2)``

    :lookup:`equals`, :lookup:`exact`, :lookup:`same_as`
        * SpatiaLite equivalent ``Equals(g1, g2)``

    :lookup:`intersects`
        * SpatiaLite equivalent ``Intersects(g1, g2)``

    :lookup:`overlaps`
        * SpatiaLite equivalent ``Overlaps(g1, g2)``

    :lookup:`relate`
        * SpatiaLite equivalent ``Relate(geom, pattern)``

    :lookup:`touches`
        * SpatiaLite equivalent ``Touches(g1, g2)``

    :lookup:`within`
        * SpatiaLite equivalent ``Within(g1, g2)``


Distance Queries
================

Introduction
------------
Distance calculations with spatial data is tricky because, unfortunately,
the Earth is not flat.  Some distance queries with fields in a geographic
coordinate system may have to be expressed differently because of 
limitations in PostGIS.  Please see the `Selecting an SRID`_ section in the 
model API documentation for more details.

.. _Selecting an SRID: model-api.html#selecting-an-srid

Distance Lookups
----------------
*Availability*: PostGIS, Oracle, SpatiaLite

Distance lookups take a tuple parameter comprising:

#. A geometry to base calculations from; and 
#. A number or ``Distance`` object containing the distance.

If a ``Distance`` [#]_ object is used, it may be expressed in
any units (the SQL generated will use units converted to those of the field); 
otherwise, numeric parameters will be assumed to be in the units of the field.

.. note::

    For PostGIS users, the routine ``ST_distance_sphere`` 
    is used by default for calculating distances on geographic coordinate systems 
    -- which may only be called with point geometries [#]_.  Thus, 
    geographic distance lookups on PostGIS are only allowed on ``PointField`` 
    model fields using points for the geographic parameter.

The following distance lookups are available:

* :lookup:`distance_lt`
* :lookup:`distance_lte`
* :lookup:`distance_gt`
* :lookup:`distance_gte`
* :lookup:`dwithin`

In addition, there's the :ref:`distance` ``GeoQuerySet`` method.

For example, let's say we have a ``SouthTexasCity`` model (from the 
`GeoDjango distance tests`__ ) on a *projected* coordinate system valid for cities 
in southern Texas::

    from django.contrib.gis.db import models
    
    class SouthTexasCity(models.Model):
        name = models.CharField(max_length=30)
        # A projected coordinate system (only valid for South Texas!) 
        # is used, units are in meters.
        point = models.PointField(srid=32140) 
        objects = models.GeoManager()

Then distance queries may be performed as follows::

    >>> from django.contrib.gis.geos import *
    >>> from django.contrib.gis.measure import D # ``D`` is a shortcut for ``Distance``
    >>> from geoapp import SouthTexasCity 
    # Distances will be calculated from this point, which does not have to be projected.
    >>> pnt = fromstr('POINT(-96.876369 29.905320)', srid=4326)
    # If numeric parameter, units of field (meters in this case) are assumed.
    >>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, 7000))
    # Find all Cities within 7 km, > 20 miles away, and > 100 chains  away (an obscure unit)
    >>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, D(km=7)))
    >>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(mi=20)))
    >>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(chain=100)))

__ http://code.djangoproject.com/browser/django/trunk/django/contrib/gis/tests/distapp/models.py

.. _geoqs_methods:

``GeoQuerySet`` Methods
=======================

``GeoQuerySet`` methods perform a spatial operation on each geographic
field in the queryset and store its output in a new attribute on the model
(which is generally the name of the ``GeoQuerySet`` method).

There are also aggregate ``GeoQuerySet`` methods which return a single value
instead of a queryset.  This section will describe the API and availability
of every ``GeoQuerySet`` method available in GeoDjango.

With a few exceptions, the following keyword arguments may be used with all
``GeoQuerySet`` methods:

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``field_name``         By default, ``GeoQuerySet`` methods use the first
                       geographic field encountered in the model.  This
                       keyword should be used to specify another 
                       geographic field (e.g., ``field_name='point2'``)
                       when there are multiple geographic fields in a model.

                       On PostGIS, the ``field_name`` keyword may also be
                       used on geometry fields in models that are related
                       via a ``ForeignKey`` relation (e.g.,
                       ``field_name='related__point'``).
    
``model_att``          By default, ``GeoQuerySet`` methods typically attach
                       their output in an attribute with the same name as
                       the ``GeoQuerySet`` method.  Setting this keyword
                       with the desired attribute name will override this
                       default behavior.  For example,
                       ``qs = Zipcode.objects.centroid(model_att='c')`` will
                       attach the centroid of the ``Zipcode`` geometry field
                       in a ``c`` attribute on every model rather than in a
                       ``centroid`` attribute.  

                       This keyword is required if 
                       a method name clashes with an existing 
                       ``GeoQuerySet`` method -- if you wanted to use the 
                       ``area()`` method on model with a ``PolygonField`` 
		       named ``area``, for example.
=====================  =====================================================

Aggregate Objects
-----------------
.. versionadded:: 1.1

Example::

    >>> from django.contrib.gis.db.models import Extent, Union
    >>> WorldBorders.objects.aggregate(Extent('mpoly'), Union('mpoly'))

.. method:: Collect

Returns the same as the :ref:`collect` aggregate method.

.. method:: Extent

Returns the same as the :ref:`extent` aggregate method.

.. method:: Extent3D

.. versionadded:: 1.2

Returns the same as the :ref:`extent3d` aggregate method.

.. method:: MakeLine

Returns the same as the :ref:`makeline` aggregate method.

.. method:: Union

Returns the same as the :ref:`unionagg` aggregate method.

Aggregate Methods
-----------------

.. _collect:

.. method:: collect()

.. versionadded:: 1.1

*Availability*: PostGIS

Returns a ``GEOMETRYCOLLECTION`` or a ``MULTI`` geometry object from the geometry
column.  This is analagous to a simplified version of the :ref:`unionagg` routine,
except it can be several orders of magnitude faster than peforming a union because
it simply rolls up geometries into a collection or multi object, not caring about
dissolving boundaries.

.. _extent:

.. method:: extent()

*Availability*: PostGIS, Oracle

Returns the extent of the ``GeoQuerySet`` as a four-tuple, comprising the 
lower left coordinate and the upper right coordinate.

Example::

    >>> qs = City.objects.filter(name__in=('Houston', 'Dallas'))
    >>> print qs.extent()
    (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)


.. _extent3d:

.. method:: extent3d()

.. versionadded:: 1.2

*Availability*: PostGIS

Returns the 3D extent of the ``GeoQuerySet`` as a six-tuple, comprising
the lower left coordinate and upper right coordinate.

Example::

    >>> qs = City.objects.filter(name__in=('Houston', 'Dallas'))
    >>> print qs.extent3d()
    (-96.8016128540039, 29.7633724212646, 0, -95.3631439208984, 32.782058715820, 0)

.. _makeline:

.. method:: make_line()

*Availability*: PostGIS

Returns a ``LineString`` constructed from the point field geometries in the 
``GeoQuerySet``.  Currently, ordering the queryset has no effect.

Example::

     >>> print City.objects.filter(name__in=('Houston', 'Dallas')).make_line()
     LINESTRING (-95.3631510000000020 29.7633739999999989, -96.8016109999999941 32.7820570000000018)

.. _unionagg:

.. function:: unionagg()

*Availability*: PostGIS, Oracle, SpatiaLite

This method returns a ``GEOSGeometry`` object comprising the union of every 
geometry in the queryset.  Please note that use of `unionagg` is processor intensive 
and may take a significant amount of time on large querysets.

Example::
    
    >>> u = Zipcode.objects.unionagg() # This may take a long time.
    >>> u = Zipcode.objects.filter(poly__within=bbox).unionagg() # A more sensible approach.

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``tolerance``          This keyword is for Oracle only.  It is for the 
                       tolerance value used by the ``SDOAGGRTYPE``
                       procedure; the  `Oracle documentation`__ has more 
                       details.
=====================  =====================================================

__ http://download.oracle.com/docs/html/B14255_01/sdo_intro.htm#sthref150 

Measurement
-----------
*Availability*: PostGIS, Oracle, SpatiaLite

.. _area:

.. function:: area()

Returns the area of the geographic field in an ``area`` attribute on
each element of this GeoQuerySet.

.. _distance:

.. function:: distance(geom)

This method takes a geometry as a parameter, and attaches a ``distance`` 
attribute to every model in the returned queryset that contains the 
distance (as a ``Distance`` object) to the given geometry.

In the following example (taken from the `GeoDjango distance tests`__), 
the distance from the `Tasmanian`__ city of Hobart to every other 
``PointField`` in the ``AustraliaCity`` queryset is calculated::

    >>> pnt = AustraliaCity.objects.get(name='Hobart').point
    >>> for city in AustraliaCity.objects.distance(pnt): print city.name, city.distance
    Wollongong 990071.220408 m
    Shellharbour 972804.613941 m
    Thirroul 1002334.36351 m
    Mittagong 975691.632637 m
    Batemans Bay 834342.185561 m
    Canberra 598140.268959 m
    Melbourne 575337.765042 m
    Sydney 1056978.87363 m
    Hobart 0.0 m
    Adelaide 1162031.83522 m
    Hillsdale 1049200.46122 m

.. note::

    Because the ``distance`` attribute is a ``Distance`` object, you can
    easily express the value in the units of your choice.  For example,
    ``city.distance.mi`` is the distance value in miles and
    ``city.distance.km`` is the distance value in kilometers.  See the
    `distance documentation`_ for usage details and the list of
    `supported units`_.

.. _distance documentation: measure.html#the-distance-and-area-objects
.. _supported units: measure.html#supported-units

__ http://en.wikipedia.org/wiki/Tasmania
__ http://code.djangoproject.com/browser/django/trunk/django/contrib/gis/tests/distapp/models.py

.. function:: length()

Returns the length of the geometry field in a ``length`` attribute
(a ``Distance`` object) on each model in the queryset.

.. function:: perimiter()

Returns the perimeter of the geometry field in a ``perimeter`` attribute
(a ``Distance`` object) on each model in the queryset.

Geometry Methods
----------------

With the exception of ``transform``, all of the following attach geometry objects 
to each element of the ``GeoQuerySet`` that is the result of the method.

.. function:: centroid()

*Availability*: PostGIS, Oracle, SpatiaLite

Returns the ``centroid`` value for the geographic field in a ``centroid``
attribute on each element of the ``GeoQuerySet``.

.. function:: envelope()

*Availability*: PostGIS, SpatiaLite

Returns a geometry representing the bounding box of the geometry field in
an ``envelope`` attribute on each element of the ``GeoQuerySet``.

.. function: point_on_surface()

*Availability*: PostGIS, Oracle, SpatiaLite

Returns a Point geometry guaranteed to lie on the surface of the
Geometry field in a `point_on_surface` attribute on each element
of this GeoQuerySet; otherwise sets with None.

.. function:: scale(x, y, z=0.0)

*Availability*: PostGIS, SpatiaLite

.. function:: snap_to_grid(*args)

.. versionadded:: 1.1

Snap all points of the input geometry to the grid.  How the
geometry is snapped to the grid depends on how many numeric
(either float, integer, or long) arguments are given.

===================  =====================================================
Number of Arguments  Description
===================  =====================================================
1                    A single size to snap bot the X and Y grids to.
2                    X and Y sizes to snap the grid to.
4                    X, Y sizes and the corresponding X, Y origins.
===================  =====================================================

.. function:: translate(x, y, z=0.0)

*Availability*: PostGIS, SpatiaLite

Translates the geometry to a new location using the given numeric
parameters as offsets.

.. function:: transform(srid)

*Availability*: PostGIS, Oracle

The ``transform`` method transforms the geometries in a model to the spatial
reference system specified by the ``srid`` parameter.  If no ``srid`` is given,
then 4326 (WGS84) is used by default.

.. note ::
    
    What spatial reference system an integer SRID corresponds to may depend on 
    the spatial database used.  In other words, the SRID numbers used for Oracle 
    are not necessarily the same as those used by PostGIS.

Example::

    >>> qs = Zipcode.objects.all().transform() # Transforms to WGS84
    >>> qs = Zipcode.objects.all().transform(32140) # Transforming to "NAD83 / Texas South Central"
    >>> print qs[0].poly.srid
    32140
    >>> print qs[0].poly
    POLYGON ((234055.1698884720099159 4937796.9232223574072123 ...

Geometry Operations
-------------------
*Availability*: PostGIS, Oracle, SpatiaLite

The following methods all take a geometry as a parameter and attach a geometry
to each element of the ``GeoQuerySet`` that is the result of the operation.

.. function:: difference(geom)

Returns the spatial difference of the geographic field with the given
geometry in a ``difference`` attribute on each element of the 
``GeoQuerySet``.

.. function:: intersection(geom)

Returns the spatial intersection of the geographic field with the
given geometry in an ``intersection`` attribute on each element of the 
``GeoQuerySet``.

.. function:: sym_difference(geom)

Returns the symmetric difference of the geographic field with the
given geometry in a ``sym_difference`` attribute on each element of the
``GeoQuerySet``.

.. function:: union(geom)

Returns the union of the geographic field with the given
geometry in an ``union`` attribute on each element of the
``GeoQuerySet``.

Output
------

The following ``GeoQuerySet`` methods will return an attribute that has the value 
of the geometry field in each model converted to the requested output format.

.. function:: geojson()

.. versionadded:: 1.1

*Availability*: PostGIS

Attaches a ``geojson`` attribute to every model in the queryset that contains the
`GeoJSON`__ representation of the geometry.

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``precision``          It may be used to specify the number of significant 
                       digits for the coordinates in the GeoJSON 
                       representation -- the default value is 8.

``crs``                Set this to ``True`` if you want the coordinate
                       reference system to be included in the returned
                       GeoJSON.

``bbox``               Set this to ``True`` if you want the bounding box
                       to be included in the returned GeoJSON.
=====================  =====================================================

__ http://geojson.org/

.. function:: gml()

*Availability*: PostGIS, Oracle

Attaches a ``gml`` attribute to every model in the queryset that contains the 
`Geographic Markup Language (GML)`__ representation of the geometry. 

Example::

    >>> qs = Zipcode.objects.all().gml()
    >>> print qs[0].gml
    <gml:Polygon srsName="EPSG:4326"><gml:OuterBoundaryIs>-147.78711,70.245363 ...  -147.78711,70.245363</gml:OuterBoundaryIs></gml:Polygon>

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``precision``          This keyword is for PostGIS only.  It may be used 
                       to specify the number of significant digits for the 
                       coordinates in the GML representation -- the default 
                       value is 8.

``version``            This keyword is for PostGIS only.  It may be used to
                       specify the GML version used, and may only be values
                       of 2 or 3.  The default value is 2.
=====================  =====================================================

__ http://en.wikipedia.org/wiki/Geography_Markup_Language

.. function:: kml()

*Availability*: PostGIS

Attaches a ``kml`` attribute to every model in the queryset that contains the 
`Keyhole Markup Language (KML)`__ representation of the geometry fields. It 
should be noted that the contents of the KML are transformed to WGS84 if 
necessary.

Example::

    >>> qs = Zipcode.objects.all().kml()
    >>> print qs[0].kml
    <Polygon><outerBoundaryIs><LinearRing><coordinates>-103.04135,36.217596,0 ... -103.04135,36.217596,0</coordinates></LinearRing></outerBoundaryIs></Polygon>

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``precision``          This keyword may be used to specify the number of 
                       significant digits for the coordinates in the KML 
                       representation -- the default value is 8.
=====================  =====================================================

__ http://code.google.com/apis/kml/documentation/

.. function:: svg()

*Availability*: PostGIS, SpatiaLite

Attaches a ``svg`` attribute to every model in the queryset that contains
the `Scalable Vector Graphics (SVG)`__ path data of the geometry fields.

=====================  =====================================================
Keyword Argument       Description
=====================  =====================================================
``relative``           If set to ``True``, the path data will be implemented
                       in terms of relative moves.  Defaults to ``False``, 
		       meaning that absolute moves are used instead.

``precision``          This keyword may be used to specify the number of 
                       significant digits for the coordinates in the SVG 
                       representation -- the default value is 8.
=====================  =====================================================

__ http://www.w3.org/Graphics/SVG/

Miscellaneous
-------------

.. function:: mem_size()

*Availability*: PostGIS

Returns the memory size (number of bytes) that the geometry field takes
in a ``mem_size`` attribute  on each element of the ``GeoQuerySet``.

.. function:: num_geom()

*Availability*: PostGIS, Oracle, SpatiaLite

Returns the number of geometries in a ``num_geom`` attribute on
each element of the ``GeoQuerySet`` if the geometry field is a
collection (e.g., a ``GEOMETRYCOLLECTION`` or ``MULTI*`` field);
otherwise sets with ``None``.

.. function:: num_points()

*Availability*: PostGIS, Oracle, SpatiaLite

Returns the number of points in the first linestring in the
geometry field in a ``num_points`` attribute on each element of
the ``GeoQuerySet``; otherwise sets with ``None``.

Compatibility Table
===================

Spatial Lookup Types
--------------------
The following table provides a summary of what lookup types are available
on each spatial backend.

===========================  =========  ========  ============ ==========
Lookup Type                  PostGIS    Oracle    MySQL [#]_   SpatiaLite
===========================  =========  ========  ============ ==========
``bbcontains``               X                    X            X
``bboverlaps``               X                    X            X
``contained``                X                    X            X
``contains``                 X          X         X            X
``coveredby``                X          X
``covers``                   X          X
``crosses``                  X                                 X
``disjoint``                 X          X         X            X
``distance_gt``              X          X                      X
``distance_gte``             X          X                      X
``distance_lt``              X          X                      X
``distance_lte``             X          X                      X
``dwithin``                  X          X
``equals``                   X          X         X            X
``exact``                    X          X         X            X
``intersects``               X          X         X            X
``overlaps``                 X          X         X            X
``relate``                   X          X                      X
``same_as``                  X          X         X            X
``touches``                  X          X         X            X
``within``                   X          X         X            X
``left``                     X
``right``                    X
``overlaps_left``            X
``overlaps_right``           X
``overlaps_above``           X
``overlaps_below``           X
``strictly_above``           X
``strictly_below``           X
===========================  =========  ========  ============ ==========

``GeoQuerySet`` Methods
-----------------------
The following table provides a summary of what ``GeoQuerySet`` methods
are available on each spatial backend.  Please note that MySQL does not 
support any of these methods, and is thus excluded from the table.

===========================  =========  ======== ==========
Method                       PostGIS    Oracle   SpatiaLite
===========================  =========  ======== ==========
``area``                     X          X        X
``centroid``                 X          X        X
``collect``                  X            
``difference``               X          X        X
``distance``                 X          X        X
``envelope``                 X                   X
``extent``                   X          X
``extent3d``                 X
``geojson``                  X
``gml``                      X          X
``intersection``             X          X        X
``kml``                      X
``length``                   X          X        X
``make_line``                X
``mem_size``                 X 
``num_geom``                 X          X        X
``num_points``               X          X        X
``perimeter``                X          X
``point_on_surface``         X          X        X
``scale``                    X                   X
``snap_to_grid``             X
``svg``                      X                   X
``sym_difference``           X          X        X
``transform``                X          X        X
``translate``                X                   X
``union``                    X          X        X
``unionagg``                 X          X        X
===========================  =========  ======== ==========    

.. rubric:: Footnotes
.. [#] *See* Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification For SQL <http://www.opengis.org/docs/99-049.pdf>`_, Document 99-049 (May 5, 1999), at  Ch. 3.2.5, p. 3-11 (SQL Textual Representation of Geometry).
.. [#] *See* `PostGIS EWKB, EWKT and Canonical Forms <http://postgis.refractions.net/documentation/manual-1.3/ch04.html#id2571020>`_, PostGIS documentation at Ch. 4.1.2.
.. [#] *See* Howard Butler, Martin Daly, Allan Doyle, Tim Schaub, & Christopher Schmidt, `The GeoJSON Format Specification <http://geojson.org/geojson-spec.html>`_, Revision 1.0 (June 16, 2008).
.. [#] *See generally*, `Operators <http://postgis.refractions.net/documentation/manual-1.3/ch06.html#id2576880>`_, PostGIS Documentation at Ch. 6.2.2.
.. [#] *See generally*, `Geometry Relationship Functions <http://postgis.refractions.net/documentation/manual-1.3/ch06.html#id2574517>`_ PostGIS Documentation at Ch. 6.1.2.
.. [#] For an explanation of this routine, see `this entry <http://lin-ear-th-inking.blogspot.com/2007/06/subtleties-of-ogc-covers-spatial.html>`_ at the blog of Martin Davis (a PostGIS developer).
.. [#] *See id.*
.. [#] *See* `OpenGIS Simple Feature Specification For SQL <http://www.opengis.org/docs/99-049.pdf>`_, at Ch. 2.1.13.2, p. 2-13 (The Dimensionally Extended Nine-Intersection Model).
.. [#] Oracle Spatial User's Guide and Manual, at Ch. 11.
.. [#] *See id.* at `SDO_RELATE documentation <http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14255/sdo_operat.htm#sthref845>`_.
.. [#] MySQL 5.0 Reference Manual, at Ch. 17.5.5.
.. [#] *See* the `distance documentation`_ for more information on the ``Distance`` object. 
.. [#] *See* ``ST_distance_sphere`` in `Measurement Functions <http://postgis.refractions.net/documentation/manual-1.3/ch06.html#id2577138>`_, PostGIS documentation at Ch. 6.2.3.
.. [#] MySQL only supports bounding box operations (known as minimum bounding rectangles, or MBR, in MySQL).  Thus, spatial lookups such as ``contains`` are really equivalent to ``bbcontains``.
