jsl-GeoRuby 1.3.3

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 (43) hide show
  1. data/MIT-LICENSE +7 -0
  2. data/README +83 -0
  3. data/georuby.gemspec +37 -0
  4. data/lib/geo_ruby.rb +16 -0
  5. data/lib/geo_ruby/shp4r/dbf.rb +180 -0
  6. data/lib/geo_ruby/shp4r/shp.rb +701 -0
  7. data/lib/geo_ruby/simple_features/envelope.rb +134 -0
  8. data/lib/geo_ruby/simple_features/ewkb_parser.rb +216 -0
  9. data/lib/geo_ruby/simple_features/ewkt_parser.rb +336 -0
  10. data/lib/geo_ruby/simple_features/geometry.rb +225 -0
  11. data/lib/geo_ruby/simple_features/geometry_collection.rb +136 -0
  12. data/lib/geo_ruby/simple_features/geometry_factory.rb +81 -0
  13. data/lib/geo_ruby/simple_features/georss_parser.rb +135 -0
  14. data/lib/geo_ruby/simple_features/helper.rb +18 -0
  15. data/lib/geo_ruby/simple_features/line_string.rb +166 -0
  16. data/lib/geo_ruby/simple_features/linear_ring.rb +12 -0
  17. data/lib/geo_ruby/simple_features/multi_line_string.rb +39 -0
  18. data/lib/geo_ruby/simple_features/multi_point.rb +41 -0
  19. data/lib/geo_ruby/simple_features/multi_polygon.rb +38 -0
  20. data/lib/geo_ruby/simple_features/point.rb +236 -0
  21. data/lib/geo_ruby/simple_features/polygon.rb +150 -0
  22. data/rakefile.rb +44 -0
  23. data/test/data/multipoint.dbf +0 -0
  24. data/test/data/multipoint.shp +0 -0
  25. data/test/data/multipoint.shx +0 -0
  26. data/test/data/point.dbf +0 -0
  27. data/test/data/point.shp +0 -0
  28. data/test/data/point.shx +0 -0
  29. data/test/data/polygon.dbf +0 -0
  30. data/test/data/polygon.shp +0 -0
  31. data/test/data/polygon.shx +0 -0
  32. data/test/data/polyline.dbf +0 -0
  33. data/test/data/polyline.shp +0 -0
  34. data/test/data/polyline.shx +0 -0
  35. data/test/test_ewkb_parser.rb +171 -0
  36. data/test/test_ewkt_parser.rb +193 -0
  37. data/test/test_georss_kml.rb +231 -0
  38. data/test/test_shp.rb +76 -0
  39. data/test/test_shp_write.rb +150 -0
  40. data/test/test_simple_features.rb +506 -0
  41. data/tools/db.yml +6 -0
  42. data/tools/shp2sql.rb +92 -0
  43. metadata +95 -0
