diff --git a/lib/geo_ruby.rb b/lib/geo_ruby.rb index f19d6b7..a8a398e 100644 --- a/lib/geo_ruby.rb +++ b/lib/geo_ruby.rb @@ -1,5 +1,5 @@ -$:.unshift(File.dirname(__FILE__)) unless - $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) +# $:.unshift(File.dirname(__FILE__)) #unless +# $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) require 'geo_ruby/simple_features/helper' require 'geo_ruby/simple_features/ewkt_parser' @@ -15,9 +15,9 @@ require 'geo_ruby/simple_features/geometry_collection' require 'geo_ruby/simple_features/envelope' require 'geo_ruby/simple_features/geometry_factory' -require 'geo_ruby/simple_features/georss_parser' -# Include if you need +# Require if you need # require 'geo_ruby/shp4r/shp' # require 'geo_ruby/gpx4r/gpx' -# require 'geo_ruby/simple_features/geojson_parser' +# require 'geo_ruby/geojson' +# require 'geo_ruby/georss' diff --git a/lib/geo_ruby/geojson.rb b/lib/geo_ruby/geojson.rb index a96a7cf..7085b71 100644 --- a/lib/geo_ruby/geojson.rb +++ b/lib/geo_ruby/geojson.rb @@ -1,131 +1,129 @@ # GeoJSON parser based on the v1.0 spec at http://geojson.org/geojson-spec.html module GeoRuby - module SimpleFeatures - #Raised when an error in the GeoJSON string is detected - class GeojsonFormatError < StandardError - end + #Raised when an error in the GeoJSON string is detected + class GeojsonFormatError < StandardError + end - # Class added to support geojson 'Feature' objects - class GeojsonFeature - attr_accessor :geometry, :properties, :id + # Class added to support geojson 'Feature' objects + class GeojsonFeature + attr_accessor :geometry, :properties, :id - def initialize(geometry, properties = {}, id = nil) - @geometry = geometry - @properties = properties - @id = id - end + def initialize(geometry, properties = {}, id = nil) + @geometry = geometry + @properties = properties + @id = id + end - def ==(other) - if (self.class != other.class) - false - else - (self.id == other.id) && (self.geometry == other.geometry) && (self.properties == other.properties) - end + def ==(other) + if (self.class != other.class) + false + else + (self.id == other.id) && (self.geometry == other.geometry) && (self.properties == other.properties) end + end - def to_json(options={}) - output = {} - output[:type] = 'Feature' - output[:geometry] = geometry - output[:properties] = properties - output[:id] = id unless id.nil? - output.to_json(options) - end - alias :as_geojson :to_json + def to_json(options={}) + output = {} + output[:type] = 'Feature' + output[:geometry] = geometry + output[:properties] = properties + output[:id] = id unless id.nil? + output.to_json(options) end + alias :as_geojson :to_json + end - # Class added to support geojson 'Feature Collection' objects - class GeojsonFeatureCollection - attr_accessor :features + # Class added to support geojson 'Feature Collection' objects + class GeojsonFeatureCollection + attr_accessor :features - def initialize(features) - @features = features - end + def initialize(features) + @features = features + end - def ==(other) - if (self.class != other.class) || (features.size != other.features.size) - return false - else - features.each_index do |index| - return false if self.features[index] != other.features[index] - end + def ==(other) + if (self.class != other.class) || (features.size != other.features.size) + return false + else + features.each_index do |index| + return false if self.features[index] != other.features[index] end - true end + true + end - def to_json(options = {}) - {:type => 'FeatureCollection', - :features => features}.to_json(options) - end - alias :as_geojson :to_json + def to_json(options = {}) + {:type => 'FeatureCollection', + :features => features}.to_json(options) end + alias :as_geojson :to_json + end - class GeojsonParser - attr_reader :geometry + class GeojsonParser + attr_reader :geometry - def parse(geojson, srid=DEFAULT_SRID) - @geometry = nil - geohash = JSON.parse(geojson) - parse_geohash(geohash, srid) - end + def parse(geojson, srid=DEFAULT_SRID) + @geometry = nil + geohash = JSON.parse(geojson) + parse_geohash(geohash, srid) + end - private - - def parse_geohash(geohash, srid) - srid = srid_from_crs(geohash['crs']) || srid - case geohash['type'] - when 'Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeometryCollection' - @geometry = parse_geometry(geohash, srid) - when 'Feature' - @geometry = parse_geojson_feature(geohash, srid) - when 'FeatureCollection' - @geometry = parse_geojson_feature_collection(geohash, srid) - else - GeojsonFormatError.new('Unknown GeoJSON type') - end + private + + def parse_geohash(geohash, srid) + srid = srid_from_crs(geohash['crs']) || srid + case geohash['type'] + when 'Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeometryCollection' + @geometry = parse_geometry(geohash, srid) + when 'Feature' + @geometry = parse_geojson_feature(geohash, srid) + when 'FeatureCollection' + @geometry = parse_geojson_feature_collection(geohash, srid) + else + GeojsonFormatError.new('Unknown GeoJSON type') end + end - def parse_geometry(geohash, srid) - srid = srid_from_crs(geohash['crs']) || srid - if geohash['type'] == 'GeometryCollection' - parse_geometry_collection(geohash, srid) - else - klass = GeoRuby::SimpleFeatures.const_get(geohash['type']) - klass.from_coordinates(geohash['coordinates'], srid, false, false) - end + def parse_geometry(geohash, srid) + srid = srid_from_crs(geohash['crs']) || srid + if geohash['type'] == 'GeometryCollection' + parse_geometry_collection(geohash, srid) + else + klass = GeoRuby::SimpleFeatures.const_get(geohash['type']) + klass.from_coordinates(geohash['coordinates'], srid, false, false) end + end - def parse_geometry_collection(geohash, srid) - srid = srid_from_crs(geohash['crs']) || srid - geometries = geohash['geometries'].map{|g| parse_geometry(g,srid)} - GeometryCollection.from_geometries(geometries,srid) - end + def parse_geometry_collection(geohash, srid) + srid = srid_from_crs(geohash['crs']) || srid + geometries = geohash['geometries'].map{|g| parse_geometry(g,srid)} + GeometryCollection.from_geometries(geometries,srid) + end - def parse_geojson_feature(geohash, srid) - srid = srid_from_crs(geohash['crs']) || srid - geometry = parse_geometry(geohash['geometry'],srid) - GeojsonFeature.new(geometry, geohash['properties'], geohash['id']) - end + def parse_geojson_feature(geohash, srid) + srid = srid_from_crs(geohash['crs']) || srid + geometry = parse_geometry(geohash['geometry'],srid) + GeojsonFeature.new(geometry, geohash['properties'], geohash['id']) + end - def parse_geojson_feature_collection(geohash, srid) - srid = srid_from_crs(geohash['crs']) || srid - features = [] - geohash['features'].each do |feature| - features << parse_geojson_feature(feature, srid) - end - GeojsonFeatureCollection.new(features) + def parse_geojson_feature_collection(geohash, srid) + srid = srid_from_crs(geohash['crs']) || srid + features = [] + geohash['features'].each do |feature| + features << parse_geojson_feature(feature, srid) end + GeojsonFeatureCollection.new(features) + end - def srid_from_crs(crs) - # We somehow need to map crs to srid, currently only support for EPSG - if crs && crs['type'] == 'OGC' - urn = crs['properties']['urn'].split(':') - return urn.last if urn[4] == 'EPSG' - end - return nil + def srid_from_crs(crs) + # We somehow need to map crs to srid, currently only support for EPSG + if crs && crs['type'] == 'OGC' + urn = crs['properties']['urn'].split(':') + return urn.last if urn[4] == 'EPSG' end + return nil end end end diff --git a/lib/geo_ruby/georss.rb b/lib/geo_ruby/georss.rb new file mode 100644 index 0000000..186681d --- /dev/null +++ b/lib/geo_ruby/georss.rb @@ -0,0 +1,133 @@ +# require 'geo_ruby/simple_features/point' +# require 'geo_ruby/simple_features/line_string' +# require 'geo_ruby/simple_features/linear_ring' +# require 'geo_ruby/simple_features/polygon' +# require 'geo_ruby/simple_features/multi_point' +# require 'geo_ruby/simple_features/multi_line_string' +# require 'geo_ruby/simple_features/multi_polygon' +# require 'geo_ruby/simple_features/geometry_collection' +# require 'geo_ruby/simple_features/envelope' + +module GeoRuby + + #Raised when an error in the GeoRSS string is detected + class GeorssFormatError < StandardError + end + + #Contains tags possibly found on GeoRss Simple geometries + class GeorssTags < Struct.new(:featuretypetag,:relationshiptag,:elev,:floor,:radius) + end + + #Parses GeoRSS strings + #You can also use directly the static method Geometry.from_georss + class GeorssParser + attr_reader :georss_tags, :geometry + + #Parses the georss geometry passed as argument and notifies the factory of events + #The parser assumes + def parse(georss,with_tags = false) + @geometry = nil + @georss_tags = GeorssTags.new + parse_geometry(georss,with_tags) + end + + private + def parse_geometry(georss,with_tags) + georss.strip! + #check for W3CGeo first + if georss =~ /<[^:>]*:lat\s*>([^<]*)]*:long\s*>([^<]*)]*:where\s*>/ + #GML format found + gml = $'.strip + if gml =~ /^<\s*[^:>]*:Point\s*>/ + #gml point + if gml =~ /<\s*[^:>]*:pos\s*>([^<]*)/ + point = $1.split(" ") + #lat comes first + @geometry = Point.from_x_y(point[1].to_f,point[0].to_f) + else + raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Point") + end + elsif gml =~ /^<\s*[^:>]*:LineString\s*>/ + if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/ + xy = $1.split(" ") + @geometry = LineString.new + 0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} + else + raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed LineString") + end + elsif gml =~ /^<\s*[^:>]*:Polygon\s*>/ + if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/ + xy = $1.split(" ") + @geometry = Polygon.new + linear_ring = LinearRing.new + @geometry << linear_ring + xy = $1.split(" ") + 0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} + else + raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Polygon") + end + elsif gml =~ /^<\s*[^:>]*:Envelope\s*>/ + if gml =~ /<\s*[^:>]*:lowerCorner\s*>([^<]*)]*:upperCorner\s*>([^<]*):]*:point([^>]*)>(.*):]*:line([^>]*)>(.*):]*:polygon([^>]*)>(.*):]*:box([^>]*)>(.*)]*:lat\s*>([^<]*)]*:long\s*>([^<]*)]*:where\s*>/ - #GML format found - gml = $'.strip - if gml =~ /^<\s*[^:>]*:Point\s*>/ - #gml point - if gml =~ /<\s*[^:>]*:pos\s*>([^<]*)/ - point = $1.split(" ") - #lat comes first - @geometry = Point.from_x_y(point[1].to_f,point[0].to_f) - else - raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Point") - end - elsif gml =~ /^<\s*[^:>]*:LineString\s*>/ - if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/ - xy = $1.split(" ") - @geometry = LineString.new - 0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} - else - raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed LineString") - end - elsif gml =~ /^<\s*[^:>]*:Polygon\s*>/ - if gml =~ /<\s*[^:>]*:posList\s*>([^<]*)/ - xy = $1.split(" ") - @geometry = Polygon.new - linear_ring = LinearRing.new - @geometry << linear_ring - xy = $1.split(" ") - 0.upto(xy.size/2 - 1) { |index| linear_ring << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} - else - raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Polygon") - end - elsif gml =~ /^<\s*[^:>]*:Envelope\s*>/ - if gml =~ /<\s*[^:>]*:lowerCorner\s*>([^<]*)]*:upperCorner\s*>([^<]*):]*:point([^>]*)>(.*):]*:line([^>]*)>(.*):]*:polygon([^>]*)>(.*):]*:box([^>]*)>(.*)