forked from nofxx/georuby
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
243 additions
and
240 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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*>([^<]*)</ | ||
#if valid, it is W3CGeo | ||
lat = $1.to_f | ||
if georss =~ /<[^:>]*:long\s*>([^<]*)</ | ||
lon = $1.to_f | ||
@geometry = Point.from_x_y(lon,lat) | ||
else | ||
raise GeorssFormatError.new("Bad W3CGeo GeoRSS format") | ||
end | ||
elsif georss =~ /^<\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*>([^<]*)</ | ||
lc = $1.split(" ").collect { |x| x.to_f}.reverse | ||
if gml =~ /<\s*[^:>]*:upperCorner\s*>([^<]*)</ | ||
uc = $1.split(" ").collect { |x| x.to_f}.reverse | ||
@geometry = Envelope.from_coordinates([lc,uc]) | ||
else | ||
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope") | ||
end | ||
else | ||
raise GeorssFormatError.new("Bad GML GeoRSS format: Malformed Envelope") | ||
end | ||
else | ||
raise GeorssFormatError.new("Bad GML GeoRSS format: Unknown geometry type") | ||
end | ||
else | ||
#must be simple format | ||
if georss =~ /^<\s*[^>:]*:point([^>]*)>(.*)</m | ||
tags = $1 | ||
point = $2.gsub(","," ").split(" ") | ||
@geometry = Point.from_x_y(point[1].to_f,point[0].to_f) | ||
elsif georss =~ /^<\s*[^>:]*:line([^>]*)>(.*)</m | ||
tags = $1 | ||
@geometry = LineString.new | ||
xy = $2.gsub(","," ").split(" ") | ||
0.upto(xy.size/2 - 1) { |index| @geometry << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} | ||
elsif georss =~ /^<\s*[^>:]*:polygon([^>]*)>(.*)</m | ||
tags = $1 | ||
@geometry = Polygon.new | ||
linear_ring = LinearRing.new | ||
@geometry << linear_ring | ||
xy = $2.gsub(","," ").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)} | ||
elsif georss =~ /^<\s*[^>:]*:box([^>]*)>(.*)</m | ||
tags = $1 | ||
corners = [] | ||
xy = $2.gsub(","," ").split(" ") | ||
0.upto(xy.size/2 - 1) {|index| corners << Point.from_x_y(xy[index*2 + 1].to_f,xy[index*2].to_f)} | ||
@geometry = Envelope.from_points(corners) | ||
else | ||
raise GeorssFormatError.new("Bad Simple GeoRSS format: Unknown geometry type") | ||
end | ||
|
||
#geometry found: parse tags | ||
return unless with_tags | ||
|
||
@georss_tags.featuretypetag = $1 if tags =~ /featuretypetag=['"]([^"']*)['"]/ | ||
@georss_tags.relationshiptag = $1 if tags =~ /relationshiptag=['"]([^'"]*)['"]/ | ||
@georss_tags.elev = $1.to_f if tags =~ /elev=['"]([^'"]*)['"]/ | ||
@georss_tags.floor = $1.to_i if tags =~ /floor=['"]([^'"]*)['"]/ | ||
@georss_tags.radius = $1.to_f if tags =~ /radius=['"]([^'"]*)['"]/ | ||
|
||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.