nofxx-georuby 1.3.7

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.
Files changed (54) hide show
  1. data/History.txt +4 -0
  2. data/LICENSE +21 -0
  3. data/README.txt +59 -0
  4. data/Rakefile +49 -0
  5. data/VERSION.yml +4 -0
  6. data/lib/geo_ruby.rb +21 -0
  7. data/lib/geo_ruby/base/envelope.rb +167 -0
  8. data/lib/geo_ruby/base/ewkb_parser.rb +216 -0
  9. data/lib/geo_ruby/base/ewkt_parser.rb +336 -0
  10. data/lib/geo_ruby/base/geometry.rb +234 -0
  11. data/lib/geo_ruby/base/geometry_collection.rb +136 -0
  12. data/lib/geo_ruby/base/geometry_factory.rb +81 -0
  13. data/lib/geo_ruby/base/georss_parser.rb +135 -0
  14. data/lib/geo_ruby/base/helper.rb +18 -0
  15. data/lib/geo_ruby/base/line_string.rb +184 -0
  16. data/lib/geo_ruby/base/linear_ring.rb +12 -0
  17. data/lib/geo_ruby/base/multi_line_string.rb +39 -0
  18. data/lib/geo_ruby/base/multi_point.rb +41 -0
  19. data/lib/geo_ruby/base/multi_polygon.rb +37 -0
  20. data/lib/geo_ruby/base/point.rb +310 -0
  21. data/lib/geo_ruby/base/polygon.rb +150 -0
  22. data/lib/geo_ruby/shp4r/dbf.rb +180 -0
  23. data/lib/geo_ruby/shp4r/shp.rb +701 -0
  24. data/spec/data/multipoint.dbf +0 -0
  25. data/spec/data/multipoint.shp +0 -0
  26. data/spec/data/multipoint.shx +0 -0
  27. data/spec/data/point.dbf +0 -0
  28. data/spec/data/point.shp +0 -0
  29. data/spec/data/point.shx +0 -0
  30. data/spec/data/polygon.dbf +0 -0
  31. data/spec/data/polygon.shp +0 -0
  32. data/spec/data/polygon.shx +0 -0
  33. data/spec/data/polyline.dbf +0 -0
  34. data/spec/data/polyline.shp +0 -0
  35. data/spec/data/polyline.shx +0 -0
  36. data/spec/geo_ruby/base/envelope_spec.rb +45 -0
  37. data/spec/geo_ruby/base/ewkb_parser_spec.rb +158 -0
  38. data/spec/geo_ruby/base/ewkt_parser_spec.rb +179 -0
  39. data/spec/geo_ruby/base/geometry_collection_spec.rb +55 -0
  40. data/spec/geo_ruby/base/geometry_factory_spec.rb +11 -0
  41. data/spec/geo_ruby/base/geometry_spec.rb +32 -0
  42. data/spec/geo_ruby/base/georss_parser_spec.rb +218 -0
  43. data/spec/geo_ruby/base/line_string_spec.rb +208 -0
  44. data/spec/geo_ruby/base/linear_ring_spec.rb +14 -0
  45. data/spec/geo_ruby/base/multi_line_string_spec.rb +35 -0
  46. data/spec/geo_ruby/base/multi_point_spec.rb +29 -0
  47. data/spec/geo_ruby/base/multi_polygon_spec.rb +35 -0
  48. data/spec/geo_ruby/base/point_spec.rb +275 -0
  49. data/spec/geo_ruby/base/polygon_spec.rb +108 -0
  50. data/spec/geo_ruby/shp4r/shp_spec.rb +238 -0
  51. data/spec/geo_ruby_spec.rb +27 -0
  52. data/spec/spec.opts +6 -0
  53. data/spec/spec_helper.rb +12 -0
  54. metadata +123 -0
