ppe-georuby 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +6 -0
  2. data/History.txt +4 -0
  3. data/LICENSE +21 -0
  4. data/README.txt +118 -0
  5. data/Rakefile +48 -0
  6. data/VERSION +1 -0
  7. data/lib/geo_ruby.rb +22 -0
  8. data/lib/geo_ruby/gpx.rb +1 -0
  9. data/lib/geo_ruby/gpx4r/gpx.rb +117 -0
  10. data/lib/geo_ruby/shp.rb +1 -0
  11. data/lib/geo_ruby/shp4r/dbf.rb +41 -0
  12. data/lib/geo_ruby/shp4r/shp.rb +697 -0
  13. data/lib/geo_ruby/simple_features/envelope.rb +167 -0
  14. data/lib/geo_ruby/simple_features/ewkb_parser.rb +216 -0
  15. data/lib/geo_ruby/simple_features/ewkt_parser.rb +336 -0
  16. data/lib/geo_ruby/simple_features/geometry.rb +228 -0
  17. data/lib/geo_ruby/simple_features/geometry_collection.rb +136 -0
  18. data/lib/geo_ruby/simple_features/geometry_factory.rb +81 -0
  19. data/lib/geo_ruby/simple_features/georss_parser.rb +135 -0
  20. data/lib/geo_ruby/simple_features/helper.rb +18 -0
  21. data/lib/geo_ruby/simple_features/line_string.rb +206 -0
  22. data/lib/geo_ruby/simple_features/linear_ring.rb +12 -0
  23. data/lib/geo_ruby/simple_features/multi_line_string.rb +51 -0
  24. data/lib/geo_ruby/simple_features/multi_point.rb +46 -0
  25. data/lib/geo_ruby/simple_features/multi_polygon.rb +52 -0
  26. data/lib/geo_ruby/simple_features/point.rb +364 -0
  27. data/lib/geo_ruby/simple_features/polygon.rb +157 -0
  28. data/ppe-georuby.gemspec +133 -0
  29. data/script/console +10 -0
  30. data/script/destroy +14 -0
  31. data/script/generate +14 -0
  32. data/script/txt2html +82 -0
  33. data/spec/data/gpx/fells_loop.gpx +1077 -0
  34. data/spec/data/gpx/long.gpx +1642 -0
  35. data/spec/data/gpx/long.kml +31590 -0
  36. data/spec/data/gpx/long.nmea +2220 -0
  37. data/spec/data/gpx/short.gpx +13634 -0
  38. data/spec/data/gpx/short.kml +130 -0
  39. data/spec/data/gpx/tracktreks.gpx +706 -0
  40. data/spec/data/multipoint.dbf +0 -0
  41. data/spec/data/multipoint.shp +0 -0
  42. data/spec/data/multipoint.shx +0 -0
  43. data/spec/data/point.dbf +0 -0
  44. data/spec/data/point.shp +0 -0
  45. data/spec/data/point.shx +0 -0
  46. data/spec/data/polygon.dbf +0 -0
  47. data/spec/data/polygon.shp +0 -0
  48. data/spec/data/polygon.shx +0 -0
  49. data/spec/data/polyline.dbf +0 -0
  50. data/spec/data/polyline.shp +0 -0
  51. data/spec/data/polyline.shx +0 -0
  52. data/spec/geo_ruby/gpx4r/gpx_spec.rb +106 -0
  53. data/spec/geo_ruby/shp4r/shp_spec.rb +240 -0
  54. data/spec/geo_ruby/simple_features/envelope_spec.rb +45 -0
  55. data/spec/geo_ruby/simple_features/ewkb_parser_spec.rb +158 -0
  56. data/spec/geo_ruby/simple_features/ewkt_parser_spec.rb +179 -0
  57. data/spec/geo_ruby/simple_features/geometry_collection_spec.rb +55 -0
  58. data/spec/geo_ruby/simple_features/geometry_factory_spec.rb +11 -0
  59. data/spec/geo_ruby/simple_features/geometry_spec.rb +32 -0
  60. data/spec/geo_ruby/simple_features/georss_parser_spec.rb +218 -0
  61. data/spec/geo_ruby/simple_features/line_string_spec.rb +245 -0
  62. data/spec/geo_ruby/simple_features/linear_ring_spec.rb +14 -0
  63. data/spec/geo_ruby/simple_features/multi_line_string_spec.rb +54 -0
  64. data/spec/geo_ruby/simple_features/multi_point_spec.rb +35 -0
  65. data/spec/geo_ruby/simple_features/multi_polygon_spec.rb +50 -0
  66. data/spec/geo_ruby/simple_features/point_spec.rb +356 -0
  67. data/spec/geo_ruby/simple_features/polygon_spec.rb +108 -0
  68. data/spec/geo_ruby_spec.rb +27 -0
  69. data/spec/spec.opts +6 -0
  70. data/spec/spec_helper.rb +65 -0
  71. metadata +162 -0
