GeoRuby 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -7
- data/lib/geo_ruby/simple_features/ewkb_parser.rb +3 -0
- data/lib/geo_ruby/simple_features/ewkt_parser.rb +237 -65
- data/lib/geo_ruby/simple_features/geometry_collection.rb +19 -38
- data/lib/geo_ruby/simple_features/line_string.rb +17 -39
- data/lib/geo_ruby/simple_features/multi_point.rb +1 -1
- data/lib/geo_ruby/simple_features/point.rb +6 -0
- data/lib/geo_ruby/simple_features/polygon.rb +9 -38
- data/rakefile.rb +3 -3
- data/test/test_ewkt_parser.rb +10 -1
- data/test/test_simple_features.rb +22 -3
- metadata +3 -3
data/README
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=GeoRuby
|
2
|
-
This is GeoRuby 0.
|
2
|
+
This is GeoRuby 0.2.1. It is intended as a holder for data returned from PostGIS and the Spatial Extensions of MySql. The data model roughly follows the OGC "Simple Features for SQL" specification (see http://www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections).
|
3
3
|
|
4
4
|
===Available data types
|
5
5
|
The following geometric data types are provided :
|
@@ -15,18 +15,16 @@ The following geometric data types are provided :
|
|
15
15
|
They can be in 2D, 3DZ, 3DM, and 4D.
|
16
16
|
|
17
17
|
===Input and output
|
18
|
-
These geometries can be input and output in WKB/EWKB/WKT/EWKT format (as well as the related HexWKB and HexEWKB formats). HexEWKB and
|
18
|
+
These geometries can be input and output in WKB/EWKB/WKT/EWKT format (as well as the related HexWKB and HexEWKB formats). HexEWKB and WKB are the default form under which geometric data is returned respectively from PostGIS and MySql.
|
19
19
|
|
20
20
|
===Installation
|
21
21
|
To install the latest version, just type :
|
22
22
|
gem install GeoRuby
|
23
23
|
|
24
24
|
===Changes since the last version
|
25
|
-
-
|
26
|
-
-
|
27
|
-
-
|
28
|
-
- Suppression of the static creation methods +from_raw_point_sequence+ (for some geometric types) and +from_raw_point_sequences+ (for other), to build a geometry from a list of point coordinates. They have been replaced by a +from_coordinates+ for all types.
|
29
|
-
- The static geometry construction method +from_hexewkb+ has been replaced with +from_hex_ewkb+.
|
25
|
+
- Correction of the output of the MultiPoint EWKT string to follow the specification, instead of what is shown in the examples (of the specification) and output by PostGIS. For example, the string previously output as MULTIPOINT(123.4 123.5,456.7 678.887) will now be output as MULTIPOINT((123.4 123.5),(456.7 678.887))
|
26
|
+
- Modification of the EWKT input to support the correct MultiPoint EWKT format, on top of the previous one. So both MULTIPOINT(123.4 123.5,456.7 678.887) and MULTIPOINT((123.4 123.5),(456.7 678.887)) would be accepted as valid MultiPoint strings.
|
27
|
+
- Addition of a +bounding_box+ method on geometries. Return an array of 2 points representing the 2 corners of the box.
|
30
28
|
|
31
29
|
===License
|
32
30
|
GeoRuby is released under the MIT license.
|
@@ -10,6 +10,7 @@ require 'geo_ruby/simple_features/geometry_collection'
|
|
10
10
|
module GeoRuby
|
11
11
|
module SimpleFeatures
|
12
12
|
|
13
|
+
#Raised when an error in the EWKB string is detected
|
13
14
|
class EWKBFormatError < StandardError
|
14
15
|
end
|
15
16
|
|
@@ -20,6 +21,8 @@ module GeoRuby
|
|
20
21
|
# ewkb_parser = EWKBParser::new(factory)
|
21
22
|
# ewkb_parser.parse(<EWKB String>)
|
22
23
|
# geometry = @factory.geometry
|
24
|
+
#
|
25
|
+
#You can also use directly the static method Geometry.from_ewkb
|
23
26
|
class EWKBParser
|
24
27
|
|
25
28
|
def initialize(factory)
|
@@ -12,6 +12,7 @@ require 'strscan'
|
|
12
12
|
module GeoRuby
|
13
13
|
module SimpleFeatures
|
14
14
|
|
15
|
+
#Raised when an error in the EWKT string is detected
|
15
16
|
class EWKTFormatError < StandardError
|
16
17
|
end
|
17
18
|
|
@@ -22,6 +23,8 @@ module GeoRuby
|
|
22
23
|
# ewkt_parser = EWKTParser::new(factory)
|
23
24
|
# ewkt_parser.parse(<EWKT String>)
|
24
25
|
# geometry = @factory.geometry
|
26
|
+
#
|
27
|
+
#You can also use directly the static method Geometry.from_ewkt
|
25
28
|
class EWKTParser
|
26
29
|
|
27
30
|
def initialize(factory)
|
@@ -40,125 +43,294 @@ module GeoRuby
|
|
40
43
|
#Parses the ewkt string passed as argument and notifies the factory of events
|
41
44
|
def parse(ewkt)
|
42
45
|
@factory.reset
|
46
|
+
@tokenizer_structure = TokenizerStructure.new(ewkt)
|
43
47
|
@with_z=false
|
44
48
|
@with_m=false
|
45
|
-
|
49
|
+
@is_3dm = false
|
50
|
+
parse_geometry(true)
|
46
51
|
@srid=nil
|
47
52
|
end
|
48
53
|
|
49
54
|
private
|
50
|
-
def parse_geometry(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
def parse_geometry(srid_allowed)
|
56
|
+
|
57
|
+
token = @tokenizer_structure.get_next_token
|
58
|
+
if token == 'SRID'
|
59
|
+
#SRID present
|
60
|
+
raise EWKTFormatError.new("SRID not allowed at this position") if(!srid_allowed)
|
61
|
+
if @tokenizer_structure.get_next_token != '='
|
62
|
+
raise EWKTFormatError.new("Invalid SRID expression")
|
55
63
|
else
|
56
|
-
|
57
|
-
raise EWKTFormatError.new("SRID
|
64
|
+
@srid = @tokenizer_structure.get_next_token.to_i
|
65
|
+
raise EWKTFormatError.new("Invalid SRID separator") if @tokenizer_structure.get_next_token != ';'
|
66
|
+
geom_type = @tokenizer_structure.get_next_token
|
58
67
|
end
|
68
|
+
|
59
69
|
else
|
60
70
|
#to manage multi geometries : the srid is not present in sub_geometries, therefore we take the srid of the parent ; if it is the root, we take the default srid
|
61
71
|
@srid= @srid || DEFAULT_SRID
|
72
|
+
geom_type = token
|
62
73
|
end
|
63
74
|
|
64
|
-
if
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
geom_type.chop! #remove the M
|
69
|
-
end
|
70
|
-
#change the parsing method : this one really is ugly...
|
71
|
-
if @parse_options.has_key?(geom_type) and scanner.scan(/^\((.*)\)$/)
|
72
|
-
@parse_options[geom_type].call(scanner[1])
|
73
|
-
else
|
74
|
-
raise EWKTFormatError.new("Bad token")
|
75
|
-
end
|
75
|
+
if geom_type[-1] == ?M
|
76
|
+
@is_3dm=true
|
77
|
+
@with_m=true
|
78
|
+
geom_type.chop! #remove the M
|
76
79
|
end
|
77
80
|
|
81
|
+
if @parse_options.has_key?(geom_type)
|
82
|
+
@parse_options[geom_type].call
|
83
|
+
else
|
84
|
+
raise EWKTFormatError.new("Urecognized geometry type: #{geom_type}")
|
85
|
+
end
|
78
86
|
end
|
79
|
-
|
87
|
+
|
88
|
+
def parse_geometry_collection
|
89
|
+
if @tokenizer_structure.get_next_token !='('
|
90
|
+
raise EWKTFormatError.new('Invalid GeometryCollection')
|
91
|
+
end
|
92
|
+
|
80
93
|
@factory.begin_geometry(GeometryCollection,@srid)
|
81
|
-
|
82
|
-
|
83
|
-
|
94
|
+
|
95
|
+
token = ''
|
96
|
+
while token != ')'
|
97
|
+
parse_geometry(false)
|
98
|
+
token = @tokenizer_structure.get_next_token
|
99
|
+
if token.nil?
|
100
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
101
|
+
end
|
84
102
|
end
|
85
|
-
|
103
|
+
|
86
104
|
@factory.end_geometry(@with_z,@with_m)
|
87
105
|
end
|
88
106
|
|
89
|
-
def parse_multi_polygon
|
107
|
+
def parse_multi_polygon
|
108
|
+
if @tokenizer_structure.get_next_token !='('
|
109
|
+
raise EWKTFormatError.new('Invalid MultiLineString')
|
110
|
+
end
|
111
|
+
|
90
112
|
@factory.begin_geometry(MultiPolygon,@srid)
|
91
|
-
|
92
|
-
while
|
93
|
-
parse_polygon
|
113
|
+
token = ''
|
114
|
+
while token != ')'
|
115
|
+
parse_polygon
|
116
|
+
token = @tokenizer_structure.get_next_token
|
117
|
+
if token.nil?
|
118
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
119
|
+
end
|
94
120
|
end
|
121
|
+
|
95
122
|
@factory.end_geometry(@with_z,@with_m)
|
96
123
|
end
|
97
124
|
|
98
|
-
def parse_multi_line_string
|
125
|
+
def parse_multi_line_string
|
126
|
+
if @tokenizer_structure.get_next_token !='('
|
127
|
+
raise EWKTFormatError.new('Invalid MultiLineString')
|
128
|
+
end
|
129
|
+
|
99
130
|
@factory.begin_geometry(MultiLineString,@srid)
|
100
|
-
scanner = StringScanner.new(string)
|
101
131
|
|
102
|
-
|
103
|
-
|
132
|
+
token = ''
|
133
|
+
while token != ')'
|
134
|
+
parse_line_string
|
135
|
+
token = @tokenizer_structure.get_next_token
|
136
|
+
if token.nil?
|
137
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
138
|
+
end
|
104
139
|
end
|
140
|
+
|
105
141
|
@factory.end_geometry(@with_z,@with_m)
|
106
142
|
end
|
107
143
|
|
108
|
-
def parse_polygon
|
144
|
+
def parse_polygon
|
145
|
+
if @tokenizer_structure.get_next_token !='('
|
146
|
+
raise EWKTFormatError.new('Invalid Polygon')
|
147
|
+
end
|
148
|
+
|
109
149
|
@factory.begin_geometry(Polygon,@srid)
|
110
|
-
|
111
|
-
|
112
|
-
|
150
|
+
|
151
|
+
token = ''
|
152
|
+
while token != ')'
|
153
|
+
parse_linear_ring
|
154
|
+
token = @tokenizer_structure.get_next_token
|
155
|
+
if token.nil?
|
156
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
157
|
+
end
|
113
158
|
end
|
159
|
+
|
114
160
|
@factory.end_geometry(@with_z,@with_m)
|
115
161
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
162
|
+
|
163
|
+
#must support the PostGIS form and the one in the specification
|
164
|
+
def parse_multi_point
|
165
|
+
if @tokenizer_structure.get_next_token !='('
|
166
|
+
raise EWKTFormatError.new('Invalid MultiPoint')
|
167
|
+
end
|
168
|
+
|
169
|
+
token = @tokenizer_structure.check_next_token
|
170
|
+
if token == '('
|
171
|
+
#specification
|
172
|
+
@factory.begin_geometry(MultiPoint,@srid)
|
173
|
+
|
174
|
+
token = ''
|
175
|
+
while token != ')'
|
176
|
+
parse_point
|
177
|
+
token = @tokenizer_structure.get_next_token
|
178
|
+
if token.nil?
|
179
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
@factory.end_geometry(@with_z,@with_m)
|
184
|
+
else
|
185
|
+
#postgis
|
186
|
+
parse_point_list(MultiPoint)
|
187
|
+
end
|
119
188
|
end
|
120
|
-
|
121
|
-
|
189
|
+
|
190
|
+
def parse_linear_ring
|
191
|
+
if @tokenizer_structure.get_next_token !='('
|
192
|
+
raise EWKTFormatError.new('Invalid Linear ring')
|
193
|
+
end
|
194
|
+
|
195
|
+
parse_point_list(LinearRing)
|
122
196
|
end
|
123
|
-
|
124
|
-
|
197
|
+
|
198
|
+
def parse_line_string
|
199
|
+
if @tokenizer_structure.get_next_token !='('
|
200
|
+
raise EWKTFormatError.new('Invalid Line string')
|
201
|
+
end
|
202
|
+
|
203
|
+
parse_point_list(LineString)
|
125
204
|
end
|
126
|
-
|
127
|
-
|
205
|
+
|
206
|
+
#used to parse line_strings and linear_rings and the PostGIS form of multi_points
|
207
|
+
def parse_point_list(geometry_type)
|
128
208
|
@factory.begin_geometry(geometry_type,@srid)
|
129
|
-
|
130
|
-
|
131
|
-
|
209
|
+
|
210
|
+
token = ''
|
211
|
+
while token != ')'
|
212
|
+
@factory.begin_geometry(Point,@srid)
|
213
|
+
token = parse_coords
|
214
|
+
if token.nil?
|
215
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
216
|
+
end
|
217
|
+
@factory.end_geometry(@with_z,@with_m)
|
132
218
|
end
|
219
|
+
|
133
220
|
@factory.end_geometry(@with_z,@with_m)
|
134
221
|
end
|
135
222
|
|
136
|
-
def parse_point
|
223
|
+
def parse_point
|
224
|
+
if @tokenizer_structure.get_next_token !='('
|
225
|
+
raise EWKTFormatError.new('Invalid Point')
|
226
|
+
end
|
227
|
+
|
137
228
|
@factory.begin_geometry(Point,@srid)
|
138
|
-
|
229
|
+
|
230
|
+
token = parse_coords
|
231
|
+
|
232
|
+
if token != ')'
|
233
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
234
|
+
end
|
235
|
+
|
236
|
+
@factory.end_geometry(@with_z,@with_m)
|
237
|
+
end
|
238
|
+
|
239
|
+
def parse_coords
|
139
240
|
coords = Array.new
|
140
|
-
|
141
|
-
|
241
|
+
x = @tokenizer_structure.get_next_token
|
242
|
+
y = @tokenizer_structure.get_next_token
|
243
|
+
|
244
|
+
if x.nil? or y.nil?
|
245
|
+
raise EWKTFormatError.new("Bad Point format")
|
142
246
|
end
|
143
247
|
|
144
|
-
if
|
145
|
-
@
|
146
|
-
|
147
|
-
if
|
148
|
-
|
248
|
+
if @is_3dm
|
249
|
+
m = @tokenizer_structure.get_next_token
|
250
|
+
|
251
|
+
if m.nil? or m == ',' or m == ')'
|
252
|
+
raise EWKTFormatError.new("No M dimension found")
|
149
253
|
else
|
150
|
-
@
|
151
|
-
@
|
254
|
+
@factory.add_point_x_y_m(x.to_f,y.to_f,m.to_f)
|
255
|
+
@tokenizer_structure.get_next_token
|
152
256
|
end
|
153
257
|
else
|
154
|
-
@
|
155
|
-
|
156
|
-
|
258
|
+
z = @tokenizer_structure.get_next_token
|
259
|
+
|
260
|
+
if z.nil?
|
261
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
262
|
+
end
|
263
|
+
|
264
|
+
if z == ',' or z == ')'
|
265
|
+
#2D : no z no m
|
266
|
+
@factory.add_point_x_y(x.to_f,y.to_f)
|
267
|
+
z
|
268
|
+
else
|
269
|
+
m = @tokenizer_structure.get_next_token
|
270
|
+
if m.nil?
|
271
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
272
|
+
end
|
273
|
+
|
274
|
+
if m == ',' or m ==')'
|
275
|
+
#3Dz : no m
|
276
|
+
@with_z = true
|
277
|
+
@factory.add_point_x_y_z(x.to_f,y.to_f,z.to_f)
|
278
|
+
m
|
279
|
+
else
|
280
|
+
#4D
|
281
|
+
@with_z = true
|
282
|
+
@with_m = true
|
283
|
+
@factory.add_point_x_y_z_m(x.to_f,y.to_f,z.to_f,m.to_f)
|
284
|
+
@tokenizer_structure.get_next_token
|
285
|
+
end
|
286
|
+
end
|
157
287
|
end
|
158
|
-
|
159
|
-
@factory.end_geometry(@with_z,@with_m)
|
160
288
|
end
|
161
289
|
end
|
162
290
|
|
291
|
+
class TokenizerStructure
|
292
|
+
|
293
|
+
def initialize(ewkt)
|
294
|
+
@ewkt = ewkt
|
295
|
+
@scanner = StringScanner.new(ewkt)
|
296
|
+
@regex = /\s*([\w.-]+)s*/
|
297
|
+
end
|
298
|
+
|
299
|
+
def get_next_token
|
300
|
+
if @scanner.scan(@regex).nil?
|
301
|
+
if @scanner.eos?
|
302
|
+
nil
|
303
|
+
else
|
304
|
+
ch = @scanner.getch
|
305
|
+
while ch == ' '
|
306
|
+
ch = @scanner.getch
|
307
|
+
end
|
308
|
+
ch
|
309
|
+
end
|
310
|
+
else
|
311
|
+
@scanner[1]
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
def check_next_token
|
317
|
+
check = @scanner.check(@regex)
|
318
|
+
if check.nil?
|
319
|
+
if @scanner.eos?
|
320
|
+
nil
|
321
|
+
else
|
322
|
+
pos = @scanner.pos
|
323
|
+
while @ewkt[pos].chr == ' '
|
324
|
+
pos+=1
|
325
|
+
end
|
326
|
+
@ewkt[pos].chr
|
327
|
+
end
|
328
|
+
else
|
329
|
+
check
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
163
335
|
end
|
164
336
|
end
|
@@ -10,46 +10,27 @@ module GeoRuby
|
|
10
10
|
super(srid,with_z,with_m)
|
11
11
|
@geometries = []
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#add geometries to the collection
|
18
|
-
def concat(geometries)
|
19
|
-
@geometries.concat geometries
|
20
|
-
end
|
21
|
-
#number of geometries in the collection
|
22
|
-
def length
|
23
|
-
@geometries.length
|
24
|
-
end
|
25
|
-
#gets the nth geometry
|
26
|
-
def [](n)
|
27
|
-
@geometries[n]
|
28
|
-
end
|
29
|
-
#replaces the nth geometry
|
30
|
-
def []=(n,geometry)
|
31
|
-
@geometries[n]=geometry
|
32
|
-
end
|
33
|
-
#iterates over all the geometries
|
34
|
-
def each(&proc)
|
35
|
-
@geometries.each(&proc)
|
36
|
-
end
|
37
|
-
#iterates over all the geometries, passing the index to the bloc
|
38
|
-
def each_index(&proc)
|
39
|
-
@geometries.each_index(&proc)
|
40
|
-
end
|
41
|
-
#inserts geometries at the nth position
|
42
|
-
def insert(n,*geometry)
|
43
|
-
@geometries.insert(n,*geometry)
|
44
|
-
end
|
45
|
-
#index of the geometry
|
46
|
-
def index(geometry)
|
47
|
-
@geometries.index(geometry)
|
13
|
+
|
14
|
+
#Delegate the unknown methods to the geometries array
|
15
|
+
def method_missing(method_name,*args,&b)
|
16
|
+
@geometries.send(method_name,*args,&b)
|
48
17
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
18
|
+
|
19
|
+
#Bounding box in 2D. Returns an array of 2 points
|
20
|
+
def bounding_box
|
21
|
+
max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
|
22
|
+
each do |geometry|
|
23
|
+
bbox = geometry.bounding_box
|
24
|
+
sw = bbox[0]
|
25
|
+
ne = bbox[1]
|
26
|
+
max_y = ne.y if ne.y > max_y
|
27
|
+
min_y = sw.y if sw.y < min_y
|
28
|
+
max_x = ne.x if ne.x > max_x
|
29
|
+
min_x = sw.x if sw.x < min_x
|
30
|
+
end
|
31
|
+
[Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
|
52
32
|
end
|
33
|
+
|
53
34
|
#tests the equality of geometry collections
|
54
35
|
def ==(other_collection)
|
55
36
|
if(other_collection.class != self.class)
|
@@ -11,50 +11,28 @@ module GeoRuby
|
|
11
11
|
super(srid,with_z,with_m)
|
12
12
|
@points=[]
|
13
13
|
end
|
14
|
+
|
15
|
+
#Delegate the unknown methods to the points array
|
16
|
+
def method_missing(method_name,*args,&b)
|
17
|
+
@points.send(method_name,*args,&b)
|
18
|
+
end
|
19
|
+
|
14
20
|
#tests if the line string is closed
|
15
21
|
def is_closed
|
16
22
|
#a bit naive...
|
17
23
|
@points.first == @points.last
|
18
24
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
#accesses the nth point in the line string
|
32
|
-
def [](n)
|
33
|
-
@points[n]
|
34
|
-
end
|
35
|
-
#replaces the nth point in the line string
|
36
|
-
def []=(n,point)
|
37
|
-
@points[n]=point
|
38
|
-
end
|
39
|
-
#iterates over the points in the line string
|
40
|
-
def each(&proc)
|
41
|
-
@points.each(&proc)
|
42
|
-
end
|
43
|
-
#iterates over the points, passing their indices to the bloc
|
44
|
-
def each_index(&proc)
|
45
|
-
@points.each_index(&proc)
|
46
|
-
end
|
47
|
-
#inserts points at the nth position
|
48
|
-
def insert(n,*point)
|
49
|
-
@points.insert(n,*point)
|
50
|
-
end
|
51
|
-
#gets the indices of point
|
52
|
-
def index(point)
|
53
|
-
@points.index(point)
|
54
|
-
end
|
55
|
-
#Removes a slice of points
|
56
|
-
def remove(*slice)
|
57
|
-
@points.slice(*slice)
|
25
|
+
|
26
|
+
#Bounding box in 2D. Returns an array of 2 points
|
27
|
+
def bounding_box
|
28
|
+
max_x, min_x, max_y, min_y = -Float::MAX, Float::MAX, -Float::MAX, Float::MAX
|
29
|
+
each do |point|
|
30
|
+
max_y = point.y if point.y > max_y
|
31
|
+
min_y = point.y if point.y < min_y
|
32
|
+
max_x = point.x if point.x > max_x
|
33
|
+
min_x = point.x if point.x < min_x
|
34
|
+
end
|
35
|
+
[Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
|
58
36
|
end
|
59
37
|
|
60
38
|
#Tests the equality of line strings
|
@@ -15,7 +15,7 @@ module GeoRuby
|
|
15
15
|
|
16
16
|
#Text representation of a MultiPoint
|
17
17
|
def text_representation(allow_z=true,allow_m=true)
|
18
|
-
@geometries.collect{|point| point.text_representation(allow_z,allow_m)}.join(",")
|
18
|
+
"(" + @geometries.collect{|point| point.text_representation(allow_z,allow_m)}.join("),(") + ")"
|
19
19
|
end
|
20
20
|
#WKT geoemtry type
|
21
21
|
def text_geometry_type
|
@@ -25,6 +25,12 @@ module GeoRuby
|
|
25
25
|
@x=x
|
26
26
|
@y=y
|
27
27
|
end
|
28
|
+
|
29
|
+
#Bounding box in 2D. Returns an array of 2 points
|
30
|
+
def bounding_box
|
31
|
+
[Point.from_x_y(@x,@y),Point.from_x_y(@x,@y)] #not too difficult...
|
32
|
+
end
|
33
|
+
|
28
34
|
#tests the equality of the position of points + m
|
29
35
|
def ==(other_point)
|
30
36
|
if other_point.class != self.class
|
@@ -11,46 +11,17 @@ module GeoRuby
|
|
11
11
|
super(srid,with_z,with_m)
|
12
12
|
@rings = []
|
13
13
|
end
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#add one or more rings to the polygon
|
19
|
-
def concat(rings)
|
20
|
-
@rings.concat rings
|
21
|
-
end
|
22
|
-
#number of linear rings in the polygon
|
23
|
-
def length
|
24
|
-
@rings.length
|
25
|
-
end
|
26
|
-
#access the nth linear ring
|
27
|
-
def [](n)
|
28
|
-
@rings[n]
|
29
|
-
end
|
30
|
-
#modifies the value of the nth linear ring
|
31
|
-
def []=(n,ring)
|
32
|
-
@rings[n]=ring
|
33
|
-
end
|
34
|
-
#iterates over the linear rings
|
35
|
-
def each(&proc)
|
36
|
-
@rings.each(&proc)
|
37
|
-
end
|
38
|
-
#iterates over the linear rings, passing their indices to the bloc
|
39
|
-
def each_index(&proc)
|
40
|
-
@rings.each_index(&proc)
|
41
|
-
end
|
42
|
-
#insert linear rings at the nth position
|
43
|
-
def insert(n,*ring)
|
44
|
-
@rings.insert(n,*ring)
|
45
|
-
end
|
46
|
-
#index of the linear_ring
|
47
|
-
def index(ring)
|
48
|
-
@rings.index(ring)
|
14
|
+
|
15
|
+
#Delegate the unknown methods to the rings array
|
16
|
+
def method_missing(method_name,*args,&b)
|
17
|
+
@rings.send(method_name,*args,&b)
|
49
18
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
19
|
+
|
20
|
+
#Bounding box in 2D. Returns an array of 2 points
|
21
|
+
def bounding_box
|
22
|
+
@rings[0].bounding_box
|
53
23
|
end
|
24
|
+
|
54
25
|
#tests for other equality. The SRID is not taken into account.
|
55
26
|
def ==(other_polygon)
|
56
27
|
if other_polygon.class != self.class or
|
data/rakefile.rb
CHANGED
@@ -13,7 +13,7 @@ end
|
|
13
13
|
|
14
14
|
desc "Generate the documentation"
|
15
15
|
Rake::RDocTask::new do |rdoc|
|
16
|
-
rdoc.rdoc_dir = 'doc/'
|
16
|
+
rdoc.rdoc_dir = 'georuby-doc/'
|
17
17
|
rdoc.title = "GeoRuby Documentation"
|
18
18
|
rdoc.options << '--line-numbers' << '--inline-source'
|
19
19
|
rdoc.rdoc_files.include('README')
|
@@ -24,10 +24,10 @@ spec = Gem::Specification::new do |s|
|
|
24
24
|
s.platform = Gem::Platform::RUBY
|
25
25
|
|
26
26
|
s.name = 'GeoRuby'
|
27
|
-
s.version = "0.
|
27
|
+
s.version = "0.2.1"
|
28
28
|
s.summary = "Ruby data holder for OGC Simple Features"
|
29
29
|
s.description = <<EOF
|
30
|
-
GeoRuby is intended as a holder for data returned from PostGIS queries.
|
30
|
+
GeoRuby is intended as a holder for data returned from PostGIS and MySQL Spatial queries. The data model roughly follows the OGC "Simple Features for SQL" specification (see www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections)
|
31
31
|
EOF
|
32
32
|
s.author = 'Guilhem Vellut'
|
33
33
|
s.email = 'guilhem.vellut+georuby@gmail.com'
|
data/test/test_ewkt_parser.rb
CHANGED
@@ -92,7 +92,7 @@ class TestEWKTParser < Test::Unit::TestCase
|
|
92
92
|
assert(polygon.instance_of?(Polygon))
|
93
93
|
assert_equal(Polygon.from_coordinates([[[0,0],[4,0],[4,4],[0,4],[0,0]],[[1,1],[3,1],[3,3],[1,3],[1,1]]],256),polygon)
|
94
94
|
|
95
|
-
@ewkt_parser.parse("SRID=256;POLYGON((0 0
|
95
|
+
@ewkt_parser.parse("SRID=256;POLYGON( ( 0 0 2,4 0 2,4 4 2,0 4 2,0 0 2),(1 1 2,3 1 2,3 3 2,1 3 2,1 1 2))")
|
96
96
|
polygon = @factory.geometry
|
97
97
|
assert(polygon.instance_of?(Polygon))
|
98
98
|
assert_equal(Polygon.from_coordinates([[[0,0,2],[4,0,2],[4,4,2],[0,4,2],[0,0,2]],[[1,1,2],[3,1,2],[3,3,2],[1,3,2],[1,1,2]]],256,true),polygon)
|
@@ -112,6 +112,7 @@ class TestEWKTParser < Test::Unit::TestCase
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def test_multi_point
|
115
|
+
#Form output by the current version of PostGIS. Future versions will output the one in the specification
|
115
116
|
@ewkt_parser.parse("SRID=444;MULTIPOINT(12.4 -123.3,-65.1 123.4,123.55555555 123)")
|
116
117
|
multi_point = @factory.geometry
|
117
118
|
assert(multi_point.instance_of?(MultiPoint))
|
@@ -125,6 +126,14 @@ class TestEWKTParser < Test::Unit::TestCase
|
|
125
126
|
assert_equal(MultiPoint.from_coordinates([[12.4,-123.3,4.5],[-65.1,123.4,6.7],[123.55555555,123,7.8]],444,true),multi_point)
|
126
127
|
assert_equal(444,multi_point.srid)
|
127
128
|
assert_equal(444,multi_point[0].srid)
|
129
|
+
|
130
|
+
#Form in the EWKT specification (from the OGC)
|
131
|
+
@ewkt_parser.parse("SRID=444;MULTIPOINT( ( 12.4 -123.3 4.5 ) , (-65.1 123.4 6.7),(123.55555555 123 7.8))")
|
132
|
+
multi_point = @factory.geometry
|
133
|
+
assert(multi_point.instance_of?(MultiPoint))
|
134
|
+
assert_equal(MultiPoint.from_coordinates([[12.4,-123.3,4.5],[-65.1,123.4,6.7],[123.55555555,123,7.8]],444,true),multi_point)
|
135
|
+
assert_equal(444,multi_point.srid)
|
136
|
+
assert_equal(444,multi_point[0].srid)
|
128
137
|
end
|
129
138
|
|
130
139
|
def test_multi_line_string
|
@@ -82,6 +82,11 @@ class TestSimpleFeatures < Test::Unit::TestCase
|
|
82
82
|
assert_equal(-3.4,point.z)
|
83
83
|
assert_equal(15,point.m)
|
84
84
|
assert_equal(123,point.srid)
|
85
|
+
|
86
|
+
bbox = Point.from_x_y_z_m(-1.6,2.8,-3.4,15,123).bounding_box
|
87
|
+
assert_equal(2,bbox.length)
|
88
|
+
assert_equal(Point.from_x_y(-1.6,2.8),bbox[0])
|
89
|
+
assert_equal(Point.from_x_y(-1.6,2.8),bbox[1])
|
85
90
|
end
|
86
91
|
|
87
92
|
def test_point_equal
|
@@ -174,6 +179,11 @@ class TestSimpleFeatures < Test::Unit::TestCase
|
|
174
179
|
assert_equal(3,line_string.length)
|
175
180
|
assert_equal(Point.from_x_y_z(12.4,-45.3,123,123),line_string[0])
|
176
181
|
|
182
|
+
bbox = LineString.from_coordinates([[12.4,-45.3,123],[45.4,41.6,333],[4.456,1.0698,987]],123,true).bounding_box
|
183
|
+
assert_equal(2,bbox.length)
|
184
|
+
assert_equal(Point.from_x_y(4.456,-45.3),bbox[0])
|
185
|
+
assert_equal(Point.from_x_y(45.4,41.6),bbox[1])
|
186
|
+
|
177
187
|
end
|
178
188
|
|
179
189
|
def test_line_string_equal
|
@@ -260,7 +270,11 @@ class TestSimpleFeatures < Test::Unit::TestCase
|
|
260
270
|
assert_equal(linear_ring1,polygon[0])
|
261
271
|
assert_equal(linear_ring2,polygon[1])
|
262
272
|
|
263
|
-
|
273
|
+
bbox = Polygon.from_coordinates([[[12.4,-45.3,15.2],[45.4,41.6,2.4],[4.456,1.0698,5.6],[12.4,-45.3,6.1]],[[2.4,5.3,4.5],[5.4,1.4263,4.2],[14.46,1.06,123.1],[2.4,5.3,4.4]]],256,true).bounding_box
|
274
|
+
assert_equal(2,bbox.length)
|
275
|
+
assert_equal(Point.from_x_y(4.456,-45.3),bbox[0])
|
276
|
+
assert_equal(Point.from_x_y(45.4,41.6),bbox[1])
|
277
|
+
|
264
278
|
end
|
265
279
|
def test_polygon_equal
|
266
280
|
polygon1 = Polygon.from_coordinates([[[12.4,-45.3],[45.4,41.6],[4.456,1.0698],[12.4,-45.3]],[[2.4,5.3],[5.4,1.4263],[14.46,1.06],[2.4,5.3]]],256)
|
@@ -319,6 +333,11 @@ class TestSimpleFeatures < Test::Unit::TestCase
|
|
319
333
|
assert_equal(256,geometry_collection.srid)
|
320
334
|
assert_equal(2,geometry_collection.length)
|
321
335
|
assert_equal(LineString.from_coordinates([[5.7,12.45],[67.55,54]],256),geometry_collection[1])
|
336
|
+
|
337
|
+
bbox = geometry_collection.bounding_box
|
338
|
+
assert_equal(2,bbox.length)
|
339
|
+
assert_equal(Point.from_x_y(4.67,12.45),bbox[0])
|
340
|
+
assert_equal(Point.from_x_y(67.55,54),bbox[1])
|
322
341
|
end
|
323
342
|
def test_geometry_collection_equal
|
324
343
|
geometry_collection1 = GeometryCollection.from_geometries([Point.from_x_y(4.67,45.4,256),LineString.from_coordinates([[5.7,12.45],[67.55,54]],256)],256)
|
@@ -363,10 +382,10 @@ class TestSimpleFeatures < Test::Unit::TestCase
|
|
363
382
|
end
|
364
383
|
def test_multi_point_text
|
365
384
|
multi_point = MultiPoint.from_coordinates([[12.4,-123.3],[-65.1,123.4],[123.55555555,123]],444)
|
366
|
-
assert_equal("SRID=444;MULTIPOINT(12.4 -123.3
|
385
|
+
assert_equal("SRID=444;MULTIPOINT((12.4 -123.3),(-65.1 123.4),(123.55555555 123))",multi_point.as_ewkt)
|
367
386
|
|
368
387
|
multi_point = MultiPoint.from_coordinates([[12.4,-123.3,4.5],[-65.1,123.4,6.7],[123.55555555,123,7.8]],444,true)
|
369
|
-
assert_equal("SRID=444;MULTIPOINT(12.4 -123.3 4.5
|
388
|
+
assert_equal("SRID=444;MULTIPOINT((12.4 -123.3 4.5),(-65.1 123.4 6.7),(123.55555555 123 7.8))",multi_point.as_ewkt)
|
370
389
|
|
371
390
|
|
372
391
|
end
|
metadata
CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: GeoRuby
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.2.1
|
7
|
+
date: 2006-06-02 00:00:00 +05:00
|
8
8
|
summary: Ruby data holder for OGC Simple Features
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: guilhem.vellut+georuby@gmail.com
|
12
12
|
homepage: http://thepochisuperstarmegashow.com
|
13
13
|
rubyforge_project:
|
14
|
-
description: GeoRuby is intended as a holder for data returned from PostGIS queries.
|
14
|
+
description: GeoRuby is intended as a holder for data returned from PostGIS and MySQL Spatial queries. The data model roughly follows the OGC "Simple Features for SQL" specification (see www.opengis.org/docs/99-049.pdf), although without any kind of advanced functionalities (such as geometric operators or reprojections)
|
15
15
|
autorequire:
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|