@@ -0,0 +1,225 @@
1
+ module GeoRuby#:nodoc:
2
+ module SimpleFeatures
3
+ #arbitrary default SRID
4
+ DEFAULT_SRID=-1
5
+
6
+ #Root of all geometric data classes.
7
+ #Objects of class Geometry should not be instantiated.
8
+ class Geometry
9
+ #SRID of the geometry
10
+ attr_reader :srid #writer defined below
11
+ #Flag indicating if the z ordinate of the geometry is meaningful
12
+ attr_accessor :with_z
13
+ #Flag indicating if the m ordinate of the geometry is meaningful
14
+ attr_accessor :with_m
15
+
16
+ def initialize(srid=DEFAULT_SRID,with_z=false,with_m=false)
17
+ @srid=srid
18
+ @with_z=with_z
19
+ @with_m=with_m
20
+ end
21
+
22
+ def srid=(new_srid)
23
+ @srid = new_srid
24
+ unless self.is_a?(Point)
25
+ self.each do |geom|
26
+ geom.srid=new_srid
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ #to be implemented in subclasses
33
+ def bounding_box
34
+ end
35
+
36
+ #to be implemented in subclasses
37
+ def m_range
38
+ end
39
+
40
+ #Returns an Envelope object for the geometry
41
+ def envelope
42
+ Envelope.from_points(bounding_box,srid,with_z)
43
+ end
44
+
45
+ #Outputs the geometry as an EWKB string.
46
+ #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.
47
+ def as_ewkb(allow_srid=true,allow_z=true,allow_m=true)
48
+ ewkb="";
49
+
50
+ ewkb << 1.chr #little_endian by default
51
+
52
+ type= binary_geometry_type
53
+ if @with_z and allow_z
54
+ type = type | Z_MASK
55
+ end
56
+ if @with_m and allow_m
57
+ type = type | M_MASK
58
+ end
59
+ if allow_srid
60
+ type = type | SRID_MASK
61
+ ewkb << [type,@srid].pack("VV")
62
+ else
63
+ ewkb << [type].pack("V")
64
+ end
65
+
66
+ ewkb << binary_representation(allow_z,allow_m)
67
+ end
68
+
69
+ #Outputs the geometry as a strict WKB string.
70
+ def as_wkb
71
+ as_ewkb(false,false,false)
72
+ end
73
+
74
+ #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.
75
+ def as_hex_ewkb(allow_srid=true,allow_z=true,allow_m=true)
76
+ as_ewkb(allow_srid, allow_z, allow_m).unpack('H*').join('').upcase
77
+ end
78
+ #Outputs the geometry as a strict HexWKB string
79
+ def as_hex_wkb
80
+ as_hex_ewkb(false,false,false)
81
+ end
82
+
83
+ #Outputs the geometry as an EWKT string.
84
+ def as_ewkt(allow_srid=true,allow_z=true,allow_m=true)
85
+ if allow_srid
86
+ ewkt="SRID=#{@srid};"
87
+ else
88
+ ewkt=""
89
+ end
90
+ ewkt << text_geometry_type
91
+ 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...
92
+ ewkt << "(" << text_representation(allow_z,allow_m) << ")"
93
+ end
94
+
95
+ #Outputs the geometry as strict WKT string.
96
+ def as_wkt
97
+ as_ewkt(false,false,false)
98
+ end
99
+
100
+ #Outputs the geometry in georss format.
101
+ #Assumes the geometries are in latlon format, with x as lon and y as lat.
102
+ #Pass the <tt>:dialect</tt> option to swhit format. Possible values are: <tt>:simple</tt> (default), <tt>:w3cgeo</tt> and <tt>:gml</tt>.
103
+ def as_georss(options = {})
104
+ dialect= options[:dialect] || :simple
105
+ case(dialect)
106
+ when :simple
107
+ geom_attr = ""
108
+ geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
109
+ geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
110
+ geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
111
+ geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
112
+ geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
113
+ georss_simple_representation(options.merge(:geom_attr => geom_attr))
114
+ when :w3cgeo
115
+ georss_w3cgeo_representation(options)
116
+ when :gml
117
+ georss_gml_representation(options)
118
+ end
119
+ end
120
+
121
+ #Iutputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
122
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
123
+ #it won't be used by GE anyway: clampToGround is the default)
124
+ def as_kml(options = {})
125
+ id_attr = ""
126
+ id_attr = " id=\"#{options[:id]}\"" if options[:id]
127
+
128
+ geom_data = ""
129
+ geom_data += "<extrude>#{options[:extrude]}</extrude>\n" if options[:extrude]
130
+ geom_data += "<tesselate>#{options[:tesselate]}</tesselate>\n" if options[:tesselate]
131
+ geom_data += "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
132
+
133
+ allow_z = (with_z || !options[:altitude].nil? )&& (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
134
+ fixed_z = options[:altitude]
135
+
136
+ kml_representation(options.merge(:id_attr => id_attr, :geom_data => geom_data, :allow_z => allow_z, :fixed_z => fixed_z))
137
+ end
138
+
139
+ #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.
140
+ def self.from_ewkb(ewkb)
141
+ factory = GeometryFactory::new
142
+ ewkb_parser= EWKBParser::new(factory)
143
+ ewkb_parser.parse(ewkb)
144
+ factory.geometry
145
+ end
146
+ #Creates a geometry based on a HexEWKB string
147
+ def self.from_hex_ewkb(hexewkb)
148
+ factory = GeometryFactory::new
149
+ hexewkb_parser= HexEWKBParser::new(factory)
150
+ hexewkb_parser.parse(hexewkb)
151
+ factory.geometry
152
+ end
153
+ #Creates a geometry based on a EWKT string. Since WKT strings are a subset of EWKT, they are also valid.
154
+ def self.from_ewkt(ewkt)
155
+ factory = GeometryFactory::new
156
+ ewkt_parser= EWKTParser::new(factory)
157
+ ewkt_parser.parse(ewkt)
158
+ factory.geometry
159
+ end
160
+
161
+ #sends back a geometry based on the GeoRSS string passed as argument
162
+ def self.from_georss(georss)
163
+ georss_parser= GeorssParser::new
164
+ georss_parser.parse(georss)
165
+ georss_parser.geometry
166
+ end
167
+ #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)
168
+ def self.from_georss_with_tags(georss)
169
+ georss_parser= GeorssParser::new
170
+ georss_parser.parse(georss,true)
171
+ [georss_parser.geometry, georss_parser.georss_tags]
172
+ end
173
+
174
+ #Sends back a geometry from a KML encoded geometry string.
175
+ #Limitations : Only supports points, linestrings and polygons (no collection for now).
176
+ #Addapted from Pramukta's code
177
+ def self.from_kml(kml)
178
+ return GeoRuby::SimpleFeatures::Geometry.from_ewkt(kml_to_wkt(kml))
179
+ end
180
+
181
+ require 'rexml/document'
182
+ def self.kml_to_wkt(kml)
183
+ doc = REXML::Document.new(kml)
184
+ wkt = ""
185
+ if ["Point", "LineString", "Polygon" ].include?(doc.root.name)
186
+ case doc.root.name
187
+ when "Point" then
188
+ coords = doc.elements["/Point/coordinates"].text.gsub(/\n/," ")
189
+ wkt = doc.root.name.upcase + "(" + split_coords(coords).join(' ') + ")"
190
+ when "LineString" then
191
+ coords = doc.elements["/LineString/coordinates"].text.gsub(/\n/," ")
192
+ coords = split_coords(coords)
193
+ wkt = doc.root.name.upcase + "(" + coords.join(",") + ")"
194
+ when "Polygon" then
195
+ # polygons have one outer ring and zero or more inner rings
196
+ bounds = []
197
+ bounds << doc.elements["/Polygon/outerBoundaryIs/LinearRing/coordinates"].text
198
+ inner_coords_elements = doc.elements.each("/Polygon/innerBoundaryIs/LinearRing/coordinates") do |inner_coords|
199
+ inner_coords = inner_coords.text
200
+ bounds << inner_coords
201
+ end
202
+
203
+ wkt = doc.root.name.upcase + "(" + bounds.map do |bound|
204
+ bound.gsub!(/\n/, " ")
205
+ bound = split_coords(bound)
206
+ if bound.first != bound.last
207
+ bound.push bound.first
208
+ end
209
+ "(" + bound.join(",") + ")"
210
+ end.join(",") + ")"
211
+ end
212
+ end
213
+ return wkt
214
+ end
215
+
216
+ private
217
+
218
+ def self.split_coords(coords)
219
+ coords.split(" ").collect { |coord|
220
+ coord.gsub(","," ")
221
+ }
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,136 @@
1
+ require 'geo_ruby/simple_features/geometry'
2
+
3
+ module GeoRuby
4
+ module SimpleFeatures
5
+ #Represents a collection of arbitrary geometries
6
+ class GeometryCollection < Geometry
7
+ attr_reader :geometries
8
+
9
+ def initialize(srid = DEFAULT_SRID,with_z=false,with_m=false)
10
+ super(srid,with_z,with_m)
11
+ @geometries = []
12
+ end
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)
17
+ end
18
+
19
+ #Bounding box in 2D/3D. 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, -Float::MAX, Float::MAX
22
+ if with_z
23
+ max_z, min_z = -Float::MAX, Float::MAX
24
+ each do |geometry|
25
+ bbox = geometry.bounding_box
26
+ sw = bbox[0]
27
+ ne = bbox[1]
28
+
29
+ max_y = ne.y if ne.y > max_y
30
+ min_y = sw.y if sw.y < min_y
31
+ max_x = ne.x if ne.x > max_x
32
+ min_x = sw.x if sw.x < min_x
33
+ max_z = ne.z if ne.z > max_z
34
+ min_z = sw.z if sw.z < min_z
35
+ end
36
+ [Point.from_x_y_z(min_x,min_y,min_z),Point.from_x_y_z(max_x,max_y,max_z)]
37
+ else
38
+ each do |geometry|
39
+ bbox = geometry.bounding_box
40
+ sw = bbox[0]
41
+ ne = bbox[1]
42
+
43
+ max_y = ne.y if ne.y > max_y
44
+ min_y = sw.y if sw.y < min_y
45
+ max_x = ne.x if ne.x > max_x
46
+ min_x = sw.x if sw.x < min_x
47
+ end
48
+ [Point.from_x_y(min_x,min_y),Point.from_x_y(max_x,max_y)]
49
+ end
50
+ end
51
+
52
+ def m_range
53
+ if with_m
54
+ max_m, min_m = -Float::MAX, Float::MAX
55
+ each do |lr|
56
+ lrmr = lr.m_range
57
+ max_m = lrmr[1] if lrmr[1] > max_m
58
+ min_m = lrmr[0] if lrmr[0] < min_m
59
+ end
60
+ [min_m,max_m]
61
+ else
62
+ [0,0]
63
+ end
64
+ end
65
+
66
+ #tests the equality of geometry collections
67
+ def ==(other_collection)
68
+ if(other_collection.class != self.class)
69
+ false
70
+ elsif length != other_collection.length
71
+ false
72
+ else
73
+ index=0
74
+ while index<length
75
+ return false if self[index] != other_collection[index]
76
+ index+=1
77
+ end
78
+ true
79
+ end
80
+ end
81
+
82
+ #Binary representation of the collection
83
+ def binary_representation(allow_z=true,allow_m=true) #:nodoc:
84
+ rep = [length].pack("V")
85
+ #output the list of geometries without outputting the SRID first and with the same setting regarding Z and M
86
+ each {|geometry| rep << geometry.as_ewkb(false,allow_z,allow_m) }
87
+ rep
88
+ end
89
+
90
+ #WKB geometry type of the collection
91
+ def binary_geometry_type #:nodoc:
92
+ 7
93
+ end
94
+
95
+ #Text representation of a geometry collection
96
+ def text_representation(allow_z=true,allow_m=true) #:nodoc:
97
+ @geometries.collect{|geometry| geometry.as_ewkt(false,allow_z,allow_m)}.join(",")
98
+ end
99
+
100
+ #WKT geometry type
101
+ def text_geometry_type #:nodoc:
102
+ "GEOMETRYCOLLECTION"
103
+ end
104
+
105
+ #georss simple representation : outputs only the first geometry of the collection
106
+ def georss_simple_representation(options)#:nodoc:
107
+ self[0].georss_simple_representation(options)
108
+ end
109
+ #georss w3c representation : outputs the first point of the outer ring
110
+ def georss_w3cgeo_representation(options)#:nodoc:
111
+ self[0].georss_w3cgeo_representation(options)
112
+ end
113
+ #georss gml representation : outputs only the first geometry of the collection
114
+ def georss_gml_representation(options)#:nodoc:
115
+ self[0].georss_gml_representation(options)
116
+ end
117
+
118
+ #outputs the geometry in kml format
119
+ def kml_representation(options = {}) #:nodoc:
120
+ result = "<MultiGeometry#{options[:id_attr]}>\n"
121
+ options[:id_attr] = "" #the subgeometries do not have an ID
122
+ each do |geometry|
123
+ result += geometry.kml_representation(options)
124
+ end
125
+ result += "</MultiGeometry>\n"
126
+ end
127
+
128
+ #creates a new GeometryCollection from an array of geometries
129
+ def self.from_geometries(geometries,srid=DEFAULT_SRID,with_z=false,with_m=false)
130
+ geometry_collection = new(srid,with_z,with_m)
131
+ geometry_collection.concat(geometries)
132
+ geometry_collection
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,81 @@
1
+ require 'geo_ruby/simple_features/point'
2
+ require 'geo_ruby/simple_features/line_string'
3
+ require 'geo_ruby/simple_features/linear_ring'
4
+ require 'geo_ruby/simple_features/polygon'
5
+ require 'geo_ruby/simple_features/multi_point'
6
+ require 'geo_ruby/simple_features/multi_line_string'
7
+ require 'geo_ruby/simple_features/multi_polygon'
8
+ require 'geo_ruby/simple_features/geometry_collection'
9
+
10
+
11
+ module GeoRuby
12
+ module SimpleFeatures
13
+ #Creates a new geometry according to constructions received from a parser, for example EWKBParser.
14
+ class GeometryFactory
15
+ #the built geometry
16
+ attr_reader :geometry
17
+
18
+ def initialize
19
+ @geometry = nil
20
+ @geometry_stack = []
21
+ end
22
+ #resets the factory
23
+ def reset
24
+ @geometry = nil
25
+ @geometry_stack = []
26
+ end
27
+ #add a 2D point to the current geometry
28
+ def add_point_x_y(x,y)
29
+ @geometry_stack.last.set_x_y(x,y)
30
+ end
31
+ #add 2D points to the current geometry
32
+ def add_points_x_y(xy)
33
+ xy.each_slice(2) {|slice| add_point_x_y(*slice)}
34
+ end
35
+ #add a 3D point to the current geometry
36
+ def add_point_x_y_z(x,y,z)
37
+ @geometry_stack.last.set_x_y_z(x,y,z)
38
+ end
39
+ #add 3D points to the current geometry
40
+ def add_points_x_y_z(xyz)
41
+ xyz.each_slice(3) {|slice| add_point_x_y_z(*slice)}
42
+ end
43
+ #add a 2D point with M to the current geometry
44
+ def add_point_x_y_m(x,y,m)
45
+ @geometry_stack.last.set_x_y(x,y)
46
+ @geometry_stack.last.m=m
47
+ end
48
+ #add 2D points with M to the current geometry
49
+ def add_points_x_y_m(xym)
50
+ xym.each_slice(3) {|slice| add_point_x_y_m(*slice)}
51
+ end
52
+ #add a 3D point with M to the current geometry
53
+ def add_point_x_y_z_m(x,y,z,m)
54
+ @geometry_stack.last.set_x_y_z(x,y,z)
55
+ @geometry_stack.last.m=m
56
+ end
57
+ #add 3D points with M to the current geometry
58
+ def add_points_x_y_z_m(xyzm)
59
+ xyzm.each_slice(4) {|slice| add_point_x_y_z_m(*slice)}
60
+ end
61
+ #begin a geometry of type +geometry_type+
62
+ def begin_geometry(geometry_type,srid=DEFAULT_SRID)
63
+ geometry= geometry_type::new(srid)
64
+ @geometry= geometry if @geometry.nil?
65
+ @geometry_stack << geometry
66
+ end
67
+ #terminates the current geometry
68
+ def end_geometry(with_z=false,with_m=false)
69
+ @geometry=@geometry_stack.pop
70
+ @geometry.with_z=with_z
71
+ @geometry.with_m=with_m
72
+ #add the newly defined geometry to its parent if there is one
73
+ @geometry_stack.last << geometry if !@geometry_stack.empty?
74
+ end
75
+ #abort a geometry
76
+ def abort_geometry
77
+ reset
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,135 @@
1
+ require 'geo_ruby/simple_features/point'
2
+ require 'geo_ruby/simple_features/line_string'
3
+ require 'geo_ruby/simple_features/linear_ring'
4
+ require 'geo_ruby/simple_features/polygon'
5
+ require 'geo_ruby/simple_features/multi_point'
6
+ require 'geo_ruby/simple_features/multi_line_string'
7
+ require 'geo_ruby/simple_features/multi_polygon'
8
+ require 'geo_ruby/simple_features/geometry_collection'
9
+ require 'geo_ruby/simple_features/envelope'
10
+
11
+ module GeoRuby
12
+ module SimpleFeatures
13
+
14
+ #Raised when an error in the GeoRSS string is detected
15
+ class GeorssFormatError < StandardError
16
+ end
17
+
18
+ #Contains tags possibly found on GeoRss Simple geometries
19
+ class GeorssTags < Struct.new(:featuretypetag,:relationshiptag,:elev,:floor,:radius)
20
+ end
21
+
22
+ #Parses GeoRSS strings
23
+ #You can also use directly the static method Geometry.from_georss
24
+ class GeorssParser
25
+ attr_reader :georss_tags, :geometry
26
+
27
+ #Parses the georss geometry passed as argument and notifies the factory of events
28
+ #The parser assumes
29
+ def parse(georss,with_tags = false)
30
+ @geometry = nil
31
+ @georss_tags = GeorssTags.new
32
+ parse_geometry(georss,with_tags)
33
+ end
34
+
35
+ private
36
+ def parse_geometry(georss,with_tags)
37
+ georss.strip!
38
+ #check for W3CGeo first
39
+ if georss =~ /<[^:>]*:lat\s*>([^<]*)</
40
+ #if valid, it is W3CGeo
41
+ lat = $1.to_f
42
+ if georss =~ /<[^:>]*:long\s*>([^<]*)</
43
+ lon = $1.to_f
44
+ @geometry = Point.from_x_y(lon,lat)
45
+ else
46
+ raise GeorssFormatError.new("Bad W3CGeo GeoRSS format")
47
+ end
48
+ elsif georss =~ /^<\s*[^:>]*:where\s*>/
49
+ #GML format found
50
+ gml = $'.strip
51
+ if gml =~ /^<\s*[^:>]*:Point\s*>/
52
+ #gml point
53
+ if gml =~ /<\s*[^:>]*:pos\s*>([^<]*)/
54
+ point = $1.split(" ")
55
+ #lat comes first
56
+ @geometry = Point.from_x_y(point[1].to_f,point[0].to_f)
57
+ else
58
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Point")
59
+ end
60
+ elsif gml =~ /^<\s*[^:>]*:LineString\s*>/
61
+ if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/
62
+ xy = $1.split(" ")
63
+ @geometry = LineString.new
64
+ 0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
65
+ else
66
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed LineString")
67
+ end
68
+ elsif gml =~ /^<\s*[^:>]*:Polygon\s*>/
69
+ if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/
70
+ xy = $1.split(" ")
71
+ @geometry = Polygon.new
72
+ linear_ring = LinearRing.new
73
+ @geometry << linear_ring
74
+ xy = $1.split(" ")
75
+ 0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
76
+ else
77
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Polygon")
78
+ end
79
+ elsif gml =~ /^<\s*[^:>]*:Envelope\s*>/
80
+ if gml =~ /<\s*[^:>]*:lowerCorner\s*>([^<]*)</
81
+ lc = $1.split(" ").collect { |x| x.to_f}.reverse
82
+ if gml =~ /<\s*[^:>]*:upperCorner\s*>([^<]*)</
83
+ uc = $1.split(" ").collect { |x| x.to_f}.reverse
84
+ @geometry = Envelope.from_coordinates([lc,uc])
85
+ else
86
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope")
87
+ end
88
+ else
89
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope")
90
+ end
91
+ else
92
+ raise GeorssFormatError.new("Bad GML GeoRSS format: Unknown geometry type")
93
+ end
94
+ else
95
+ #must be simple format
96
+ if georss =~ /^<\s*[^>:]*:point([^>]*)>(.*)</m
97
+ tags = $1
98
+ point = $2.gsub(","," ").split(" ")
99
+ @geometry = Point.from_x_y(point[1].to_f,point[0].to_f)
100
+ elsif georss =~ /^<\s*[^>:]*:line([^>]*)>(.*)</m
101
+ tags = $1
102
+ @geometry = LineString.new
103
+ xy = $2.gsub(","," ").split(" ")
104
+ 0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
105
+ elsif georss =~ /^<\s*[^>:]*:polygon([^>]*)>(.*)</m
106
+ tags = $1
107
+ @geometry = Polygon.new
108
+ linear_ring = LinearRing.new
109
+ @geometry << linear_ring
110
+ xy = $2.gsub(","," ").split(" ")
111
+ 0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
112
+ elsif georss =~ /^<\s*[^>:]*:box([^>]*)>(.*)</m
113
+ tags = $1
114
+ corners = []
115
+ xy = $2.gsub(","," ").split(" ")
116
+ 0.upto(xy.size/2 - 1) {|index| corners << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)}
117
+ @geometry = Envelope.from_points(corners)
118
+ else
119
+ raise GeorssFormatError.new("Bad Simple GeoRSS format: Unknown geometry type")
120
+ end
121
+
122
+ #geometry found: parse tags
123
+ return unless with_tags
124
+
125
+ @georss_tags.featuretypetag = $1 if tags =~ /featuretypetag=['"]([^"']*)['"]/
126
+ @georss_tags.relationshiptag = $1 if tags =~ /relationshiptag=['"]([^'"]*)['"]/
127
+ @georss_tags.elev = $1.to_f if tags =~ /elev=['"]([^'"]*)['"]/
128
+ @georss_tags.floor = $1.to_i if tags =~ /floor=['"]([^'"]*)['"]/
129
+ @georss_tags.radius = $1.to_f if tags =~ /radius=['"]([^'"]*)['"]/
130
+
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end