The Feature namespace contains interfaces and general tools for implementations of the Open Geospatial Consortium Simple Features Specification (SFS), version 1.1.0.
Each interface is defined as a module, and is provided primarily for the sake of documentation. Implementations do not necessarily include the modules themselves. Therefore, you should not depend on the kind_of? method to check type. Instead, each interface module will provide a check_type class method (and a corresponding === operator to support case-when constructs).
In addition, a Factory interface is defined here. A factory is an object that knows how to construct geometry instances for a given implementation. Each implementation’s front-end consists of a way to create factories. Those factories, in turn, provide the api for building the features themselves. Note that, like the geometry modules, the Factory module itself may not actually be included in a factory implementation.
Any particular implementation may extend these interfaces to provide implementation-specific features beyond what is stated in the SFS itself. The implementation should separately document any such extensions that it may provide.
Cast the given object according to the given parameters, if possible, and return the resulting object. If the requested cast is not possible, nil is returned.
Parameters may be provided as a hash, or as separate arguments. Hash keys are as follows:
:factory
Set the factory to the given factory. If this argument is not given, the original object’s factory is kept.
:type
Cast to the given type, which must be a module in the RGeo::Feature namespace. If this argument is not given, the result keeps the same type as the original.
:project
If this is set to true, and both the original and new factories support proj4 projections, then the cast will also cause the coordinates to be transformed between those two projections. If set to false, the coordinates are not modified. Default is false.
:keep_subtype
Value must be a boolean indicating whether to keep the subtype of the original. If set to false, casting to a particular type always casts strictly to that type, even if the old type is a subtype of the new type. If set to true, the cast retains the subtype in that case. For example, casting a LinearRing to a LineString will normally yield a LineString, even though LinearRing is already a more specific subtype. If you set this value to true, the casted object will remain a LinearRing. Default is false.
:force_new
Always return a newly-created object, even if neither the type nor factory is modified. Normally, if this is set to false, and a cast is not set to modify either the factory or type, the original object itself is returned. Setting this flag to true causes cast to return a clone in that case. Default is false.
You may also pass the new factory, the new type, and the flags as separate arguments. In this case, the flag names must be passed as symbols, and their effect is the same as setting their values to true. You can even combine separate arguments and hash arguments. For example, the following three calls are equivalent:
RGeo::Feature.cast(geom, :type => RGeo::Feature::Point, :project => true) RGeo::Feature.cast(geom, RGeo::Feature::Point, :project => true) RGeo::Feature.cast(geom, RGeo::Feature::Point, :project)
RGeo provides a default casting algorithm. Individual feature implementation factories may override this and customize the casting behavior by defining the override_cast method. See RGeo::Feature::Factory#override_cast for more details.
# File lib/rgeo/feature/types.rb, line 209 def cast(obj_, *params_) # Interpret params factory_ = obj_.factory type_ = obj_.geometry_type opts_ = {} params_.each do |param_| case param_ when Factory::Instance opts_[:factory] = param_ when Type opts_[:type] = param_ when ::Symbol opts_[param_] = true when ::Hash opts_.merge!(param_) end end force_new_ = opts_[:force_new] keep_subtype_ = opts_[:keep_subtype] project_ = opts_[:project] nfactory_ = opts_.delete(:factory) || factory_ ntype_ = opts_.delete(:type) || type_ # Let the factory override if nfactory_.respond_to?(:override_cast) override_ = nfactory_.override_cast(obj_, ntype_, opts_) return override_ unless override_ == false end # Default algorithm ntype_ = type_ if keep_subtype_ && type_.include?(ntype_) if ntype_ == type_ # Types are the same if nfactory_ == factory_ force_new_ ? obj_.dup : obj_ else if type_ == Point proj_ = nproj_ = nil if project_ proj_ = factory_.proj4 nproj_ = nfactory_.proj4 end hasz_ = factory_.property(:has_z_coordinate) nhasz_ = nfactory_.property(:has_z_coordinate) if proj_ && nproj_ coords_ = CoordSys::Proj4.transform_coords(proj_, nproj_, obj_.x, obj_.y, hasz_ ? obj_.z : nil) coords_ << (hasz_ ? obj_.z : 0.0) if nhasz_ && coords_.size < 3 else coords_ = [obj_.x, obj_.y] coords_ << (hasz_ ? obj_.z : 0.0) if nhasz_ end coords_ << (factory_.property(:has_m_coordinate) ? obj_.m : 0.0) if nfactory_.property(:has_m_coordinate) nfactory_.point(*coords_) elsif type_ == Line nfactory_.line(cast(obj_.start_point, nfactory_, opts_), cast(obj_.end_point, nfactory_, opts_)) elsif type_ == LinearRing nfactory_.linear_ring(obj_.points.map{ |p_| cast(p_, nfactory_, opts_) }) elsif type_ == LineString nfactory_.line_string(obj_.points.map{ |p_| cast(p_, nfactory_, opts_) }) elsif type_ == Polygon nfactory_.polygon(cast(obj_.exterior_ring, nfactory_, opts_), obj_.interior_rings.map{ |r_| cast(r_, nfactory_, opts_) }) elsif type_ == MultiPoint nfactory_.multi_point(obj_.map{ |g_| cast(g_, nfactory_, opts_) }) elsif type_ == MultiLineString nfactory_.multi_line_string(obj_.map{ |g_| cast(g_, nfactory_, opts_) }) elsif type_ == MultiPolygon nfactory_.multi_polygon(obj_.map{ |g_| cast(g_, nfactory_, opts_) }) elsif type_ == GeometryCollection nfactory_.collection(obj_.map{ |g_| cast(g_, nfactory_, opts_) }) else nil end end else # Types are different if ntype_ == Point && (type_ == MultiPoint || type_ == GeometryCollection) || (ntype_ == Line || ntype_ == LineString || ntype_ == LinearRing) && (type_ == MultiLineString || type_ == GeometryCollection) || ntype_ == Polygon && (type_ == MultiPolygon || type_ == GeometryCollection) then if obj_.num_geometries == 1 cast(obj_.geometry_n(0), nfactory_, ntype_, opts_) else nil end elsif ntype_ == Point nil elsif ntype_ == Line if type_ == LineString && obj_.num_points == 2 nfactory_.line(cast(obj_.point_n(0), nfactory_, opts_), cast(obj_.point_n(1), nfactory_, opts_)) else nil end elsif ntype_ == LinearRing if type_ == LineString nfactory_.linear_ring(obj_.points.map{ |p_| cast(p_, nfactory_, opts_) }) else nil end elsif ntype_ == LineString if type_ == Line || type_ == LinearRing nfactory_.line_string(obj_.points.map{ |p_| cast(p_, nfactory_, opts_) }) else nil end elsif ntype_ == MultiPoint if type_ == Point nfactory_.multi_point([cast(obj_, nfactory_, opts_)]) elsif type_ == GeometryCollection nfactory_.multi_point(obj_.map{ |g_| cast(p_, nfactory_, opts_) }) else nil end elsif ntype_ == MultiLineString if type_ == Line || type_ == LinearRing || type_ == LineString nfactory_.multi_line_string([cast(obj_, nfactory_, opts_)]) elsif type_ == GeometryCollection nfactory_.multi_line_string(obj_.map{ |g_| cast(p_, nfactory_, opts_) }) else nil end elsif ntype_ == MultiPolygon if type_ == Polygon nfactory_.multi_polygon([cast(obj_, nfactory_, opts_)]) elsif type_ == GeometryCollection nfactory_.multi_polygon(obj_.map{ |g_| cast(p_, nfactory_, opts_) }) else nil end elsif ntype_ == GeometryCollection if type_ == MultiPoint || type_ == MultiLineString || type_ == MultiPolygon nfactory_.collection(obj_.map{ |g_| cast(p_, nfactory_, opts_) }) else nfactory_.collection([cast(obj_, nfactory_, opts_)]) end else nil end end end