postgis_adapter 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,158 @@
1
+ # #
2
+ #
3
+ # PostGIS Adapter - http://github.com/nofxx/postgis_adapter
4
+ #
5
+ # Hope you enjoy this plugin.
6
+ #
7
+ #
8
+ #
9
+ # Post any bugs/suggestions to the lighthouse tracker:
10
+ # http://nofxx.lighthouseapp.com/projects/20712-postgisadapter
11
+ #
12
+ #
13
+ # Some links:
14
+ #
15
+ # PostGis Manual - http://postgis.refractions.net/documentation/manual-svn/ch07.html
16
+ # Earth Spheroid - http://en.wikipedia.org/wiki/Figure_of_the_Earth
17
+ #
18
+ #
19
+ #
20
+ module PostgisFunctions
21
+ # EARTH_SPHEROID = "'SPHEROID[\"GRS-80\",6378137,298.257222101]'"
22
+
23
+ EARTH_SPHEROID = "'SPHEROID[\"IERS_2003\",6378136.6,298.25642]'"
24
+
25
+ def postgis_calculate(operation, subjects, options = nil)
26
+ subjects = [subjects] unless subjects.respond_to?(:map)
27
+ return execute_geometrical_calculation(operation, subjects, options)
28
+ rescue Exception => e
29
+ raise StandardError, "#{e}"
30
+ end
31
+
32
+
33
+ private
34
+
35
+
36
+ # Construct the postgis sql query
37
+ # TODO: ST_Transform() ?? # Convert between distances. Implement this?
38
+ #
39
+ # Area return in square feet
40
+ # Distance/DWithin/Length/Perimeter — in projected units.
41
+ # DistanceSphere/Spheroid — in meters.
42
+ #
43
+ #
44
+ def construct_geometric_sql(type,geoms,options)
45
+
46
+ tables = geoms.map do |t| {
47
+ :class => t.class.to_s.downcase.pluralize,
48
+ :uid => unique_identifier,
49
+ :id => t[:id] }
50
+ end
51
+
52
+ fields = tables.map { |f| "#{f[:uid]}.geom" } # W1.geom
53
+ conditions = tables.map { |f| "#{f[:uid]}.id = #{f[:id]}" } # W1.id = 5
54
+ tables.map! { |f| "#{f[:class]} #{f[:uid]}" } # streets W1
55
+
56
+ #
57
+ # Data => SELECT Func(A,B)
58
+ # BBox => SELECT (A <=> B)
59
+ #
60
+ if type == :bbox
61
+ opcode = nil
62
+ s_join = " #{options} "
63
+ else
64
+ opcode = type.to_s
65
+ opcode = "ST_#{opcode}" unless opcode =~ /th3d|pesinter/
66
+ s_join = ","
67
+ fields << options if options
68
+ end
69
+
70
+ sql = "SELECT #{opcode}(#{fields.join(s_join)}) "
71
+ sql << "FROM #{tables.join(",")} " if tables
72
+ sql << "WHERE #{conditions.join(" AND ")}" if conditions
73
+ #p sql; sql
74
+ end
75
+
76
+ #
77
+ # Execute the query and parse the return.
78
+ # We may receive:
79
+ #
80
+ # "t" or "f" for boolean queries
81
+ # BIGHASH for geometries
82
+ # HASH for ST_Relate
83
+ # Rescue a float
84
+ #
85
+ def execute_geometrical_calculation(operation, subject, options) #:nodoc:
86
+ value = connection.select_value(construct_geometric_sql(operation, subject, options))
87
+ return nil unless value
88
+ if value =~ /t|f/
89
+ {"f" => false, "t" => true}[value]
90
+ else
91
+ GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(value) rescue value
92
+ end
93
+ end
94
+
95
+ # Get a unique ID for tables
96
+ def unique_identifier
97
+ @u_id ||= "W1"
98
+ @u_id = @u_id.succ
99
+ end
100
+
101
+ end
102
+
103
+ #
104
+ # POINT(0 0)
105
+ # LINESTRING(0 0,1 1,1 2)
106
+ # POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
107
+ # MULTIPOINT(0 0,1 2)
108
+ # MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))
109
+ # MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ..)
110
+ # GEOMETRYCOLLECTION(POINT(2 3),LINESTRING((2 3,3 4)))
111
+ #
112
+ #Accessors
113
+ #
114
+ #ST_Dump
115
+ #ST_ExteriorRing
116
+ #ST_GeometryN
117
+ #ST_GeometryType
118
+ #ST_InteriorRingN
119
+ #ST_IsEmpty
120
+ #ST_IsRing
121
+ #ST_IsSimple
122
+ #ST_IsValid
123
+ #ST_mem_size
124
+ #ST_M
125
+ #ST_NumGeometries
126
+ #ST_NumInteriorRings
127
+ #ST_PointN
128
+ #ST_SetSRID
129
+ #ST_Summary1
130
+ #ST_X
131
+ #ST_XMin,ST_XMax
132
+ #ST_Y
133
+ #YMin,YMax
134
+ #ST_Z
135
+ #ZMin,ZMax
136
+
137
+ #OUTPUT
138
+
139
+ #ST_AsBinary
140
+ #ST_AsText
141
+ #ST_AsEWKB
142
+ #ST_AsEWKT
143
+ #ST_AsHEXEWKB
144
+ #ST_AsGML
145
+ #ST_AsKML
146
+ #ST_AsSVG
147
+ #
148
+ # def distance_convert(value, unit, from = nil)
149
+ # factor = case unit
150
+ # when :km, :kilo then 1
151
+ # when :miles,:mile then 0.62137119
152
+ # when :cm, :cent then 0.1
153
+ # when :nmi, :nmile then 0.5399568
154
+ # end
155
+ # factor *= 1e3 if from
156
+ # value * factor
157
+ # end #use all commands in lowcase form
158
+ #opcode = opcode.camelize unless opcode =~ /spher|max|npoints/
@@ -0,0 +1,128 @@
1
+ ###
2
+ ##
3
+ #
4
+ # BBox
5
+ #
6
+ #
7
+ module PostgisFunctions
8
+
9
+ #
10
+ # These operators utilize indexes. They compare geometries by bounding boxes.
11
+ #
12
+ # You can use the literal forms or call directly using the 'bbox' method. eg.:
13
+ #
14
+ # @point.bbox(">>", @area)
15
+ # @point.bbox("|&>", @area)
16
+ #
17
+ #
18
+ # Cheatsheet:
19
+ #
20
+ # A &< B => A overlaps or is to the left of B
21
+ # A &> B => A overlaps or is to the right of B
22
+ # A << B => A is strictly to the left of B
23
+ # A >> B => A is strictly to the right of B
24
+ # A &<| B => A overlaps B or is below B
25
+ # A |&> B => A overlaps or is above B
26
+ # A <<| B => A strictly below B
27
+ # A |>> B => A strictly above B
28
+ # A = B => A bbox same as B bbox
29
+ # A @ B => A completely contained by B
30
+ # A ~ B => A completely contains B
31
+ # A && B => A and B bboxes interact
32
+ # A ~= B => A and B geometries are binary equal?
33
+ #
34
+ def bbox(operator, other)
35
+ postgis_calculate(:bbox, [self, other], operator)
36
+ end
37
+
38
+ #
39
+ # bbox literal method.
40
+ #
41
+ def completely_contained_by? other
42
+ bbox("@", other)
43
+ end
44
+
45
+ #
46
+ # bbox literal method.
47
+ #
48
+ def completely_contains? other
49
+ bbox("~", other)
50
+ end
51
+
52
+ #
53
+ # bbox literal method.
54
+ #
55
+ def overlaps_or_above? other
56
+ bbox("|&>", other)
57
+ end
58
+
59
+ #
60
+ # bbox literal method.
61
+ #
62
+ def overlaps_or_below? other
63
+ bbox("&<|", other)
64
+ end
65
+
66
+ #
67
+ # bbox literal method.
68
+ #
69
+ def overlaps_or_left_of? other
70
+ bbox("&<", other)
71
+ end
72
+
73
+ #
74
+ # bbox literal method.
75
+ #
76
+ def overlaps_or_right_of? other
77
+ bbox("&>", other)
78
+ end
79
+
80
+ #
81
+ # bbox literal method.
82
+ #
83
+ def strictly_above? other
84
+ bbox("|>>", other)
85
+ end
86
+
87
+ #
88
+ # bbox literal method.
89
+ #
90
+ def strictly_below? other
91
+ bbox("<<|", other)
92
+ end
93
+
94
+ #
95
+ # bbox literal method.
96
+ #
97
+ def strictly_left_of? other
98
+ bbox("<<", other)
99
+ end
100
+
101
+ #
102
+ # bbox literal method.
103
+ #
104
+ def strictly_right_of? other
105
+ bbox(">>", other)
106
+ end
107
+
108
+ #
109
+ # bbox literal method.
110
+ #
111
+ def interacts_with? other
112
+ bbox("&&", other)
113
+ end
114
+
115
+ #
116
+ # bbox literal method.
117
+ #
118
+ def binary_equal? other
119
+ bbox("~=", other)
120
+ end
121
+
122
+ #
123
+ # bbox literal method.
124
+ #
125
+ def same_as? other
126
+ bbox("=", other)
127
+ end
128
+ end
@@ -0,0 +1,64 @@
1
+ module PostgisFunctions
2
+
3
+
4
+ ###
5
+ ##
6
+ #
7
+ # Class Methods
8
+ #
9
+ # Falling back to AR here.
10
+ #
11
+ module ClassMethods
12
+
13
+ #
14
+ # Returns the closest record
15
+ #
16
+ def closest_to(p, srid=4326)
17
+ find(:first, :order => "ST_Distance(geom, GeomFromText('POINT(#{p.x} #{p.y})', #{srid}))" )
18
+ end
19
+
20
+ def close_to(p, srid=4326)
21
+ find(:all, :order => "ST_Distance(geom, GeomFromText('POINT(#{p.x} #{p.y})', #{srid}))" )
22
+ end
23
+
24
+ #
25
+ #
26
+ #
27
+ def by_length sort='asc'
28
+ find(:all, :order => "ST_length(geom) #{sort}" )
29
+ end
30
+
31
+ def longest
32
+ find(:first, :order => "ST_length(geom) DESC")
33
+ end
34
+
35
+ def contains(p, srid=4326)
36
+ find(:all, :conditions => ["ST_Contains(geom, GeomFromText('POINT(#{p.x} #{p.y})', #{srid}))"])
37
+ end
38
+
39
+ def contain(p, srid=4326)
40
+ find(:first, :conditions => ["ST_Contains(geom, GeomFromText('POINT(#{p.x} #{p.y})', #{srid}))"])
41
+ end
42
+
43
+ def by_area sort='asc'
44
+ find(:all, :order => "ST_Area(geom) #{sort}" )
45
+ end
46
+
47
+ def by_perimeter sort='asc'
48
+ find(:all, :order => "ST_Perimeter(geom) #{sort}" )
49
+ end
50
+
51
+ def all_within(other, margin=1)
52
+ # find(:all, :conditions => "ST_DWithin(geom, ST_GeomFromEWKB(E'#{other.as_ewkt}'), #{margin})")
53
+ find(:all, :conditions => "ST_DWithin(geom, ST_GeomFromEWKT(E'#{other.as_hex_ewkb}'), #{margin})")
54
+ end
55
+
56
+ def by_boundaries sort='asc'
57
+ find(:all, :order => "ST_Boundary(geom) #{sort}" )
58
+ end
59
+
60
+ end
61
+
62
+
63
+
64
+ end
@@ -0,0 +1,438 @@
1
+ # #
2
+ #
3
+ # COMMON GEOMETRICAL FUNCTIONS
4
+ #
5
+ # The methods here can be used by all geoms.
6
+ #
7
+
8
+ module PostgisFunctions
9
+
10
+ #
11
+ # True if the given geometries represent the same geometry.
12
+ # Directionality is ignored.
13
+ #
14
+ # Returns TRUE if the given Geometries are "spatially equal".
15
+ # Use this for a 'better' answer than '='. Note by spatially equal we
16
+ # mean ST_Within(A,B) = true and ST_Within(B,A) = true and also mean ordering
17
+ # of points can be different but represent the same geometry structure.
18
+ # To verify the order of points is consistent, use ST_OrderingEquals
19
+ # (it must be noted ST_OrderingEquals is a little more stringent than
20
+ # simply verifying order of points are the same).
21
+ #
22
+ # This function will return false if either geometry is invalid even
23
+ # if they are binary equal.
24
+ #
25
+ # Returns Boolean ST_Equals(geometry A, geometry B);
26
+ #
27
+ def spatially_equal?(other)
28
+ postgis_calculate(:equals, [self, other])
29
+ end
30
+
31
+ #
32
+ # Returns the minimum bounding box for the supplied geometry, as a geometry.
33
+ # The polygon is defined by the corner points of the bounding box
34
+ # ((MINX, MINY), (MINX, MAXY), (MAXX, MAXY), (MAXX, MINY), (MINX, MINY)).
35
+ # PostGIS will add a ZMIN/ZMAX coordinate as well/
36
+ #
37
+ # Degenerate cases (vertical lines, points) will return a geometry of
38
+ # lower dimension than POLYGON, ie. POINT or LINESTRING.
39
+ #
40
+ # In PostGIS, the bounding box of a geometry is represented internally using
41
+ # float4s instead of float8s that are used to store geometries. The bounding
42
+ # box coordinates are floored, guarenteeing that the geometry is contained
43
+ # entirely within its bounds. This has the advantage that a geometry's
44
+ # bounding box is half the size as the minimum bounding rectangle,
45
+ # which means significantly faster indexes and general performance.
46
+ # But it also means that the bounding box is NOT the same as the minimum
47
+ # bounding rectangle that bounds the geome.
48
+ #
49
+ # Returns GeometryCollection ST_Envelope(geometry g1);
50
+ #
51
+ def envelope
52
+ postgis_calculate(:envelope, self)
53
+ end
54
+
55
+ #
56
+ # Computes the geometric center of a geometry, or equivalently,
57
+ # the center of mass of the geometry as a POINT. For [MULTI]POINTs, this is
58
+ # computed as the arithmetric mean of the input coordinates.
59
+ # For [MULTI]LINESTRINGs, this is computed as the weighted length of each
60
+ # line segment. For [MULTI]POLYGONs, "weight" is thought in terms of area.
61
+ # If an empty geometry is supplied, an empty GEOMETRYCOLLECTION is returned.
62
+ # If NULL is supplied, NULL is returned.
63
+ #
64
+ # The centroid is equal to the centroid of the set of component Geometries of
65
+ # highest dimension (since the lower-dimension geometries contribute zero
66
+ # "weight" to the centroid).
67
+ #
68
+ # Computation will be more accurate if performed by the GEOS module (enabled at compile time).
69
+ #
70
+ # http://postgis.refractions.net/documentation/manual-svn/ST_Centroid.html
71
+ #
72
+ # Returns Geometry ST_Centroid(geometry g1);
73
+ #
74
+ def centroid
75
+ postgis_calculate(:centroid, self)
76
+ end
77
+
78
+ #
79
+ # Returns the closure of the combinatorial boundary of this Geometry.
80
+ # The combinatorial boundary is defined as described in section 3.12.3.2 of the
81
+ # OGC SPEC. Because the result of this function is a closure, and hence topologically
82
+ # closed, the resulting boundary can be represented using representational
83
+ # geometry primitives as discussed in the OGC SPEC, section 3.12.2.
84
+ #
85
+ # Do not call with a GEOMETRYCOLLECTION as an argument.
86
+ #
87
+ # Performed by the GEOS module.
88
+ #
89
+ # Returns Geometry ST_Boundary(geometry geomA);
90
+ #
91
+ def boundary
92
+ postgis_calculate(:boundary, self)
93
+ end
94
+
95
+ #
96
+ # 2D minimum cartesian distance between two geometries in projected units.
97
+ #
98
+ # Returns Float ST_Distance(geometry g1, geometry g2);
99
+ #
100
+ def distance_to(other)
101
+ postgis_calculate(:distance, [self, other]).to_f
102
+ end
103
+
104
+ #
105
+ # True if geometry A is completely inside geometry B.
106
+ #
107
+ # For this function to make sense, the source geometries must both be of the same
108
+ # coordinate projection, having the same SRID. It is a given that
109
+ # if ST_Within(A,B) is true and ST_Within(B,A) is true, then the
110
+ # two geometries are considered spatially equal.
111
+ #
112
+ # This function call will automatically include a bounding box comparison that will
113
+ # make use of any indexes that are available on the geometries. To avoid index use,
114
+ # use the function _ST_Within.
115
+ #
116
+ # Do not call with a GEOMETRYCOLLECTION as an argument
117
+ # Do not use this function with invalid geometries. You will get unexpected results.
118
+ #
119
+ # Performed by the GEOS module.
120
+ #
121
+ # Returns Boolean ST_Within(geometry A, geometry B);
122
+ #
123
+ def within? other
124
+ postgis_calculate(:within, [self, other])
125
+ end
126
+
127
+ #
128
+ # True if the geometries are within the specified distance of one another.
129
+ # The distance is specified in units defined by the spatial reference system
130
+ # of the geometries. For this function to make sense, the source geometries
131
+ # must both be of the same coorindate projection, having the same SRID.
132
+ #
133
+ # Returns boolean ST_DWithin(geometry g1, geometry g2, double precision distance);
134
+ #
135
+ def d_within?(other, margin=0.1)
136
+ postgis_calculate(:dwithin, [self, other], margin)
137
+ end
138
+ alias_method "in_bounds?", "d_within?"
139
+
140
+ #
141
+ # True if geometry B is completely inside geometry A.
142
+ #
143
+ # For this function to make sense, the source geometries must both be of the same
144
+ # coordinate projection, having the same SRID. 'contains?' is the inverse of 'within?'.
145
+ #
146
+ # So a.contains?(b) is like b.within?(a) except in the case of invalid
147
+ # geometries where the result is always false regardless or not defined.
148
+ #
149
+ # Do not call with a GEOMETRYCOLLECTION as an argument
150
+ # Do not use this function with invalid geometries. You will get unexpected results.
151
+ #
152
+ # Performed by the GEOS module
153
+ #
154
+ # Returns Boolean ST_Contains(geometry geomA, geometry geomB);
155
+ #
156
+ def contains? other
157
+ postgis_calculate(:contains, [self, other])
158
+ end
159
+
160
+ #
161
+ # True if no point in Geometry A is outside Geometry B
162
+ #
163
+ # This function call will automatically include a bounding box comparison that
164
+ # will make use of any indexes that are available on the geometries. To avoid
165
+ # index use, use the function _ST_CoveredBy.
166
+ #
167
+ # Do not call with a GEOMETRYCOLLECTION as an argument.
168
+ # Do not use this function with invalid geometries. You will get unexpected results.
169
+ #
170
+ # Performed by the GEOS module.
171
+ #
172
+ # Aliased as 'inside?'
173
+ #
174
+ # Returns Boolean ST_CoveredBy(geometry geomA, geometry geomB);
175
+ #
176
+ def covered_by? other
177
+ postgis_calculate(:coveredby, [self, other])
178
+ end
179
+ alias_method "inside?", "covered_by?"
180
+
181
+ #
182
+ # Eye-candy. See 'covered_by?'.
183
+ #
184
+ # Returns !(Boolean ST_CoveredBy(geometry geomA, geometry geomB);)
185
+ #
186
+ def outside? other
187
+ !covered_by? other
188
+ end
189
+
190
+ #
191
+ # True if the Geometries do not "spatially intersect" - if they
192
+ # do not share any space together.
193
+ #
194
+ # Overlaps, Touches, Within all imply geometries are not spatially disjoint.
195
+ # If any of the aforementioned returns true, then the geometries are not
196
+ # spatially disjoint. Disjoint implies false for spatial intersection.
197
+ #
198
+ # Do not call with a GEOMETRYCOLLECTION as an argument.
199
+ #
200
+ # Returns boolean ST_Disjoint( geometry A , geometry B );
201
+ #
202
+ def disjoint? other
203
+ postgis_calculate(:disjoint, [self, other])
204
+ end
205
+
206
+ #
207
+ # How many dimensions the geom is made of (2, 3 or 4)
208
+ #
209
+ # Returns Integer ST_Dimension(geom g1)
210
+ #
211
+ def dimension
212
+ postgis_calculate(:dimension, self).to_i
213
+ end
214
+
215
+ #
216
+ # Returns a "simplified" version of the given geometry using the Douglas-Peuker
217
+ # algorithm. Will actually do something only with (multi)lines and (multi)polygons
218
+ # but you can safely call it with any kind of geometry. Since simplification
219
+ # occurs on a object-by-object basis you can also feed a GeometryCollection to this
220
+ # function.
221
+ #
222
+ # Note that returned geometry might loose its simplicity (see 'is_simple?').
223
+ # Topology may not be preserved and may result in invalid geometries.
224
+ # Use 'simplify_preserve_topology' to preserve topology.
225
+ #
226
+ # Performed by the GEOS Module.
227
+ #
228
+ # Returns Geometry ST_Simplify(geometry geomA, float tolerance);
229
+ #
230
+ def simplify(tolerance=0.1)
231
+ postgis_calculate(:simplify, self, tolerance)
232
+ end
233
+
234
+
235
+ def simplify!(tolerance=0.1)
236
+ #FIXME: not good..
237
+ self.geom = simplify
238
+ end
239
+
240
+ #
241
+ # Returns a "simplified" version of the given geometry using the Douglas-Peuker
242
+ # algorithm. Will avoid creating derived geometries (polygons in particular) that
243
+ # are invalid. Will actually do something only with (multi)lines and (multi)polygons
244
+ # but you can safely call it with any kind of geometry. Since simplification occurs
245
+ # on a object-by-object basis you can also feed a GeometryCollection to this function.
246
+ #
247
+ # Performed by the GEOS module. Requires GEOS 3.0.0+
248
+ #
249
+ # Returns Geometry ST_SimplifyPreserveTopology(geometry geomA, float tolerance);
250
+ #
251
+ def simplify_preserve_topology(tolerance=0.1)
252
+ postgis_calculate(:simplifypreservetopology, self, tolerance)
253
+ end
254
+
255
+ #
256
+ # True if Geometries "spatially intersect", share any portion of space.
257
+ # False if they don't (they are Disjoint).
258
+ #
259
+ # 'overlaps?', 'touches?', 'within?' all imply spatial intersection.
260
+ # If any of the aforementioned returns true, then the geometries also
261
+ # spatially intersect. 'disjoint?' implies false for spatial intersection.
262
+ #
263
+ # Returns Boolean ST_Intersects(geometry geomA, geometry geomB);
264
+ #
265
+ def intersects? other
266
+ postgis_calculate(:intersects, [self, other])
267
+ end
268
+
269
+ #
270
+ # True if a Geometry`s Envelope "spatially intersect", share any portion of space.
271
+ #
272
+ # It`s 'intersects?', for envelopes.
273
+ #
274
+ # Returns Boolean SE_EnvelopesIntersect(geometry geomA, geometry geomB);
275
+ #
276
+ def envelopes_intersect? other
277
+ postgis_calculate(:se_envelopesintersect, [self, other])
278
+ end
279
+
280
+ #
281
+ # Geometry that represents the point set intersection of the Geometries.
282
+ # In other words - that portion of geometry A and geometry B that is shared between
283
+ # the two geometries. If the geometries do not share any space (are disjoint),
284
+ # then an empty geometry collection is returned.
285
+ #
286
+ # 'intersection' in conjunction with intersects? is very useful for clipping
287
+ # geometries such as in bounding box, buffer, region queries where you only want
288
+ # to return that portion of a geometry that sits in a country or region of interest.
289
+ #
290
+ # Do not call with a GEOMETRYCOLLECTION as an argument.
291
+ # Performed by the GEOS module.
292
+ #
293
+ # Returns Geometry ST_Intersection(geometry geomA, geometry geomB);
294
+ #
295
+ def intersection other
296
+ postgis_calculate(:intersection, [self, other])
297
+ end
298
+
299
+ #
300
+ # True if the Geometries share space, are of the same dimension, but are
301
+ # not completely contained by each other. They intersect, but one does not
302
+ # completely contain another.
303
+ #
304
+ # Do not call with a GeometryCollection as an argument
305
+ # This function call will automatically include a bounding box comparison that
306
+ # will make use of any indexes that are available on the geometries. To avoid
307
+ # index use, use the function _ST_Overlaps.
308
+ #
309
+ # Performed by the GEOS module.
310
+ #
311
+ # Returns Boolean ST_Overlaps(geometry A, geometry B);
312
+ #
313
+ def overlaps? other
314
+ postgis_calculate(:overlaps, [self, other])
315
+ end
316
+
317
+ # True if the geometries have at least one point in common,
318
+ # but their interiors do not intersect.
319
+ #
320
+ # If the only points in common between g1 and g2 lie in the union of the
321
+ # boundaries of g1 and g2. The 'touches?' relation applies to all Area/Area,
322
+ # Line/Line, Line/Area, Point/Area and Point/Line pairs of relationships,
323
+ # but not to the Point/Point pair.
324
+ #
325
+ # Returns Boolean ST_Touches(geometry g1, geometry g2);
326
+ #
327
+ def touches? other
328
+ postgis_calculate(:touches, [self, other])
329
+ end
330
+
331
+ #
332
+ # The convex hull of a geometry represents the minimum closed geometry that
333
+ # encloses all geometries within the set.
334
+ #
335
+ # It is usually used with MULTI and Geometry Collections. Although it is not
336
+ # an aggregate - you can use it in conjunction with ST_Collect to get the convex
337
+ # hull of a set of points. ST_ConvexHull(ST_Collect(somepointfield)).
338
+ # It is often used to determine an affected area based on a set of point observations.
339
+ #
340
+ # Performed by the GEOS module.
341
+ #
342
+ # Returns Geometry ST_ConvexHull(geometry geomA);
343
+ #
344
+ def convex_hull
345
+ postgis_calculate(:convexhull, self)
346
+ end
347
+
348
+ #
349
+ # Creates an areal geometry formed by the constituent linework of given geometry.
350
+ # The return type can be a Polygon or MultiPolygon, depending on input.
351
+ # If the input lineworks do not form polygons NULL is returned. The inputs can
352
+ # be LINESTRINGS, MULTILINESTRINGS, POLYGONS, MULTIPOLYGONS, and GeometryCollections.
353
+ #
354
+ # Returns Boolean ST_BuildArea(geometry A);
355
+ #
356
+ def build_area
357
+ postgis_calculate(:buildarea, self)
358
+ end
359
+
360
+ #
361
+ # Returns true if this Geometry has no anomalous geometric points, such as
362
+ # self intersection or self tangency.
363
+ #
364
+ # Returns boolean ST_IsSimple(geometry geomA);
365
+ #
366
+ def is_simple?
367
+ postgis_calculate(:issimple, self)
368
+ end
369
+ alias_method "simple?", "is_simple?"
370
+
371
+ #
372
+ # Aggregate. Creates a GeometryCollection containing possible polygons formed
373
+ # from the constituent linework of a set of geometries.
374
+ #
375
+ # Geometry Collections are often difficult to deal with with third party tools,
376
+ # so use ST_Polygonize in conjunction with ST_Dump to dump the polygons out into
377
+ # individual polygons.
378
+ #
379
+ # Returns Geometry ST_Polygonize(geometry set geomfield);
380
+ #
381
+ def polygonize#(geom)
382
+ postgis_calculate(:polygonize, self)
383
+ end
384
+
385
+ #
386
+ # Returns true if this Geometry is spatially related to anotherGeometry,
387
+ # by testing for intersections between the Interior, Boundary and Exterior
388
+ # of the two geometries as specified by the values in the
389
+ # intersectionPatternMatrix. If no intersectionPatternMatrix is passed in,
390
+ # then returns the maximum intersectionPatternMatrix that relates the 2 geometries.
391
+ #
392
+ #
393
+ # Version 1: Takes geomA, geomB, intersectionMatrix and Returns 1 (TRUE) if
394
+ # this Geometry is spatially related to anotherGeometry, by testing for
395
+ # intersections between the Interior, Boundary and Exterior of the two
396
+ # geometries as specified by the values in the intersectionPatternMatrix.
397
+ #
398
+ # This is especially useful for testing compound checks of intersection,
399
+ # crosses, etc in one step.
400
+ #
401
+ # Do not call with a GeometryCollection as an argument
402
+ #
403
+ # This is the "allowable" version that returns a boolean, not an integer.
404
+ # This is defined in OGC spec.
405
+ # This DOES NOT automagically include an index call. The reason for that
406
+ # is some relationships are anti e.g. Disjoint. If you are using a relationship
407
+ # pattern that requires intersection, then include the && index call.
408
+ #
409
+ # Version 2: Takes geomA and geomB and returns the DE-9IM
410
+ # (dimensionally extended nine-intersection matrix)
411
+ #
412
+ # Do not call with a GeometryCollection as an argument
413
+ # Not in OGC spec, but implied. see s2.1.13.2
414
+ #
415
+ # Both Performed by the GEOS module
416
+ #
417
+ # Returns:
418
+ #
419
+ # text ST_Relate(geometry geomA, geometry geomB);
420
+ # boolean ST_Relate(geometry geomA, geometry geomB, text intersectionPatternMatrix);
421
+ #
422
+ def relate?(other, m = nil)
423
+ # Relate is case sentitive.......
424
+ m = "'#{m}'" if m
425
+ postgis_calculate("Relate", [self, other], m)
426
+ end
427
+
428
+ end
429
+
430
+ # NEW
431
+ #ST_OrderingEquals — Returns true if the given geometries represent the same geometry and points are in the same directional order.
432
+ #boolean ST_OrderingEquals(g
433
+ # ST_PointOnSurface — Returns a POINT guaranteed to lie on the surface.
434
+ #geometry ST_PointOnSurface(geometry g1);eometry A, geometry B);
435
+
436
+
437
+ #x ST_SnapToGrid(geometry, geometry, sizeX, sizeY, sizeZ, sizeM)
438
+ # ST_X , ST_Y, SE_M, SE_Z, SE_IsMeasured has_m?