@@ -0,0 +1,228 @@
1
+ module GeoRuby#:nodoc:
2
+ module SimpleFeatures
3
+ #arbitrary default SRID
4
+ DEFAULT_SRID = 4326 unless defined? DEFAULT_SRID
5
+
6
+
7
+ #Root of all geometric data classes.
8
+ #Objects of class Geometry should not be instantiated.
9
+ class Geometry
10
+ #SRID of the geometry
11
+ attr_reader :srid #writer defined below
12
+ #Flag indicating if the z ordinate of the geometry is meaningful
13
+ attr_accessor :with_z
14
+ alias :with_z? :with_z
15
+ #Flag indicating if the m ordinate of the geometry is meaningful
16
+ attr_accessor :with_m
17
+ alias :with_m? :with_m
18
+
19
+ def initialize(srid=DEFAULT_SRID,with_z=false,with_m=false)
20
+ @srid=srid
21
+ @with_z=with_z
22
+ @with_m=with_m
23
+ end
24
+
25
+ def srid=(new_srid)
26
+ @srid = new_srid
27
+ unless self.is_a?(Point)
28
+ self.each do |geom|
29
+ geom.srid=new_srid
30
+ end
31
+ end
32
+ end
33
+
34
+ #to be implemented in subclasses
35
+ def bounding_box
36
+ end
37
+
38
+ #to be implemented in subclasses
39
+ def m_range
40
+ end
41
+
42
+ #Returns an Envelope object for the geometry
43
+ def envelope
44
+ Envelope.from_points(bounding_box,srid,with_z)
45
+ end
46
+
47
+ #Outputs the geometry as an EWKB string.
48
+ #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.
49
+ def as_ewkb(allow_srid=true,allow_z=true,allow_m=true)
50
+ ewkb="";
51
+
52
+ ewkb << 1.chr #little_endian by default
53
+
54
+ type= binary_geometry_type
55
+ if @with_z and allow_z
56
+ type = type | Z_MASK
57
+ end
58
+ if @with_m and allow_m
59
+ type = type | M_MASK
60
+ end
61
+ if allow_srid
62
+ type = type | SRID_MASK
63
+ ewkb << [type,@srid].pack("VV")
64
+ else
65
+ ewkb << [type].pack("V")
66
+ end
67
+
68
+ ewkb << binary_representation(allow_z,allow_m)
69
+ end
70
+
71
+ #Outputs the geometry as a strict WKB string.
72
+ def as_wkb
73
+ as_ewkb(false,false,false)
74
+ end
75
+
76
+ #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.
77
+ def as_hex_ewkb(allow_srid=true,allow_z=true,allow_m=true)
78
+ as_ewkb(allow_srid, allow_z, allow_m).unpack('H*').join('').upcase
79
+ end
80
+
81
+ #Outputs the geometry as a strict HexWKB string
82
+ def as_hex_wkb
83
+ as_hex_ewkb(false,false,false)
84
+ end
85
+
86
+ #Outputs the geometry as an EWKT string.
87
+ def as_ewkt(allow_srid=true,allow_z=true,allow_m=true)
88
+ if allow_srid
89
+ ewkt="SRID=#{@srid};"
90
+ else
91
+ ewkt=""
92
+ end
93
+ ewkt << text_geometry_type
94
+ 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...
95
+ ewkt << "(" << text_representation(allow_z,allow_m) << ")"
96
+ end
97
+
98
+ #Outputs the geometry as strict WKT string.
99
+ def as_wkt
100
+ as_ewkt(false,false,false)
101
+ end
102
+
103
+ #Outputs the geometry in georss format.
104
+ #Assumes the geometries are in latlon format, with x as lon and y as lat.
105
+ #Pass the <tt>:dialect</tt> option to swhit format. Possible values are: <tt>:simple</tt> (default), <tt>:w3cgeo</tt> and <tt>:gml</tt>.
106
+ def as_georss(options = {})
107
+ dialect= options[:dialect] || :simple
108
+ case(dialect)
109
+ when :simple
110
+ geom_attr = ""
111
+ geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
112
+ geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
113
+ geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
114
+ geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
115
+ geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
116
+ georss_simple_representation(options.merge(:geom_attr => geom_attr))
117
+ when :w3cgeo
118
+ georss_w3cgeo_representation(options)
119
+ when :gml
120
+ georss_gml_representation(options)
121
+ end
122
+ end
123
+
124
+ #Iutputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
125
+ #<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
126
+ #it won't be used by GE anyway: clampToGround is the default)
127
+ def as_kml(options = {})
128
+ id_attr = ""
129
+ id_attr = " id=\"#{options[:id]}\"" if options[:id]
130
+
131
+ geom_data = ""
132
+ geom_data += "<extrude>#{options[:extrude]}</extrude>\n" if options[:extrude]
133
+ geom_data += "<tesselate>#{options[:tesselate]}</tesselate>\n" if options[:tesselate]
134
+ geom_data += "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
135
+
136
+ allow_z = (with_z || !options[:altitude].nil? )&& (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
137
+ fixed_z = options[:altitude]
138
+
139
+ kml_representation(options.merge(:id_attr => id_attr, :geom_data => geom_data, :allow_z => allow_z, :fixed_z => fixed_z))
140
+ end
141
+
142
+ #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.
143
+ def self.from_ewkb(ewkb)
144
+ factory = GeometryFactory::new
145
+ ewkb_parser= EWKBParser::new(factory)
146
+ ewkb_parser.parse(ewkb)
147
+ factory.geometry
148
+ end
149
+ #Creates a geometry based on a HexEWKB string
150
+ def self.from_hex_ewkb(hexewkb)
151
+ factory = GeometryFactory::new
152
+ hexewkb_parser= HexEWKBParser::new(factory)
153
+ hexewkb_parser.parse(hexewkb)
154
+ factory.geometry
155
+ end
156
+ #Creates a geometry based on a EWKT string. Since WKT strings are a subset of EWKT, they are also valid.
157
+ def self.from_ewkt(ewkt)
158
+ factory = GeometryFactory::new
159
+ ewkt_parser= EWKTParser::new(factory)
160
+ ewkt_parser.parse(ewkt)
161
+ factory.geometry
162
+ end
163
+
164
+ #sends back a geometry based on the GeoRSS string passed as argument
165
+ def self.from_georss(georss)
166
+ georss_parser= GeorssParser::new
167
+ georss_parser.parse(georss)
168
+ georss_parser.geometry
169
+ end
170
+ #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)
171
+ def self.from_georss_with_tags(georss)
172
+ georss_parser= GeorssParser::new
173
+ georss_parser.parse(georss,true)
174
+ [georss_parser.geometry, georss_parser.georss_tags]
175
+ end
176
+
177
+ #Sends back a geometry from a KML encoded geometry string.
178
+ #Limitations : Only supports points, linestrings and polygons (no collection for now).
179
+ #Addapted from Pramukta's code
180
+ def self.from_kml(kml)
181
+ return GeoRuby::SimpleFeatures::Geometry.from_ewkt(kml_to_wkt(kml))
182
+ end
183
+
184
+ require 'rexml/document'
185
+ def self.kml_to_wkt(kml)
186
+ doc = REXML::Document.new(kml)
187
+ wkt = ""
188
+ if ["Point", "LineString", "Polygon" ].include?(doc.root.name)
189
+ case doc.root.name
190
+ when "Point" then
191
+ coords = doc.elements["/Point/coordinates"].text.gsub(/\n/," ")
192
+ wkt = doc.root.name.upcase + "(" + split_coords(coords).join(' ') + ")"
193
+ when "LineString" then
194
+ coords = doc.elements["/LineString/coordinates"].text.gsub(/\n/," ")
195
+ coords = split_coords(coords)
196
+ wkt = doc.root.name.upcase + "(" + coords.join(",") + ")"
197
+ when "Polygon" then
198
+ # polygons have one outer ring and zero or more inner rings
199
+ bounds = []
200
+ bounds << doc.elements["/Polygon/outerBoundaryIs/LinearRing/coordinates"].text
201
+ inner_coords_elements = doc.elements.each("/Polygon/innerBoundaryIs/LinearRing/coordinates") do |inner_coords|
202
+ inner_coords = inner_coords.text
203
+ bounds << inner_coords
204
+ end
205
+
206
+ wkt = doc.root.name.upcase + "(" + bounds.map do |bound|
207
+ bound.gsub!(/\n/, " ")
208
+ bound = split_coords(bound)
209
+ if bound.first != bound.last
210
+ bound.push bound.first
211
+ end
212
+ "(" + bound.join(",") + ")"
213
+ end.join(",") + ")"
214
+ end
215
+ end
216
+ return wkt
217
+ end
218
+
219
+ private
220
+
221
+ def self.split_coords(coords)
222
+ coords.split(" ").collect { |coord|
223
+ coord.gsub(","," ")
224
+ }
225
+ end
226
+ end
227
+ end
228
+ 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