postgis_adapter 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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?