module GeoRuby #:nodoc:
module SimpleFeatures
# Default SRID
DEFAULT_SRID = 4326 unless defined? DEFAULT_SRID
# Root of all geometric data classes.
# Objects of class Geometry should not be instantiated.
class Geometry
# SRID of the geometry
attr_reader :srid # writer defined below
# Flag indicating if the z ordinate of the geometry is meaningful
attr_accessor :with_z
alias_method :with_z?, :with_z
# Flag indicating if the m ordinate of the geometry is meaningful
attr_accessor :with_m
alias_method :with_m?, :with_m
def initialize(srid = DEFAULT_SRID, with_z = false, with_m = false)
@srid = srid
@with_z = with_z
@with_m = with_m
end
def srid=(new_srid)
@srid = new_srid
unless self.is_a?(Point)
each do |geom|
geom.srid = new_srid
end
end
end
# to be implemented in subclasses
def bounding_box
end
# to be implemented in subclasses
def m_range
end
#
# Returns an Envelope object for the geometry
#
def envelope
Envelope.from_points(bounding_box, srid, with_z)
end
#
# Outputs the geometry as an EWKB string.
#
# The +allow_srid+, +allow_z+ and +allow_m+ arguments allow the output
# to include srid, z and m respectively if they are present.
# 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.
#
def as_ewkb(allow_srid = true, allow_z = true, allow_m = true)
ewkb = 1.chr # little_endian by default
type = binary_geometry_type
type |= Z_MASK if @with_z && allow_z
type |= M_MASK if @with_m && allow_m
if allow_srid
type = type | SRID_MASK
ewkb << [type, @srid].pack('VV')
else
ewkb << [type].pack('V')
end
ewkb << binary_representation(allow_z, allow_m)
end
#
# Outputs the geometry as a strict WKB string.
#
def as_wkb
as_ewkb(false, false, false)
end
#
# 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 hex 2-char representation in a HexEWKB string.
#
def as_hex_ewkb(allow_srid = true, allow_z = true, allow_m = true)
as_ewkb(allow_srid, allow_z, allow_m).unpack('H*').join('').upcase
end
#
# Outputs the geometry as a strict HexWKB string
#
def as_hex_wkb
as_hex_ewkb(false, false, false)
end
#
# Outputs the geometry as an EWKT string.
#
def as_ewkt(allow_srid = true, allow_z = true, allow_m = true)
if allow_srid
ewkt = "SRID=#{@srid};"
else
ewkt = ''
end
ewkt << text_geometry_type
# to distinguish the M from the Z when there is actually no Z...
ewkt << 'M' if @with_m && allow_m && (!@with_z || !allow_z)
ewkt << '(' << text_representation(allow_z, allow_m) << ')'
end
#
# Outputs the geometry as strict WKT string.
#
def as_wkt
as_ewkt(false, false, false)
end
# Outputs the geometry in georss format.
# Assumes the geometries are in latlon format, with x as lon and y as lat.
# Pass the :dialect option to swhit format. Possible values are:
# :simple (default), :w3cgeo and :gml.
def as_georss(options = {})
dialect = options[:dialect] || :simple
case (dialect)
when :simple
geom_attr = ''
if options[:featuretypetag]
geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\""
end
if options[:relationshiptag]
geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\""
end
geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
georss_simple_representation(options.merge(geom_attr: geom_attr))
when :w3cgeo
georss_w3cgeo_representation(options)
when :gml
georss_gml_representation(options)
end
end
# Iutputs the geometry in kml format : options are :id,
# :tesselate, :extrude, :altitude_mode.
# If the altitude_mode option is not present, the Z (if present) will not
# be output (since it won't be used by GE: clampToGround is the default)
def as_kml(options = {})
id_attr = ''
id_attr = " id=\"#{options[:id]}\"" if options[:id]
geom_data = ''
if options[:extrude]
geom_data += "#{options[:extrude]}\n"
end
if options[:tesselate]
geom_data += "#{options[:tesselate]}\n"
end
if options[:altitude_mode]
geom_data += "#{options[:altitude_mode]}\n"
end
allow_z = (with_z || !options[:altitude].nil?) &&
(!options[:altitude_mode].nil?) &&
options[:atitude_mode] != 'clampToGround'
fixed_z = options[:altitude]
kml_representation(options.merge(id_attr: id_attr, geom_data: geom_data,
allow_z: allow_z, fixed_z: fixed_z))
end
# simple geojson representation
# TODO add CRS / SRID support?
def to_json(options = {})
as_json(options).to_json(options)
end
def as_json(_options = {})
# Implemented by each class
end
alias_method :as_geojson, :as_json
# 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.
def self.from_ewkb(ewkb)
factory = GeometryFactory.new
ewkb_parser = EWKBParser.new(factory)
ewkb_parser.parse(ewkb)
factory.geometry
end
# Creates a geometry based on a HexEWKB string given.
def self.from_hex_ewkb(hexewkb)
factory = GeometryFactory.new
hexewkb_parser = HexEWKBParser.new(factory)
hexewkb_parser.parse(hexewkb)
factory.geometry
end
# Creates a geometry based on a EWKT string. Since WKT strings are a
# subset of EWKT, they are also valid.
def self.from_ewkt(ewkt)
factory = GeometryFactory.new
ewkt_parser = EWKTParser.new(factory)
ewkt_parser.parse(ewkt)
factory.geometry
end
# Creates a geometry based on the GeoRSS string given.
def self.from_georss(georss)
georss_parser = GeorssParser.new
georss_parser.parse(georss)
georss_parser.geometry
end
# 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)
def self.from_georss_with_tags(georss)
georss_parser = GeorssParser.new
georss_parser.parse(georss, true)
[georss_parser.geometry, georss_parser.georss_tags]
end
# Sends back a geometry from a KML encoded geometry string.
def self.from_kml(kml)
factory = GeometryFactory.new
parser = KmlParser.new(factory)
parser.parse(kml)
end
# Some GeoJSON files do not include srid info, so
# we provide an optional parameter
def self.from_geojson(geojson, srid = DEFAULT_SRID)
geojson_parser = GeoJSONParser.new
geojson_parser.parse(geojson, srid)
geojson_parser.geometry
end
private
def self.split_coords(coords)
coords.split(' ').collect do |coord|
coord.gsub(',', ' ')
end
end
end
end
end