@@ -0,0 +1,336 @@
1
+ require 'geo_ruby/base/point'
2
+ require 'geo_ruby/base/line_string'
3
+ require 'geo_ruby/base/linear_ring'
4
+ require 'geo_ruby/base/polygon'
5
+ require 'geo_ruby/base/multi_point'
6
+ require 'geo_ruby/base/multi_line_string'
7
+ require 'geo_ruby/base/multi_polygon'
8
+ require 'geo_ruby/base/geometry_collection'
9
+
10
+ require 'strscan'
11
+
12
+ module GeoRuby
13
+ module Base
14
+
15
+ #Raised when an error in the EWKT string is detected
16
+ class EWKTFormatError < StandardError
17
+ end
18
+
19
+ #Parses EWKT strings and notifies of events (such as the beginning of the definition of geometry, the value of the SRID...) the factory passed as argument to the constructor.
20
+ #
21
+ #=Example
22
+ # factory = GeometryFactory::new
23
+ # ewkt_parser = EWKTParser::new(factory)
24
+ # ewkt_parser.parse(<EWKT String>)
25
+ # geometry = @factory.geometry
26
+ #
27
+ #You can also use directly the static method Geometry.from_ewkt
28
+ class EWKTParser
29
+
30
+ def initialize(factory)
31
+ @factory = factory
32
+ @parse_options ={
33
+ "POINT" => method(:parse_point),
34
+ "LINESTRING" => method(:parse_line_string),
35
+ "POLYGON" => method(:parse_polygon),
36
+ "MULTIPOINT" => method(:parse_multi_point),
37
+ "MULTILINESTRING" => method(:parse_multi_line_string),
38
+ "MULTIPOLYGON" => method(:parse_multi_polygon),
39
+ "GEOMETRYCOLLECTION" => method(:parse_geometry_collection)
40
+ }
41
+ end
42
+
43
+ #Parses the ewkt string passed as argument and notifies the factory of events
44
+ def parse(ewkt)
45
+ @factory.reset
46
+ @tokenizer_structure = TokenizerStructure.new(ewkt)
47
+ @with_z=false
48
+ @with_m=false
49
+ @is_3dm = false
50
+ parse_geometry(true)
51
+ @srid=nil
52
+ end
53
+
54
+ private
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")
63
+ else
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
67
+ end
68
+
69
+ else
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
71
+ @srid= @srid || @@default_srid
72
+ geom_type = token
73
+ end
74
+
75
+ if geom_type[-1] == ?M
76
+ @is_3dm=true
77
+ @with_m=true
78
+ geom_type.chop! #remove the M
79
+ end
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
86
+ end
87
+
88
+ def parse_geometry_collection
89
+ if @tokenizer_structure.get_next_token !='('
90
+ raise EWKTFormatError.new('Invalid GeometryCollection')
91
+ end
92
+
93
+ @factory.begin_geometry(GeometryCollection,@srid)
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
102
+ end
103
+
104
+ @factory.end_geometry(@with_z,@with_m)
105
+ end
106
+
107
+ def parse_multi_polygon
108
+ if @tokenizer_structure.get_next_token !='('
109
+ raise EWKTFormatError.new('Invalid MultiLineString')
110
+ end
111
+
112
+ @factory.begin_geometry(MultiPolygon,@srid)
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
120
+ end
121
+
122
+ @factory.end_geometry(@with_z,@with_m)
123
+ end
124
+
125
+ def parse_multi_line_string
126
+ if @tokenizer_structure.get_next_token !='('
127
+ raise EWKTFormatError.new('Invalid MultiLineString')
128
+ end
129
+
130
+ @factory.begin_geometry(MultiLineString,@srid)
131
+
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
139
+ end
140
+
141
+ @factory.end_geometry(@with_z,@with_m)
142
+ end
143
+
144
+ def parse_polygon
145
+ if @tokenizer_structure.get_next_token !='('
146
+ raise EWKTFormatError.new('Invalid Polygon')
147
+ end
148
+
149
+ @factory.begin_geometry(Polygon,@srid)
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
158
+ end
159
+
160
+ @factory.end_geometry(@with_z,@with_m)
161
+ end
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
188
+ end
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)
196
+ end
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)
204
+ end
205
+
206
+ #used to parse line_strings and linear_rings and the PostGIS form of multi_points
207
+ def parse_point_list(geometry_type)
208
+ @factory.begin_geometry(geometry_type,@srid)
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)
218
+ end
219
+
220
+ @factory.end_geometry(@with_z,@with_m)
221
+ end
222
+
223
+ def parse_point
224
+ if @tokenizer_structure.get_next_token !='('
225
+ raise EWKTFormatError.new('Invalid Point')
226
+ end
227
+
228
+ @factory.begin_geometry(Point,@srid)
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
240
+ coords = Array.new
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")
246
+ end
247
+
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")
253
+ else
254
+ @factory.add_point_x_y_m(x.to_f,y.to_f,m.to_f)
255
+ @tokenizer_structure.get_next_token
256
+ end
257
+ else
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
287
+ end
288
+ end
289
+ end
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
+
335
+ end
336
+ end
@@ -0,0 +1,234 @@
1
+ module GeoRuby#:nodoc:
2
+ module Base
3
+ #arbitrary default SRID
4
+ @@default_srid = 4326
5
+
6
+ def self.default_srid
7
+ @@default_srid
8
+ end
9
+ def self.srid=(srid)
10
+ @@default_srid = srid
11
+ end
12
+
13
+ #Root of all geometric data classes.
14
+ #Objects of class Geometry should not be instantiated.
15
+ class Geometry
16
+ #SRID of the geometry
17
+ attr_reader :srid #writer defined below
18
+ #Flag indicating if the z ordinate of the geometry is meaningful
19
+ attr_accessor :with_z
20
+ alias :with_z? :with_z
21
+ #Flag indicating if the m ordinate of the geometry is meaningful
22
+ attr_accessor :with_m
23
+ alias :with_m? :with_m
24
+
25
+ def initialize(srid=@@default_srid,with_z=false,with_m=false)
26
+ @srid=srid
27
+ @with_z=with_z
28
+ @with_m=with_m
29
+ end
30
+
31
+ def srid=(new_srid)
32
+ @srid = new_srid
33
+ unless self.is_a?(Point)
34
+ self.each do |geom|
35
+ geom.srid=new_srid
36
+ end
37
+ end
38
+ end
39
+
40
+ #to be implemented in subclasses
41
+ def bounding_box
42
+ end
43
+
44
+ #to be implemented in subclasses
45
+ def m_range
46
+ end
47
+
48
+ #Returns an Envelope object for the geometry
49
+ def envelope
50
+ Envelope.from_points(bounding_box,srid,with_z)
51
+ end
52
+
53
+ #Outputs the geometry as an EWKB string.
54
+ #The +allow_srid+, +allow_z+ and +allow_m+ arguments allow the output to include srid, z and m respectively if they are present in the geometry. If these arguments are set to false, srid, z and m are not included, even if they are present in the geometry. By default, the output string contains all the information in the object.
55
+ def as_ewkb(allow_srid=true,allow_z=true,allow_m=true)
56
+ ewkb="";
57
+
58
+ ewkb << 1.chr #little_endian by default
59
+
60
+ type= binary_geometry_type
61
+ if @with_z and allow_z
62
+ type = type | Z_MASK
63
+ end
64
+ if @with_m and allow_m
65
+ type = type | M_MASK
66
+ end
67
+ if allow_srid
68
+ type = type | SRID_MASK
69
+ ewkb << [type,@srid].pack("VV")
70
+ else
71
+ ewkb << [type].pack("V")
72
+ end
73
+
74
+ ewkb << binary_representation(allow_z,allow_m)
75
+ end
76
+
77
+ #Outputs the geometry as a strict WKB string.
78
+ def as_wkb
79
+ as_ewkb(false,false,false)
80
+ end
81
+
82
+ #Outputs the geometry as a HexEWKB string. It is almost the same as a WKB string, except that each byte of a WKB string is replaced by its hexadecimal 2-character representation in a HexEWKB string.
83
+ def as_hex_ewkb(allow_srid=true,allow_z=true,allow_m=true)
84
+ as_ewkb(allow_srid, allow_z, allow_m).unpack('H*').join('').upcase
85
+ end
86
+
87
+ #Outputs the geometry as a strict HexWKB string
88
+ def as_hex_wkb
89
+ as_hex_ewkb(false,false,false)
90
+ end
91
+
92
+ #Outputs the geometry as an EWKT string.
93
+ def as_ewkt(allow_srid=true,allow_z=true,allow_m=true)
94
+ if allow_srid
95
+ ewkt="SRID=#{@srid};"
96
+ else
97
+ ewkt=""
98
+ end
99
+ ewkt << text_geometry_type
100
+ ewkt << "M" if @with_m and allow_m and (!@with_z or !allow_z) #to distinguish the M from the Z when there is actually no Z...
101
+ ewkt << "(" << text_representation(allow_z,allow_m) << ")"
102
+ end
103
+
104
+ #Outputs the geometry as strict WKT string.
105
+ def as_wkt
106
+ as_ewkt(false,false,false)
107
+ end
108
+
109
+ #Outputs the geometry in georss format.
110
+ #Assumes the geometries are in latlon format, with x as lon and y as lat.
111
+ #Pass the <tt>:dialect</tt> option to swhit format. Possible values are: <tt>:simple</tt> (default), <tt>:w3cgeo</tt> and <tt>:gml</tt>.
112
+ def as_georss(options = {})
113
+ dialect= options[:dialect] || :simple
114
+ case(dialect)
115
+ when :simple
116
+ geom_attr = ""
117
+ geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
118
+ geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
119
+ geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
120
+ geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
121
+ geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
122
+ georss_simple_representation(options.merge(:geom_attr => geom_attr))
123
+ when :w3cgeo
124
+ georss_w3cgeo_representation(options)
125
+ when :gml
126
+ georss_gml_representation(options)
127
+ end
128
+ end
129
+
130
+ #Iutputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
131
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
132
+ #it won't be used by GE anyway: clampToGround is the default)
133
+ def as_kml(options = {})
134
+ id_attr = ""
135
+ id_attr = " id=\"#{options[:id]}\"" if options[:id]
136
+
137
+ geom_data = ""
138
+ geom_data += "<extrude>#{options[:extrude]}</extrude>\n" if options[:extrude]
139
+ geom_data += "<tesselate>#{options[:tesselate]}</tesselate>\n" if options[:tesselate]
140
+ geom_data += "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
141
+
142
+ allow_z = (with_z || !options[:altitude].nil? )&& (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
143
+ fixed_z = options[:altitude]
144
+
145
+ kml_representation(options.merge(:id_attr => id_attr, :geom_data => geom_data, :allow_z => allow_z, :fixed_z => fixed_z))
146
+ end
147
+
148
+ #Creates a geometry based on a EWKB string. The actual class returned depends of the content of the string passed as argument. Since WKB strings are a subset of EWKB, they are also valid.
149
+ def self.from_ewkb(ewkb)
150
+ factory = GeometryFactory::new
151
+ ewkb_parser= EWKBParser::new(factory)
152
+ ewkb_parser.parse(ewkb)
153
+ factory.geometry
154
+ end
155
+ #Creates a geometry based on a HexEWKB string
156
+ def self.from_hex_ewkb(hexewkb)
157
+ factory = GeometryFactory::new
158
+ hexewkb_parser= HexEWKBParser::new(factory)
159
+ hexewkb_parser.parse(hexewkb)
160
+ factory.geometry
161
+ end
162
+ #Creates a geometry based on a EWKT string. Since WKT strings are a subset of EWKT, they are also valid.
163
+ def self.from_ewkt(ewkt)
164
+ factory = GeometryFactory::new
165
+ ewkt_parser= EWKTParser::new(factory)
166
+ ewkt_parser.parse(ewkt)
167
+ factory.geometry
168
+ end
169
+
170
+ #sends back a geometry based on the GeoRSS string passed as argument
171
+ def self.from_georss(georss)
172
+ georss_parser= GeorssParser::new
173
+ georss_parser.parse(georss)
174
+ georss_parser.geometry
175
+ end
176
+ #sends back an array: The first element is the goemetry based on the GeoRSS string passed as argument. The second one is the GeoRSSTags (found only with the Simple format)
177
+ def self.from_georss_with_tags(georss)
178
+ georss_parser= GeorssParser::new
179
+ georss_parser.parse(georss,true)
180
+ [georss_parser.geometry, georss_parser.georss_tags]
181
+ end
182
+
183
+ #Sends back a geometry from a KML encoded geometry string.
184
+ #Limitations : Only supports points, linestrings and polygons (no collection for now).
185
+ #Addapted from Pramukta's code
186
+ def self.from_kml(kml)
187
+ return GeoRuby::Base::Geometry.from_ewkt(kml_to_wkt(kml))
188
+ end
189
+
190
+ require 'rexml/document'
191
+ def self.kml_to_wkt(kml)
192
+ doc = REXML::Document.new(kml)
193
+ wkt = ""
194
+ if ["Point", "LineString", "Polygon" ].include?(doc.root.name)
195
+ case doc.root.name
196
+ when "Point" then
197
+ coords = doc.elements["/Point/coordinates"].text.gsub(/\n/," ")
198
+ wkt = doc.root.name.upcase + "(" + split_coords(coords).join(' ') + ")"
199
+ when "LineString" then
200
+ coords = doc.elements["/LineString/coordinates"].text.gsub(/\n/," ")
201
+ coords = split_coords(coords)
202
+ wkt = doc.root.name.upcase + "(" + coords.join(",") + ")"
203
+ when "Polygon" then
204
+ # polygons have one outer ring and zero or more inner rings
205
+ bounds = []
206
+ bounds << doc.elements["/Polygon/outerBoundaryIs/LinearRing/coordinates"].text
207
+ inner_coords_elements = doc.elements.each("/Polygon/innerBoundaryIs/LinearRing/coordinates") do |inner_coords|
208
+ inner_coords = inner_coords.text
209
+ bounds << inner_coords
210
+ end
211
+
212
+ wkt = doc.root.name.upcase + "(" + bounds.map do |bound|
213
+ bound.gsub!(/\n/, " ")
214
+ bound = split_coords(bound)
215
+ if bound.first != bound.last
216
+ bound.push bound.first
217
+ end
218
+ "(" + bound.join(",") + ")"
219
+ end.join(",") + ")"
220
+ end
221
+ end
222
+ return wkt
223
+ end
224
+
225
+ private
226
+
227
+ def self.split_coords(coords)
228
+ coords.split(" ").collect { |coord|
229
+ coord.gsub(","," ")
230
+ }
231
+ end
232
+ end
233
+ end
234
+ end