class Geos::CoordinateSequence
A CoordinateSequence
is a list of coordinates in a Geometry
.
Attributes
Public Class Methods
The ptr version of the initializer is for internal use.
new(points) will try to glean the size and dimensions of your CoordinateSequence
from an Array of points. The Array should contain uniform-sized Arrays which represent the [ x, y, z ] values of your coordinates.
# File lib/ffi-geos/coordinate_sequence.rb, line 57 def initialize(*args) points = nil # forward declaration we can use later ptr, auto_free, parent = if args.first.is_a?(FFI::Pointer) args.first(3) else size, dimensions = if args.first.is_a?(Array) points = if args.first.first.is_a?(Array) args.first else args end lengths = points.collect(&:length).uniq if lengths.empty? [0, 0] elsif lengths.length != 1 raise ParseError, 'Different sized points found in Array' elsif !lengths.first.between?(1, 3) raise ParseError, 'Expected points to contain 1-3 elements' else [points.length, points.first.length] end elsif args.first.is_a?(Hash) args.first.values_at(:size, :dimensions) elsif !args.length.between?(0, 2) raise ArgumentError, "wrong number of arguments (#{args.length} for 0-2)" else [args[0], args[1]] end size ||= 0 dimensions ||= 0 [FFIGeos.GEOSCoordSeq_create_r(Geos.current_handle_pointer, size, dimensions), true] end @ptr = FFI::AutoPointer.new( ptr, self.class.method(:release) ) @ptr.autorelease = auto_free @parent = parent if parent @x = CoordinateAccessor.new(self, 0) @y = CoordinateAccessor.new(self, 1) @z = CoordinateAccessor.new(self, 2) return unless points points.each_with_index do |point, idx| point.each_with_index do |val, dim| set_ordinate(idx, dim, val) end end end
Public Instance Methods
# File lib/ffi-geos/coordinate_sequence.rb, line 145 def [](*args) if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0 i = args.first ary = [get_x(i), get_y(i)] ary << get_z(i) if has_z? ary else to_a[*args] end end
# File lib/ffi-geos/coordinate_sequence.rb, line 374 def affine(options) dup.affine!(options) end
# File lib/ffi-geos/coordinate_sequence.rb, line 348 def affine!(options) options.default = 0.0 if has_z? length.times do |i| x = self.x[i] y = self.y[i] z = self.z[i] self.x[i] = (options[:afac] * x) + (options[:bfac] * y) + (options[:cfac] * z) + options[:xoff] self.y[i] = (options[:dfac] * x) + (options[:efac] * y) + (options[:ffac] * z) + options[:yoff] self.z[i] = (options[:gfac] * x) + (options[:hfac] * y) + (options[:ifac] * z) + options[:zoff] end else length.times do |i| x = self.x[i] y = self.y[i] self.x[i] = (options[:afac] * x) + (options[:bfac] * y) + options[:xoff] self.y[i] = (options[:dfac] * x) + (options[:efac] * y) + options[:yoff] end end self end
Available in GEOS 3.7+.
# File lib/ffi-geos/coordinate_sequence.rb, line 239 def counter_clockwise? char_ptr = FFI::MemoryPointer.new(:char) FFIGeos.GEOSCoordSeq_isCCW_r(Geos.current_handle_pointer, ptr, char_ptr) Tools.bool_result(char_ptr.read_char) end
# File lib/ffi-geos/coordinate_sequence.rb, line 227 def dimensions if defined?(@dimensions) @dimensions else int_ptr = FFI::MemoryPointer.new(:int) FFIGeos.GEOSCoordSeq_getDimensions_r(Geos.current_handle_pointer, ptr, int_ptr) @dimensions = int_ptr.read_int end end
Yields coordinates as [ x, y, z ]. The z coordinate may be omitted for 2-dimensional CoordinateSequences.
# File lib/ffi-geos/coordinate_sequence.rb, line 132 def each if block_given? length.times do |n| yield build_coordinate(n) end self else length.times.collect { |n| build_coordinate(n) }.to_enum end end
# File lib/ffi-geos/coordinate_sequence.rb, line 223 def empty? length.zero? end
# File lib/ffi-geos/coordinate_sequence.rb, line 209 def get_ordinate(idx, dim) check_bounds(idx) double_ptr = FFI::MemoryPointer.new(:double) FFIGeos.GEOSCoordSeq_getOrdinate_r(Geos.current_handle_pointer, ptr, idx, dim, double_ptr) double_ptr.read_double end
Gets the x value of a coordinate. Can also be retrieved via x
[].
# File lib/ffi-geos/coordinate_sequence.rb, line 186 def get_x(idx) check_bounds(idx) double_ptr = FFI::MemoryPointer.new(:double) FFIGeos.GEOSCoordSeq_getX_r(Geos.current_handle_pointer, ptr, idx, double_ptr) double_ptr.read_double end
Gets the y value of a coordinate. Can also be retrieved via y
[].
# File lib/ffi-geos/coordinate_sequence.rb, line 194 def get_y(idx) check_bounds(idx) double_ptr = FFI::MemoryPointer.new(:double) FFIGeos.GEOSCoordSeq_getY_r(Geos.current_handle_pointer, ptr, idx, double_ptr) double_ptr.read_double end
Gets the z value of a coordinate. Can also be retrieved via z
[].
# File lib/ffi-geos/coordinate_sequence.rb, line 202 def get_z(idx) check_bounds(idx) double_ptr = FFI::MemoryPointer.new(:double) FFIGeos.GEOSCoordSeq_getZ_r(Geos.current_handle_pointer, ptr, idx, double_ptr) double_ptr.read_double end
# File lib/ffi-geos/coordinate_sequence.rb, line 115 def initialize_copy(source) @ptr = FFI::AutoPointer.new( FFIGeos.GEOSCoordSeq_clone_r(Geos.current_handle_pointer, source.ptr), self.class.method(:release) ) @x = CoordinateAccessor.new(self, 0) @y = CoordinateAccessor.new(self, 1) @z = CoordinateAccessor.new(self, 2) end
# File lib/ffi-geos/coordinate_sequence.rb, line 216 def length int_ptr = FFI::MemoryPointer.new(:int) FFIGeos.GEOSCoordSeq_getSize_r(Geos.current_handle_pointer, ptr, int_ptr) int_ptr.read_int end
# File lib/ffi-geos/coordinate_sequence.rb, line 342 def remove_duplicate_coords Geos::CoordinateSequence.new(to_a.each_with_object([]) do |v, memo| memo << v unless memo.last == v end) end
# File lib/ffi-geos/coordinate_sequence.rb, line 405 def rotate(radians, origin = [0.0, 0.0]) dup.rotate!(radians, origin) end
# File lib/ffi-geos/coordinate_sequence.rb, line 378 def rotate!(radians, origin = [0.0, 0.0]) origin = case origin when Array origin when Geos::Geometry center = origin.centroid [center.x, center.y] else raise ArgumentError, 'Expected an Array or a Geos::Geometry for the origin' end affine!( afac: Math.cos(radians), bfac: -Math.sin(radians), cfac: 0, dfac: Math.sin(radians), efac: Math.cos(radians), ffac: 0, gfac: 0, hfac: 0, ifac: 1, xoff: origin[0] - (Math.cos(radians) * origin[0]) + (Math.sin(radians) * origin[1]), yoff: origin[1] - (Math.sin(radians) * origin[0]) - (Math.cos(radians) * origin[1]), zoff: 0 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 426 def rotate_x(radians) dup.rotate_x!(radians) end
# File lib/ffi-geos/coordinate_sequence.rb, line 409 def rotate_x!(radians) affine!( afac: 1, bfac: 0, cfac: 0, dfac: 0, efac: Math.cos(radians), ffac: -Math.sin(radians), gfac: 0, hfac: Math.sin(radians), ifac: Math.cos(radians), xoff: 0, yoff: 0, zoff: 0 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 447 def rotate_y(radians) dup.rotate_y!(radians) end
# File lib/ffi-geos/coordinate_sequence.rb, line 430 def rotate_y!(radians) affine!( afac: Math.cos(radians), bfac: 0, cfac: Math.sin(radians), dfac: 0, efac: 1, ffac: 0, gfac: -Math.sin(radians), hfac: 0, ifac: Math.cos(radians), xoff: 0, yoff: 0, zoff: 0 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 455 def rotate_z(radians) dup.rotate!(radians) end
# File lib/ffi-geos/coordinate_sequence.rb, line 451 def rotate_z!(radians) rotate!(radians) end
# File lib/ffi-geos/coordinate_sequence.rb, line 484 def scale(*args, **kwargs) dup.scale!(*args, **kwargs) end
# File lib/ffi-geos/coordinate_sequence.rb, line 459 def scale!(*args, **kwargs) x, y, z = if !kwargs.empty? kwargs.values_at(:x, :y, :z) elsif args.length.between?(1, 3) args.values_at(0...3) else raise ArgumentError, "Wrong number of arguments #{args.length} for 1-3" end affine!( afac: x || 1, bfac: 0, cfac: 0, dfac: 0, efac: y || 1, ffac: 0, gfac: 0, hfac: 0, ifac: z || 1, xoff: 0, yoff: 0, zoff: 0 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 180 def set_ordinate(idx, dim, val) check_bounds(idx) FFIGeos.GEOSCoordSeq_setOrdinate_r(Geos.current_handle_pointer, ptr, idx, dim, val.to_f) end
Sets the x value of a coordinate. Can also be set via x
[]=.
# File lib/ffi-geos/coordinate_sequence.rb, line 163 def set_x(idx, val) check_bounds(idx) FFIGeos.GEOSCoordSeq_setX_r(Geos.current_handle_pointer, ptr, idx, val.to_f) end
Sets the y value of a coordinate. Can also be set via y
[]=.
# File lib/ffi-geos/coordinate_sequence.rb, line 169 def set_y(idx, val) check_bounds(idx) FFIGeos.GEOSCoordSeq_setY_r(Geos.current_handle_pointer, ptr, idx, val.to_f) end
Sets the z value of a coordinate. Can also be set via z
[]=.
# File lib/ffi-geos/coordinate_sequence.rb, line 175 def set_z(idx, val) check_bounds(idx) FFIGeos.GEOSCoordSeq_setZ_r(Geos.current_handle_pointer, ptr, idx, val.to_f) end
# File lib/ffi-geos/coordinate_sequence.rb, line 338 def snap_to_grid(*args, **) dup.snap_to_grid!(*args) end
# File lib/ffi-geos/coordinate_sequence.rb, line 291 def snap_to_grid!(*args, **kwargs) grid = { offset_x: 0, # 1 offset_y: 0, # 2 offset_z: 0, # - size_x: 0, # 3 size_y: 0, # 4 size_z: 0 # - } if args.length == 1 && args[0].is_a?(Numeric) grid[:size_x] = grid[:size_y] = grid[:size_z] = args[0] elsif !kwargs.empty? grid.merge!(kwargs) end grid[:size_x] = grid[:size_y] = grid[:size_z] = grid[:size] if grid[:size] if grid[:offset] case grid[:offset] when Geos::Geometry point = grid[:offset].centroid grid[:offset_x] = point.x grid[:offset_y] = point.y grid[:offset_z] = point.z when Array grid[:offset_x], grid[:offset_y], grid[:offset_z] = grid[:offset] else raise ArgumentError, 'Expected :offset option to be a Geos::Point' end end length.times do |i| x[i] = (((x[i] - grid[:offset_x]) / grid[:size_x]).round * grid[:size_x]) + grid[:offset_x] if grid[:size_x] != 0 y[i] = (((y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y]) + grid[:offset_y] if grid[:size_y] != 0 z[i] = (((z[i] - grid[:offset_z]) / grid[:size_z]).round * grid[:size_z]) + grid[:offset_z] if has_z? && grid[:size_z] != 0 end cs = remove_duplicate_coords @ptr = cs.ptr self end
# File lib/ffi-geos/coordinate_sequence.rb, line 255 def to_line_string(options = {}) Geos.create_line_string(self, srid: options[:srid]) end
# File lib/ffi-geos/coordinate_sequence.rb, line 251 def to_linear_ring(options = {}) Geos.create_linear_ring(self, srid: options[:srid]) end
# File lib/ffi-geos/coordinate_sequence.rb, line 247 def to_point(options = {}) Geos.create_point(self, srid: options[:srid]) end
# File lib/ffi-geos/coordinate_sequence.rb, line 259 def to_polygon(options = {}) Geos.create_polygon(self, srid: options[:srid]) end
# File lib/ffi-geos/coordinate_sequence.rb, line 263 def to_s entries.collect { |entry| entry.join(' ') }.join(', ') end
# File lib/ffi-geos/coordinate_sequence.rb, line 518 def trans_scale(*args, **kwargs) dup.trans_scale!(*args, **kwargs) end
# File lib/ffi-geos/coordinate_sequence.rb, line 488 def trans_scale!(*args, **kwargs) delta_x, delta_y, x_factor, y_factor = if !kwargs.empty? kwargs.values_at(:delta_x, :delta_y, :x_factor, :y_factor) elsif args.length.between?(1, 4) args.values_at(0...4) else raise ArgumentError, "Wrong number of arguments #{args.length} for 1-4" end x_factor ||= 1 y_factor ||= 1 delta_x ||= 0 delta_y ||= 0 affine!( afac: x_factor, bfac: 0, cfac: 0, dfac: 0, efac: y_factor, ffac: 0, gfac: 0, hfac: 0, ifac: 1, xoff: delta_x * x_factor, yoff: delta_y * y_factor, zoff: 0 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 547 def translate(*args, **kwargs) dup.translate!(*args, **kwargs) end
# File lib/ffi-geos/coordinate_sequence.rb, line 522 def translate!(*args, **kwargs) x, y, z = if !kwargs.empty? kwargs.values_at(:x, :y, :z) elsif args.length.between?(1, 3) args.values_at(0...3) else raise ArgumentError, "Wrong number of arguments #{args.length} for 1-3" end affine!( afac: 1, bfac: 0, cfac: 0, dfac: 0, efac: 1, ffac: 0, gfac: 0, hfac: 0, ifac: 1, xoff: x || 0, yoff: y || 0, zoff: z || 1 ) end
# File lib/ffi-geos/coordinate_sequence.rb, line 157 def z? dimensions == 3 end