ffi-geos 2.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +49 -0
  3. data/.rubocop-minitest.yml +240 -0
  4. data/.rubocop.yml +497 -111
  5. data/.rubocop_todo.yml +100 -0
  6. data/Gemfile +3 -6
  7. data/MIT-LICENSE +1 -1
  8. data/README.rdoc +2 -0
  9. data/ffi-geos.gemspec +5 -0
  10. data/lib/ffi-geos/buffer_params.rb +1 -1
  11. data/lib/ffi-geos/coordinate_sequence.rb +32 -32
  12. data/lib/ffi-geos/geojson_reader.rb +35 -0
  13. data/lib/ffi-geos/geojson_writer.rb +49 -0
  14. data/lib/ffi-geos/geometry.rb +11 -5
  15. data/lib/ffi-geos/geometry_collection.rb +5 -5
  16. data/lib/ffi-geos/line_string.rb +11 -11
  17. data/lib/ffi-geos/multi_line_string.rb +1 -1
  18. data/lib/ffi-geos/point.rb +4 -4
  19. data/lib/ffi-geos/polygon.rb +5 -5
  20. data/lib/ffi-geos/prepared_geometry.rb +21 -1
  21. data/lib/ffi-geos/strtree.rb +1 -1
  22. data/lib/ffi-geos/version.rb +1 -1
  23. data/lib/ffi-geos/wkb_reader.rb +1 -1
  24. data/lib/ffi-geos/wkb_writer.rb +14 -2
  25. data/lib/ffi-geos/wkt_reader.rb +1 -1
  26. data/lib/ffi-geos/wkt_writer.rb +2 -2
  27. data/lib/ffi-geos.rb +92 -4
  28. data/sonar-project.properties +4 -4
  29. data/test/coordinate_sequence_tests.rb +6 -6
  30. data/test/geojson_reader_tests.rb +170 -0
  31. data/test/geojson_writer_tests.rb +103 -0
  32. data/test/geometry_collection_tests.rb +4 -4
  33. data/test/geometry_tests.rb +75 -32
  34. data/test/line_string_tests.rb +13 -5
  35. data/test/point_tests.rb +3 -3
  36. data/test/polygon_tests.rb +3 -3
  37. data/test/prepared_geometry_tests.rb +30 -0
  38. data/test/strtree_tests.rb +8 -8
  39. data/test/test_helper.rb +43 -12
  40. data/test/wkb_writer_tests.rb +20 -0
  41. metadata +15 -6
  42. data/.travis.yml +0 -32
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,100 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000`
3
+ # on 2022-06-13 13:21:07 UTC using RuboCop version 1.30.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Lint/BinaryOperatorWithIdenticalOperands:
11
+ Exclude:
12
+ - 'test/geometry_tests.rb'
13
+
14
+ # Offense count: 6
15
+ # Configuration parameters: IgnoredMethods, CountRepeatedAttributes, Max.
16
+ Metrics/AbcSize:
17
+ Exclude:
18
+ - 'lib/ffi-geos/coordinate_sequence.rb'
19
+ - 'lib/ffi-geos/line_string.rb'
20
+ - 'lib/ffi-geos/utils.rb'
21
+ - 'test/geometry_tests.rb'
22
+
23
+ # Offense count: 2
24
+ # Configuration parameters: CountComments, Max, CountAsOne.
25
+ Metrics/ClassLength:
26
+ Exclude:
27
+ - 'lib/ffi-geos/coordinate_sequence.rb'
28
+ - 'lib/ffi-geos/geometry.rb'
29
+
30
+ # Offense count: 3
31
+ # Configuration parameters: IgnoredMethods, Max.
32
+ Metrics/CyclomaticComplexity:
33
+ Exclude:
34
+ - 'lib/ffi-geos/coordinate_sequence.rb'
35
+ - 'lib/ffi-geos/tools.rb'
36
+
37
+ # Offense count: 1
38
+ # Configuration parameters: CountComments, Max, CountAsOne.
39
+ Metrics/ModuleLength:
40
+ Exclude:
41
+ - 'lib/ffi-geos.rb'
42
+
43
+ # Offense count: 1
44
+ # Configuration parameters: Max, CountKeywordArgs, MaxOptionalParameters.
45
+ Metrics/ParameterLists:
46
+ Exclude:
47
+ - 'lib/ffi-geos/utils.rb'
48
+
49
+ # Offense count: 4
50
+ # Configuration parameters: IgnoredMethods, Max.
51
+ Metrics/PerceivedComplexity:
52
+ Exclude:
53
+ - 'lib/ffi-geos/coordinate_sequence.rb'
54
+ - 'lib/ffi-geos/tools.rb'
55
+ - 'test/geometry_tests.rb'
56
+
57
+ # Offense count: 9
58
+ Naming/AccessorMethodName:
59
+ Exclude:
60
+ - 'lib/ffi-geos/geojson_writer.rb'
61
+ - 'lib/ffi-geos/point.rb'
62
+ - 'lib/ffi-geos/wkb_writer.rb'
63
+ - 'lib/ffi-geos/wkt_writer.rb'
64
+
65
+ # Offense count: 1
66
+ # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms.
67
+ # CheckDefinitionPathHierarchyRoots: lib, spec, test, src
68
+ # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
69
+ Naming/FileName:
70
+ Exclude:
71
+ - 'lib/ffi-geos.rb'
72
+
73
+ # Offense count: 2
74
+ # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros.
75
+ # NamePrefix: is_, has_, have_
76
+ # ForbiddenPrefixes: is_, has_, have_
77
+ # AllowedMethods: is_a?
78
+ # MethodDefinitionMacros: define_method, define_singleton_method
79
+ Naming/PredicateName:
80
+ Exclude:
81
+ - 'lib/ffi-geos/coordinate_sequence.rb'
82
+ - 'lib/ffi-geos/geometry.rb'
83
+
84
+ # Offense count: 2
85
+ # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
86
+ # SupportedStyles: snake_case, normalcase, non_integer
87
+ # AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339
88
+ Naming/VariableNumber:
89
+ Exclude:
90
+ - 'lib/ffi-geos.rb'
91
+ - 'lib/ffi-geos/geometry.rb'
92
+
93
+ # Offense count: 4
94
+ # Configuration parameters: AllowedMethods.
95
+ # AllowedMethods: respond_to_missing?
96
+ Style/OptionalBooleanParameter:
97
+ Exclude:
98
+ - 'lib/ffi-geos/geometry.rb'
99
+ - 'test/wkb_reader_tests.rb'
100
+ - 'test/wkb_writer_tests.rb'
data/Gemfile CHANGED
@@ -11,11 +11,8 @@ gem 'minitest-reporters'
11
11
  gem 'rake'
12
12
  gem 'rdoc'
13
13
  gem 'rubocop', require: false
14
- gem 'simplecov', '~> 0.17.0', require: false
15
-
16
- platforms :rbx do
17
- gem 'rubinius-developer_tools'
18
- gem 'rubysl', '~> 2.0'
19
- end
14
+ gem 'rubocop-minitest', require: false
15
+ gem 'simplecov', require: false
16
+ gem 'simplecov_json_formatter', require: false
20
17
 
21
18
  instance_eval File.read('Gemfile.local') if File.exist?('Gemfile.local')
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2021 J Smith <dark.panda@gmail.com>
1
+ Copyright (c) 2010-2022 J Smith <dark.panda@gmail.com>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.rdoc CHANGED
@@ -54,6 +54,8 @@ Ruby bindings along with the following enhancements and additions:
54
54
  GEOS library and perform other work or cancel GEOS calls outright. The
55
55
  interruption API was added in GEOS 3.4.0.
56
56
 
57
+ * Geos::GeoJSONReader and Geos::GeoJSONWriter support on GEOS 3.10+.
58
+
57
59
  == New Methods and Additions (not exhaustive)
58
60
 
59
61
  * SRIDs can be copied on many operations. GEOS doesn't usually copy SRIDs
data/ffi-geos.gemspec CHANGED
@@ -7,6 +7,8 @@ Gem::Specification.new do |s|
7
7
  s.version = Geos::VERSION
8
8
 
9
9
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
10
+ s.required_ruby_version = '>= 2.6'
11
+
10
12
  s.authors = ['J Smith']
11
13
  s.description = 'An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).'
12
14
  s.summary = s.description
@@ -22,4 +24,7 @@ Gem::Specification.new do |s|
22
24
  s.require_paths = ['lib']
23
25
 
24
26
  s.add_dependency('ffi', ['>= 1.0.0'])
27
+ s.metadata = {
28
+ 'rubygems_mfa_required' => 'true'
29
+ }
25
30
  end
@@ -36,7 +36,7 @@ module Geos
36
36
  end
37
37
  end
38
38
 
39
- def self.release(ptr) #:nodoc:
39
+ def self.release(ptr) # :nodoc:
40
40
  FFIGeos.GEOSBufferParams_destroy_r(Geos.current_handle_pointer, ptr)
41
41
  end
42
42
 
@@ -123,7 +123,7 @@ module Geos
123
123
  @z = CoordinateAccessor.new(self, 2)
124
124
  end
125
125
 
126
- def self.release(ptr) #:nodoc:
126
+ def self.release(ptr) # :nodoc:
127
127
  FFIGeos.GEOSCoordSeq_destroy_r(Geos.current_handle_pointer, ptr)
128
128
  end
129
129
 
@@ -287,7 +287,7 @@ module Geos
287
287
  RUBY
288
288
  end
289
289
 
290
- def snap_to_grid!(*args)
290
+ def snap_to_grid!(*args, **kwargs)
291
291
  grid = {
292
292
  offset_x: 0, # 1
293
293
  offset_y: 0, # 2
@@ -299,8 +299,8 @@ module Geos
299
299
 
300
300
  if args.length == 1 && args[0].is_a?(Numeric)
301
301
  grid[:size_x] = grid[:size_y] = grid[:size_z] = args[0]
302
- elsif args[0].is_a?(Hash)
303
- grid.merge!(args[0])
302
+ elsif !kwargs.empty?
303
+ grid.merge!(kwargs)
304
304
  end
305
305
 
306
306
  grid[:size_x] = grid[:size_y] = grid[:size_z] = grid[:size] if grid[:size]
@@ -321,11 +321,11 @@ module Geos
321
321
  end
322
322
 
323
323
  length.times do |i|
324
- x[i] = ((x[i] - grid[:offset_x]) / grid[:size_x]).round * grid[:size_x] + grid[:offset_x] if grid[:size_x] != 0
324
+ x[i] = (((x[i] - grid[:offset_x]) / grid[:size_x]).round * grid[:size_x]) + grid[:offset_x] if grid[:size_x] != 0
325
325
 
326
- y[i] = ((y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y] + grid[:offset_y] if grid[:size_y] != 0
326
+ y[i] = (((y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y]) + grid[:offset_y] if grid[:size_y] != 0
327
327
 
328
- z[i] = ((z[i] - grid[:offset_z]) / grid[:size_z]).round * grid[:size_z] + grid[:offset_z] if has_z? && grid[:size_z] != 0
328
+ z[i] = (((z[i] - grid[:offset_z]) / grid[:size_z]).round * grid[:size_z]) + grid[:offset_z] if has_z? && grid[:size_z] != 0
329
329
  end
330
330
 
331
331
  cs = remove_duplicate_coords
@@ -334,7 +334,7 @@ module Geos
334
334
  self
335
335
  end
336
336
 
337
- def snap_to_grid(*args)
337
+ def snap_to_grid(*args, **)
338
338
  dup.snap_to_grid!(*args)
339
339
  end
340
340
 
@@ -353,17 +353,17 @@ module Geos
353
353
  y = self.y[i]
354
354
  z = self.z[i]
355
355
 
356
- self.x[i] = options[:afac] * x + options[:bfac] * y + options[:cfac] * z + options[:xoff]
357
- self.y[i] = options[:dfac] * x + options[:efac] * y + options[:ffac] * z + options[:yoff]
358
- self.z[i] = options[:gfac] * x + options[:hfac] * y + options[:ifac] * z + options[:zoff]
356
+ self.x[i] = (options[:afac] * x) + (options[:bfac] * y) + (options[:cfac] * z) + options[:xoff]
357
+ self.y[i] = (options[:dfac] * x) + (options[:efac] * y) + (options[:ffac] * z) + options[:yoff]
358
+ self.z[i] = (options[:gfac] * x) + (options[:hfac] * y) + (options[:ifac] * z) + options[:zoff]
359
359
  end
360
360
  else
361
361
  length.times do |i|
362
362
  x = self.x[i]
363
363
  y = self.y[i]
364
364
 
365
- self.x[i] = options[:afac] * x + options[:bfac] * y + options[:xoff]
366
- self.y[i] = options[:dfac] * x + options[:efac] * y + options[:yoff]
365
+ self.x[i] = (options[:afac] * x) + (options[:bfac] * y) + options[:xoff]
366
+ self.y[i] = (options[:dfac] * x) + (options[:efac] * y) + options[:yoff]
367
367
  end
368
368
  end
369
369
 
@@ -395,8 +395,8 @@ module Geos
395
395
  gfac: 0,
396
396
  hfac: 0,
397
397
  ifac: 1,
398
- xoff: origin[0] - Math.cos(radians) * origin[0] + Math.sin(radians) * origin[1],
399
- yoff: origin[1] - Math.sin(radians) * origin[0] - Math.cos(radians) * origin[1],
398
+ xoff: origin[0] - (Math.cos(radians) * origin[0]) + (Math.sin(radians) * origin[1]),
399
+ yoff: origin[1] - (Math.sin(radians) * origin[0]) - (Math.cos(radians) * origin[1]),
400
400
  zoff: 0
401
401
  )
402
402
  end
@@ -455,9 +455,9 @@ module Geos
455
455
  dup.rotate!(radians)
456
456
  end
457
457
 
458
- def scale!(*args)
459
- x, y, z = if args.length == 1 && args[0].is_a?(Hash)
460
- args[0].values_at(:x, :y, :z)
458
+ def scale!(*args, **kwargs)
459
+ x, y, z = if !kwargs.empty?
460
+ kwargs.values_at(:x, :y, :z)
461
461
  elsif args.length.between?(1, 3)
462
462
  args.values_at(0...3)
463
463
  else
@@ -480,13 +480,13 @@ module Geos
480
480
  )
481
481
  end
482
482
 
483
- def scale(*args)
484
- dup.scale!(*args)
483
+ def scale(*args, **kwargs)
484
+ dup.scale!(*args, **kwargs)
485
485
  end
486
486
 
487
- def trans_scale!(*args)
488
- delta_x, delta_y, x_factor, y_factor = if args.length == 1 && args[0].is_a?(Hash)
489
- args[0].values_at(:delta_x, :delta_y, :x_factor, :y_factor)
487
+ def trans_scale!(*args, **kwargs)
488
+ delta_x, delta_y, x_factor, y_factor = if !kwargs.empty?
489
+ kwargs.values_at(:delta_x, :delta_y, :x_factor, :y_factor)
490
490
  elsif args.length.between?(1, 4)
491
491
  args.values_at(0...4)
492
492
  else
@@ -514,13 +514,13 @@ module Geos
514
514
  )
515
515
  end
516
516
 
517
- def trans_scale(*args)
518
- dup.trans_scale!(*args)
517
+ def trans_scale(*args, **kwargs)
518
+ dup.trans_scale!(*args, **kwargs)
519
519
  end
520
520
 
521
- def translate!(*args)
522
- x, y, z = if args.length == 1 && args[0].is_a?(Hash)
523
- args[0].values_at(:x, :y, :z)
521
+ def translate!(*args, **kwargs)
522
+ x, y, z = if !kwargs.empty?
523
+ kwargs.values_at(:x, :y, :z)
524
524
  elsif args.length.between?(1, 3)
525
525
  args.values_at(0...3)
526
526
  else
@@ -543,17 +543,17 @@ module Geos
543
543
  )
544
544
  end
545
545
 
546
- def translate(*args)
547
- dup.translate!(*args)
546
+ def translate(*args, **kwargs)
547
+ dup.translate!(*args, **kwargs)
548
548
  end
549
549
 
550
550
  protected
551
551
 
552
- def check_bounds(idx) #:nodoc:
552
+ def check_bounds(idx) # :nodoc:
553
553
  raise Geos::IndexBoundsError, 'Index out of bounds' if idx.negative? || idx >= length
554
554
  end
555
555
 
556
- def build_coordinate(n) #:nodoc:
556
+ def build_coordinate(n) # :nodoc:
557
557
  [
558
558
  get_x(n),
559
559
  (dimensions >= 2 ? get_y(n) : nil),
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geos
4
+ class GeoJSONReader
5
+ include Geos::Tools
6
+
7
+ attr_reader :ptr
8
+
9
+ class ParseError < Geos::ParseError
10
+ end
11
+
12
+ def initialize(*args)
13
+ ptr = if args.first.is_a?(FFI::Pointer)
14
+ args.first
15
+ else
16
+ FFIGeos.GEOSGeoJSONReader_create_r(Geos.current_handle_pointer, *args)
17
+ end
18
+
19
+ @ptr = FFI::AutoPointer.new(
20
+ ptr,
21
+ self.class.method(:release)
22
+ )
23
+ end
24
+
25
+ def read(json, options = {})
26
+ cast_geometry_ptr(FFIGeos.GEOSGeoJSONReader_readGeometry_r(Geos.current_handle_pointer, ptr, json), srid: options[:srid])
27
+ rescue Geos::GEOSException => e
28
+ raise ParseError, e
29
+ end
30
+
31
+ def self.release(ptr) # :nodoc:
32
+ FFIGeos.GEOSGeoJSONReader_destroy_r(Geos.current_handle_pointer, ptr)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geos
4
+ class GeoJSONWriter
5
+ attr_accessor :indentation
6
+ attr_reader :ptr
7
+
8
+ def initialize(options = {})
9
+ options = {
10
+ indentation: -1
11
+ }.merge(options)
12
+
13
+ ptr = FFIGeos.GEOSGeoJSONWriter_create_r(Geos.current_handle_pointer)
14
+ @ptr = FFI::AutoPointer.new(
15
+ ptr,
16
+ self.class.method(:release)
17
+ )
18
+
19
+ set_options(options)
20
+ end
21
+
22
+ def self.release(ptr) # :nodoc:
23
+ FFIGeos.GEOSGeoJSONWriter_destroy_r(Geos.current_handle_pointer, ptr)
24
+ end
25
+
26
+ def set_options(options) # :nodoc:
27
+ [:indentation].each do |k|
28
+ send("#{k}=", options[k]) if respond_to?("#{k}=") && options.key?(k)
29
+ end
30
+ end
31
+ private :set_options
32
+
33
+ # Options can be set temporarily for individual writes using an options
34
+ # Hash. Options include :indentation.
35
+ def write(geom, options = nil)
36
+ unless options.nil?
37
+ old_options = {
38
+ indentation: indentation
39
+ }
40
+
41
+ set_options(options)
42
+ end
43
+
44
+ FFIGeos.GEOSGeoJSONWriter_writeGeometry_r(Geos.current_handle_pointer, ptr, geom.ptr, indentation)
45
+ ensure
46
+ set_options(old_options) unless options.nil?
47
+ end
48
+ end
49
+ end
@@ -38,7 +38,7 @@ module Geos
38
38
  self.srid = source.srid
39
39
  end
40
40
 
41
- def self.release(ptr) #:nodoc:
41
+ def self.release(ptr) # :nodoc:
42
42
  FFIGeos.GEOSGeom_destroy_r(Geos.current_handle_pointer, ptr)
43
43
  end
44
44
 
@@ -330,7 +330,7 @@ module Geos
330
330
  bool_result(FFIGeos.GEOSCovers_r(Geos.current_handle_pointer, ptr, geom.ptr))
331
331
  end
332
332
  else
333
- def covers?(geom) #:nodoc:
333
+ def covers?(geom) # :nodoc:
334
334
  check_geometry(geom)
335
335
  !!%w{
336
336
  T*****FF*
@@ -352,7 +352,7 @@ module Geos
352
352
  bool_result(FFIGeos.GEOSCoveredBy_r(Geos.current_handle_pointer, ptr, geom.ptr))
353
353
  end
354
354
  else
355
- def covered_by?(geom) #:nodoc:
355
+ def covered_by?(geom) # :nodoc:
356
356
  check_geometry(geom)
357
357
  !!%w{
358
358
  T*F**F***
@@ -386,7 +386,7 @@ module Geos
386
386
 
387
387
  def eql_almost?(other, decimal = 6)
388
388
  check_geometry(other)
389
- bool_result(FFIGeos.GEOSEqualsExact_r(Geos.current_handle_pointer, ptr, other.ptr, 0.5 * 10 ** -decimal))
389
+ bool_result(FFIGeos.GEOSEqualsExact_r(Geos.current_handle_pointer, ptr, other.ptr, 0.5 * (10 ** -decimal)))
390
390
  end
391
391
  alias equals_almost? eql_almost?
392
392
  alias almost_equals? eql_almost?
@@ -441,7 +441,7 @@ module Geos
441
441
 
442
442
  # GEOS versions prior to 3.3.0 didn't handle exceptions and can crash on
443
443
  # bad input.
444
- if FFIGeos.respond_to?(:GEOSProject_r) && Geos::GEOS_VERSION >= '3.3.0'
444
+ if FFIGeos.respond_to?(:GEOSProject_r) && Geos::GEOS_NICE_VERSION >= '030300'
445
445
  def project(geom, normalized = false)
446
446
  raise TypeError, 'Expected Geos::Point type' unless geom.is_a?(Geos::Point)
447
447
 
@@ -637,6 +637,12 @@ module Geos
637
637
  end
638
638
  end
639
639
 
640
+ if FFIGeos.respond_to?(:GEOSConstrainedDelaunayTriangulation_r)
641
+ def constrained_delaunay_triangulation
642
+ cast_geometry_ptr(FFIGeos.GEOSConstrainedDelaunayTriangulation_r(Geos.current_handle_pointer, ptr))
643
+ end
644
+ end
645
+
640
646
  if FFIGeos.respond_to?(:GEOSVoronoiDiagram_r)
641
647
  # Available in GEOS 3.5.0+
642
648
  #
@@ -46,7 +46,7 @@ module Geos
46
46
 
47
47
  %w{ x y z }.each do |dimension|
48
48
  %w{ max min }.each do |op|
49
- native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
49
+ native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..]}_r"
50
50
 
51
51
  if FFIGeos.respond_to?(native_method)
52
52
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
@@ -82,18 +82,18 @@ module Geos
82
82
  translate
83
83
  }.each do |m|
84
84
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
85
- def #{m}!(*args)
85
+ def #{m}!(*args, **kwargs)
86
86
  unless self.empty?
87
87
  self.num_geometries.times do |i|
88
- self[i].#{m}!(*args)
88
+ self[i].#{m}!(*args, **kwargs)
89
89
  end
90
90
  end
91
91
 
92
92
  self
93
93
  end
94
94
 
95
- def #{m}(*args)
96
- ret = self.dup.#{m}!(*args)
95
+ def #{m}(*args, **kwargs)
96
+ ret = self.dup.#{m}!(*args, **kwargs)
97
97
  ret.srid = pick_srid_according_to_policy(self.srid)
98
98
  ret
99
99
  end
@@ -42,7 +42,7 @@ module Geos
42
42
  end
43
43
  alias slice []
44
44
 
45
- def offset_curve(width, options = {})
45
+ def offset_curve(width, **options)
46
46
  options = Constants::BUFFER_PARAM_DEFAULTS.merge(options)
47
47
 
48
48
  cast_geometry_ptr(
@@ -81,7 +81,7 @@ module Geos
81
81
  cur_path.concat(to_a)
82
82
  end
83
83
 
84
- def snap_to_grid!(*args)
84
+ def snap_to_grid!(*args, **)
85
85
  unless empty?
86
86
  cs = coord_seq.snap_to_grid!(*args)
87
87
 
@@ -97,7 +97,7 @@ module Geos
97
97
  self
98
98
  end
99
99
 
100
- def snap_to_grid(*args)
100
+ def snap_to_grid(*args, **)
101
101
  ret = dup.snap_to_grid!(*args)
102
102
  ret.srid = pick_srid_according_to_policy(srid)
103
103
  ret
@@ -126,9 +126,9 @@ module Geos
126
126
  dseg = (fraction - total_length) / seg_length
127
127
 
128
128
  args = []
129
- args << p_1.x + ((p_2.x - p_1.x) * dseg)
130
- args << p_1.y + ((p_2.y - p_1.y) * dseg)
131
- args << p_1.z + ((p_2.z - p_1.z) * dseg) if has_z?
129
+ args << (p_1.x + ((p_2.x - p_1.x) * dseg))
130
+ args << (p_1.y + ((p_2.y - p_1.y) * dseg))
131
+ args << (p_1.z + ((p_2.z - p_1.z) * dseg)) if has_z?
132
132
 
133
133
  args << { srid: pick_srid_according_to_policy(srid) } unless srid.zero?
134
134
 
@@ -146,7 +146,7 @@ module Geos
146
146
 
147
147
  %w{ max min }.each do |op|
148
148
  %w{ x y }.each do |dimension|
149
- native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
149
+ native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..]}_r"
150
150
 
151
151
  if FFIGeos.respond_to?(native_method)
152
152
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
@@ -193,16 +193,16 @@ module Geos
193
193
  translate
194
194
  }.each do |m|
195
195
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
196
- def #{m}!(*args)
196
+ def #{m}!(*args, **kwargs)
197
197
  unless self.empty?
198
- self.coord_seq.#{m}!(*args)
198
+ self.coord_seq.#{m}!(*args, **kwargs)
199
199
  end
200
200
 
201
201
  self
202
202
  end
203
203
 
204
- def #{m}(*args)
205
- ret = self.dup.#{m}!(*args)
204
+ def #{m}(*args, **kwargs)
205
+ ret = self.dup.#{m}!(*args, **kwargs)
206
206
  ret.srid = pick_srid_according_to_policy(self.srid)
207
207
  ret
208
208
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Geos
4
4
  class MultiLineString < GeometryCollection
5
- if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::GEOS_VERSION >= '3.5.0'
5
+ if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::GEOS_NICE_VERSION >= '030500'
6
6
  # Available in GEOS 3.5.0+.
7
7
  def closed?
8
8
  bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
@@ -118,16 +118,16 @@ module Geos
118
118
  translate
119
119
  }.each do |m|
120
120
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
121
- def #{m}!(*args)
121
+ def #{m}!(*args, **kwargs)
122
122
  unless empty?
123
- coord_seq.#{m}!(*args)
123
+ coord_seq.#{m}!(*args, **kwargs)
124
124
  end
125
125
 
126
126
  self
127
127
  end
128
128
 
129
- def #{m}(*args)
130
- ret = dup.#{m}!(*args)
129
+ def #{m}(*args, **kwargs)
130
+ ret = dup.#{m}!(*args, **kwargs)
131
131
  ret.srid = pick_srid_according_to_policy(srid)
132
132
  ret
133
133
  end
@@ -78,7 +78,7 @@ module Geos
78
78
 
79
79
  %w{ max min }.each do |op|
80
80
  %w{ x y }.each do |dimension|
81
- native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
81
+ native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..]}_r"
82
82
 
83
83
  if FFIGeos.respond_to?(native_method)
84
84
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
@@ -125,16 +125,16 @@ module Geos
125
125
  translate
126
126
  }.each do |m|
127
127
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
128
- def #{m}!(*args)
129
- exterior_ring.coord_seq.#{m}!(*args)
128
+ def #{m}!(*args, **kwargs)
129
+ exterior_ring.coord_seq.#{m}!(*args, **kwargs)
130
130
  interior_rings.each do |ring|
131
131
  ring.coord_seq.#{m}!(*args)
132
132
  end
133
133
  self
134
134
  end
135
135
 
136
- def #{m}(*args)
137
- ret = dup.#{m}!(*args)
136
+ def #{m}(*args, **kwargs)
137
+ ret = dup.#{m}!(*args, **kwargs)
138
138
  ret.srid = pick_srid_according_to_policy(srid)
139
139
  ret
140
140
  end
@@ -24,7 +24,7 @@ module Geos
24
24
  @ptr.autorelease = !!options[:auto_free]
25
25
  end
26
26
 
27
- def self.release(ptr) #:nodoc:
27
+ def self.release(ptr) # :nodoc:
28
28
  FFIGeos.GEOSPreparedGeom_destroy_r(Geos.current_handle_pointer, ptr)
29
29
  end
30
30
 
@@ -77,5 +77,25 @@ module Geos
77
77
  check_geometry(geom)
78
78
  bool_result(FFIGeos.GEOSPreparedWithin_r(Geos.current_handle_pointer, ptr, geom.ptr))
79
79
  end
80
+
81
+ def distance(geom)
82
+ check_geometry(geom)
83
+ double_ptr = FFI::MemoryPointer.new(:double)
84
+ FFIGeos.GEOSPreparedDistance_r(Geos.current_handle_pointer, ptr, geom.ptr, double_ptr)
85
+ double_ptr.read_double
86
+ end
87
+
88
+ def distance_within?(geom, distance)
89
+ check_geometry(geom)
90
+ bool_result(FFIGeos.GEOSPreparedDistanceWithin_r(Geos.current_handle_pointer, ptr, geom.ptr, distance))
91
+ end
92
+
93
+ def nearest_points(geom)
94
+ check_geometry(geom)
95
+
96
+ coord_seq_ptr = FFIGeos.GEOSPreparedNearestPoints_r(Geos.current_handle_pointer, ptr, geom.ptr)
97
+
98
+ Geos::CoordinateSequence.new(coord_seq_ptr)
99
+ end
80
100
  end
81
101
  end
@@ -60,7 +60,7 @@ module Geos
60
60
  end
61
61
  end
62
62
 
63
- def self.release(ptr) #:nodoc:
63
+ def self.release(ptr) # :nodoc:
64
64
  FFIGeos.GEOSSTRtree_destroy_r(Geos.current_handle_pointer, ptr)
65
65
  end
66
66
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Geos
4
- VERSION = '2.2.0'
4
+ VERSION = '2.4.0'
5
5
  end