# GeoJSON parser based on the v1.0 spec at http://geojson.org/geojson-spec.html require 'rubygems' begin require 'json' rescue LoadError puts "You've loaded GeoRuby GeoJSON Support." puts "Please install any 'json' provider gem. `gem install json`" end module GeoRuby # 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 def initialize(geometry, properties = {}, id = nil) @geometry = geometry @properties = properties @id = id end def ==(other) if (self.class != other.class) false else (id == other.id) && (geometry == other.geometry) && (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_method :as_geojson, :to_json end # Class added to support geojson 'Feature Collection' objects class GeoJSONFeatureCollection attr_accessor :features 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 features[index] != other.features[index] end end true end def to_json(options = {}) ({ type: 'FeatureCollection', features: features }).to_json end alias_method :as_geojson, :to_json end # GeoJSON main parser class GeoJSONParser include GeoRuby::SimpleFeatures attr_reader :geometry 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 fail GeoJSONFormatError, '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 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_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 nil end end # GeoJSONParser end # GeoRuby