# ----------------------------------------------------------------------------- # # GEOS factory implementation # # ----------------------------------------------------------------------------- # Copyright 2010 Daniel Azuma # # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # * Neither the name of the copyright holder, nor the names of any other # contributors to this software, may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ----------------------------------------------------------------------------- ; module RGeo module Geos # This the GEOS implementation of ::RGeo::Features::Factory. class Factory include Features::Factory class << self # Create a new factory. Returns nil if the GEOS implementation is # not supported. # # Options include: # # :lenient_multi_polygon_assertions:: # If set to true, assertion checking on MultiPolygon is disabled. # This may speed up creation of MultiPolygon objects, at the # expense of not doing the proper checking for OGC MultiPolygon # compliance. See RGeo::Features::MultiPolygon for details on # the MultiPolygon assertions. Default is false. # :buffer_resolution:: # The resolution of buffers around geometries created by this # factory. This controls the number of line segments used to # approximate curves. The default is 1, which causes, for # example, the buffer around a point to be approximated by a # 4-sided polygon. A resolution of 2 would cause that buffer # to be approximated by an 8-sided polygon. The exact behavior # for different kinds of buffers is defined by GEOS. # :srid:: # Set the SRID returned by geometries created by this factory. # Default is 0. def create(opts_={}) return nil unless respond_to?(:_create) flags_ = 0 flags_ |= 1 if opts_[:lenient_multi_polygon_assertions] buffer_resolution_ = opts_[:buffer_resolution].to_i buffer_resolution_ = 1 if buffer_resolution_ < 1 _create(flags_, opts_[:srid].to_i, buffer_resolution_) end alias_method :new, :create end # Returns the SRID of geometries created by this factory. def srid _srid end # Returns the resolution used by buffer calculations on geometries # created by this factory def buffer_resolution _buffer_resolution end # Returns true if this factory is lenient with MultiPolygon assertions def lenient_multi_polygons? _flags & 0x1 != 0 end # Equivalence test. def eql?(rhs_) rhs_.is_a?(Factory) && rhs_.srid == _srid && rhs_._buffer_resolution == _buffer_resolution && rhs_._flags == _flags end alias_method :==, :eql? # See ::RGeo::Features::Factory#parse_wkt def parse_wkt(str_) _parse_wkt_impl(str_) end # See ::RGeo::Features::Factory#parse_wkb def parse_wkb(str_) _parse_wkb_impl(str_) end # See ::RGeo::Features::Factory#point def point(x_, y_) PointImpl.create(self, x_, y_) rescue nil end # See ::RGeo::Features::Factory#line_string def line_string(points_) points_ = points_.to_a unless points_.kind_of?(::Array) LineStringImpl.create(self, points_) rescue nil end # See ::RGeo::Features::Factory#line def line(start_, end_) LineImpl.create(self, start_, end_) rescue nil end # See ::RGeo::Features::Factory#linear_ring def linear_ring(points_) points_ = points_.to_a unless points_.kind_of?(::Array) if points_.size > 1 && points_.first != points_.last points_ << points_.first end LinearRingImpl.create(self, points_) rescue nil end # See ::RGeo::Features::Factory#polygon def polygon(outer_ring_, inner_rings_=nil) inner_rings_ = inner_rings_.to_a unless inner_rings_.kind_of?(::Array) PolygonImpl.create(self, outer_ring_, inner_rings_) rescue nil end # See ::RGeo::Features::Factory#collection def collection(elems_) elems_ = elems_.to_a unless elems_.kind_of?(::Array) GeometryCollectionImpl.create(self, elems_) rescue nil end # See ::RGeo::Features::Factory#multi_point def multi_point(elems_) elems_ = elems_.to_a unless elems_.kind_of?(::Array) MultiPointImpl.create(self, elems_) rescue nil end # See ::RGeo::Features::Factory#multi_line_string def multi_line_string(elems_) elems_ = elems_.to_a unless elems_.kind_of?(::Array) MultiLineStringImpl.create(self, elems_) rescue nil end # See ::RGeo::Features::Factory#multi_polygon def multi_polygon(elems_) elems_ = elems_.to_a unless elems_.kind_of?(::Array) MultiPolygonImpl.create(self, elems_) rescue nil end # See ::RGeo::Features::Factory#cast def cast(original_, force_new_=false) return nil unless Geos.supported? case original_ when GeometryImpl if original_.factory != self result_ = original_.dup result_.instance_variable_set(:@_factory, self) result_ elsif force_new_ original_.dup else original_ end when Features::Point if original_.respond_to?(:z) PointImpl.create(self, original_.x, original_.y, original_.z) else PointImpl.create(self, original_.x, original_.y) end when Features::Line LineImpl.create(self, cast(original_.start_point), cast(original_.end_point)) when Features::LinearRing LinearRingImpl.create(self, original_.points.map{ |g_| cast(g_) }) when Features::LineString LineStringImpl.create(self, original_.points.map{ |g_| cast(g_) }) when Features::Polygon PolygonImpl.create(self, cast(original_.exterior_ring), original_.interior_rings.map{ |g_| cast(g_) }) when Features::MultiPoint MultiPointImpl.create(self, original_.to_a.map{ |g_| cast(g_) }) when Features::MultiLineString MultiLineStringImpl.create(self, original_.to_a.map{ |g_| cast(g_) }) when Features::MultiPolygon MultiPolygonImpl.create(self, original_.to_a.map{ |g_| cast(g_) }) when Features::GeometryCollection GeometryCollectionImpl.create(self, original_.to_a.map{ |g_| cast(g_) }) else nil end end # A GEOS extension that creates a 3-D point with a Z coordinate. def point3d(x_, y_, z_) PointImpl.create3d(self, x_, y_, z_) rescue nil end end end end