[1] | 1 | .. _spatial_relationships: |
---|
| 2 | |
---|
| 3 | Section 10: Spatial Relationships |
---|
| 4 | ================================= |
---|
| 5 | |
---|
| 6 | So far we have only used spatial functions that measure (:command:`ST_Area`, :command:`ST_Length`), serialize (:command:`ST_GeomFromText`) or deserialize (:command:`ST_AsGML`) geometries. What these functions have in common is that they only work on one geometry at a time. |
---|
| 7 | |
---|
| 8 | Spatial databases are powerful because they not only store geometry, they also have the ability to compare *relationships between geometries*. |
---|
| 9 | |
---|
| 10 | Questions like âWhich are the closet bike racks to a park?â or âWhere are the intersections of subway lines and streets?â can only be answered by comparing geometries representing the bike racks, streets, and subway lines. |
---|
| 11 | |
---|
| 12 | The OGC standard defines the following set of methods to compare geometries. |
---|
| 13 | |
---|
| 14 | ST_Equals |
---|
| 15 | --------- |
---|
| 16 | |
---|
| 17 | :command:`ST_Equals(geometry A, geometry B)` tests the spatial equality of two geometries. |
---|
| 18 | |
---|
| 19 | .. figure:: ./spatial_relationships/st_equals.png |
---|
| 20 | :align: center |
---|
| 21 | |
---|
| 22 | ST_Equals returns TRUE if two geometries of the same type have identical x,y coordinate values, i.e. if the secondary shape is equal (identical) to the primary shape object. |
---|
| 23 | |
---|
| 24 | First, let's retrieve a representation of a point from our ``nyc_subway_stations`` table. We'll take just the entry for 'Broad St'. |
---|
| 25 | |
---|
| 26 | .. code-block:: sql |
---|
| 27 | |
---|
| 28 | SELECT name, the_geom, ST_AsText(the_geom) |
---|
| 29 | FROM nyc_subway_stations |
---|
| 30 | WHERE name = 'Broad St'; |
---|
| 31 | |
---|
| 32 | :: |
---|
| 33 | |
---|
| 34 | name | the_geom | st_astext |
---|
| 35 | ----------+----------------------------------------------------+----------------------- |
---|
| 36 | Broad St | 0101000020266900000EEBD4CF27CF2141BC17D69516315141 | POINT(583571 4506714) |
---|
| 37 | |
---|
| 38 | Then, plug the geometry representation back into an :command:`ST_Equals` test: |
---|
| 39 | |
---|
| 40 | .. code-block:: sql |
---|
| 41 | |
---|
| 42 | SELECT name |
---|
| 43 | FROM nyc_subway_stations |
---|
| 44 | WHERE ST_Equals(the_geom, '0101000020266900000EEBD4CF27CF2141BC17D69516315141'); |
---|
| 45 | |
---|
| 46 | :: |
---|
| 47 | |
---|
| 48 | Broad St |
---|
| 49 | |
---|
| 50 | .. note:: |
---|
| 51 | |
---|
| 52 | The representation of the point was not very human readable (``0101000020266900000EEBD4CF27CF2141BC17D69516315141``) but it was an exact representation of the coordinate values. For a test like equality, using the exact coordinates in necessary. |
---|
| 53 | |
---|
| 54 | |
---|
| 55 | ST_Intersects, ST_Disjoint, ST_Crosses and ST_Overlaps |
---|
| 56 | ------------------------------------------------------ |
---|
| 57 | |
---|
| 58 | :command:`ST_Intersects`, :command:`ST_Crosses`, and :command:`ST_Overlaps` test whether the interiors of the geometries intersect. |
---|
| 59 | |
---|
| 60 | .. figure:: ./spatial_relationships/st_intersects.png |
---|
| 61 | :align: center |
---|
| 62 | |
---|
| 63 | :command:`ST_Intersects(geometry A, geometry B)` returns t (TRUE) if the intersection does not result in an empty set. Intersects returns the exact opposite result of disjoint. |
---|
| 64 | |
---|
| 65 | .. figure:: ./spatial_relationships/st_disjoint.png |
---|
| 66 | :align: center |
---|
| 67 | |
---|
| 68 | The opposite of ST_Intersects is :command:`ST_Disjoint(geometry A , geometry B)`. If two geometries are disjoint, they do not intersect, and vice-versa. In fact, it is often more efficient to test "not intersects" than to test "disjoint" because the intersects tests can be spatially indexed, while the disjoint test cannot. |
---|
| 69 | |
---|
| 70 | .. figure:: ./spatial_relationships/st_crosses.png |
---|
| 71 | :align: center |
---|
| 72 | |
---|
| 73 | For multipoint/polygon, multipoint/linestring, linestring/linestring, linestring/polygon, and linestring/multipolygon comparisons, :command:`ST_Crosses(geometry A, geometry B)` returns t (TRUE) if the intersection results in a geometry whose dimension is one less than the maximum dimension of the two source geometries and the intersection set is interior to both source geometries. |
---|
| 74 | |
---|
| 75 | .. figure:: ./spatial_relationships/st_overlaps.png |
---|
| 76 | :align: center |
---|
| 77 | |
---|
| 78 | :command:`ST_Overlaps(geometry A, geometry B)` compares two geometries of the same dimension and returns TRUE if their intersection set results in a geometry different from both but of the same dimension. |
---|
| 79 | |
---|
| 80 | Let's take our Broad Street subway station and determine its neighborhood using the :command:`ST_Intersects` function: |
---|
| 81 | |
---|
| 82 | .. code-block:: sql |
---|
| 83 | |
---|
| 84 | SELECT name, boroname |
---|
| 85 | FROM nyc_neighborhoods |
---|
| 86 | WHERE ST_Intersects(the_geom, '0101000020266900000EEBD4CF27CF2141BC17D69516315141'); |
---|
| 87 | |
---|
| 88 | :: |
---|
| 89 | |
---|
| 90 | name | boroname |
---|
| 91 | --------------------+----------- |
---|
| 92 | Financial District | Manhattan |
---|
| 93 | |
---|
| 94 | |
---|
| 95 | |
---|
| 96 | ST_Touches |
---|
| 97 | ---------- |
---|
| 98 | |
---|
| 99 | :command:`ST_Touches` tests whether two geometries touch at their boundaries, but do not intersect in their interiors |
---|
| 100 | |
---|
| 101 | .. figure:: ./spatial_relationships/st_touches.png |
---|
| 102 | :align: center |
---|
| 103 | |
---|
| 104 | :command:`ST_Touches(geometry A, geometry B)` returns TRUE if either of the geometries' boundaries intersect or if only one of the geometry's interiors intersects the other's boundary. |
---|
| 105 | |
---|
| 106 | ST_Within and ST_Contains |
---|
| 107 | ------------------------- |
---|
| 108 | |
---|
| 109 | :command:`ST_Within` and :command:`ST_Contains` test whether one geometry is fully within the other. |
---|
| 110 | |
---|
| 111 | .. figure:: ./spatial_relationships/st_within.png |
---|
| 112 | :align: center |
---|
| 113 | |
---|
| 114 | :command:`ST_Within(geometry A , geometry B)` returns TRUE if the first geometry is completely within the second geometry. ST_Within tests for the exact opposite result of ST_Contains. |
---|
| 115 | |
---|
| 116 | :command:`ST_Contains(geometry A, geometry B)` returns TRUE if the second geometry is completely contained by the first geometry. |
---|
| 117 | |
---|
| 118 | |
---|
| 119 | ST_Distance and ST_DWithin |
---|
| 120 | -------------------------- |
---|
| 121 | |
---|
| 122 | An extremely common GIS question is "find all the stuff within distance X of this other stuff". |
---|
| 123 | |
---|
| 124 | The :command:`ST_Distance(geometry A, geometry B)` calculates the *shortest* distance between two geometries and returns it as a float. This is useful for actually reporting back the distance between objects. |
---|
| 125 | |
---|
| 126 | .. code-block:: sql |
---|
| 127 | |
---|
| 128 | SELECT ST_Distance( |
---|
| 129 | ST_GeometryFromText('POINT(0 5)'), |
---|
| 130 | ST_GeometryFromText('LINESTRING(-2 2, 2 2)')); |
---|
| 131 | |
---|
| 132 | :: |
---|
| 133 | |
---|
| 134 | 3 |
---|
| 135 | |
---|
| 136 | For testing whether two objects are within a distance of one another, the :command:`ST_DWithin` function provides an index-accelerated true/false test. This is useful for questions like "how many trees are within a 500 meter buffer of the road?". You don't have to calculate an actual buffer, you just have to test the distance relationship. |
---|
| 137 | |
---|
| 138 | .. figure:: ./spatial_relationships/st_dwithin.png |
---|
| 139 | :align: center |
---|
| 140 | |
---|
| 141 | Using our Broad Street subway station again, we can find the streets nearby (within 10 meters of) the subway stop: |
---|
| 142 | |
---|
| 143 | .. code-block:: sql |
---|
| 144 | |
---|
| 145 | SELECT name |
---|
| 146 | FROM nyc_streets |
---|
| 147 | WHERE ST_DWithin( |
---|
| 148 | the_geom, |
---|
| 149 | '0101000020266900000EEBD4CF27CF2141BC17D69516315141', |
---|
| 150 | 10 |
---|
| 151 | ); |
---|
| 152 | |
---|
| 153 | :: |
---|
| 154 | |
---|
| 155 | name |
---|
| 156 | -------------- |
---|
| 157 | Wall St |
---|
| 158 | Broad St |
---|
| 159 | Nassau St |
---|
| 160 | |
---|
| 161 | And we can verify the answer on a map. The Broad St station is actually at the intersection of Wall, Broad and Nassau Streets. |
---|
| 162 | |
---|
| 163 | .. image:: ./spatial_relationships/broad_st.jpg |
---|
| 164 | |
---|
| 165 | Function List |
---|
| 166 | ------------- |
---|
| 167 | |
---|
| 168 | `ST_Contains(geometry A, geometry B) <http://postgis.org/docs/ST_Contains.html>`_: Returns true if and only if no points of B lie in the exterior of A, and at least one point of the interior of B lies in the interior of A. |
---|
| 169 | |
---|
| 170 | `ST_Crosses(geometry A, geometry B) <http://postgis.org/docs/ST_Crosses.html>`_: Returns TRUE if the supplied geometries have some, but not all, interior points in common. |
---|
| 171 | |
---|
| 172 | `ST_Disjoint(geometry A , geometry B) <http://postgis.org/docs/ST_Disjoint.html>`_: Returns TRUE if the Geometries do not "spatially intersect" - if they do not share any space together. |
---|
| 173 | |
---|
| 174 | `ST_Distance(geometry A, geometry B) <http://postgis.org/docs/ST_Distance.html>`_: Returns the 2-dimensional cartesian minimum distance (based on spatial ref) between two geometries in projected units. |
---|
| 175 | |
---|
| 176 | `ST_DWithin(geometry A, geometry B, radius) <http://postgis.org/docs/ST_DWithin.html>`_: Returns true if the geometries are within the specified distance (radius) of one another. |
---|
| 177 | |
---|
| 178 | `ST_Equals(geometry A, geometry B) <http://postgis.org/docs/ST_Equals.html>`_: Returns true if the given geometries represent the same geometry. Directionality is ignored. |
---|
| 179 | |
---|
| 180 | `ST_Intersects(geometry A, geometry B) <http://postgis.org/docs/ST_Intersects.html>`_: Returns TRUE if the Geometries/Geography "spatially intersect" - (share any portion of space) and FALSE if they don't (they are Disjoint). |
---|
| 181 | |
---|
| 182 | `ST_Overlaps(geometry A, geometry B) <http://postgis.org/docs/ST_Overlaps.html>`_: Returns TRUE if the Geometries share space, are of the same dimension, but are not completely contained by each other. |
---|
| 183 | |
---|
| 184 | `ST_Touches(geometry A, geometry B) <http://postgis.org/docs/ST_Touches.html>`_: Returns TRUE if the geometries have at least one point in common, but their interiors do not intersect. |
---|
| 185 | |
---|
| 186 | `ST_Within(geometry A , geometry B) <http://postgis.org/docs/ST_Within.html>`_: Returns true if the geometry A is completely inside geometry B |
---|
| 187 | |
---|
| 188 | |
---|
| 189 | |
---|