ffi-geos 1.2.2 → 2.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +49 -0
- data/.rubocop.yml +5117 -4
- data/FUNDING.yml +2 -0
- data/Gemfile +9 -16
- data/Guardfile +3 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -20
- data/Rakefile +3 -2
- data/ffi-geos.gemspec +7 -2
- data/lib/ffi-geos/buffer_params.rb +1 -1
- data/lib/ffi-geos/coordinate_sequence.rb +179 -177
- data/lib/ffi-geos/geometry.rb +118 -31
- data/lib/ffi-geos/geometry_collection.rb +26 -12
- data/lib/ffi-geos/interrupt.rb +11 -14
- data/lib/ffi-geos/line_string.rb +64 -49
- data/lib/ffi-geos/multi_line_string.rb +1 -1
- data/lib/ffi-geos/point.rb +18 -18
- data/lib/ffi-geos/polygon.rb +44 -30
- data/lib/ffi-geos/prepared_geometry.rb +1 -1
- data/lib/ffi-geos/strtree.rb +28 -30
- data/lib/ffi-geos/tools.rb +1 -1
- data/lib/ffi-geos/utils.rb +16 -23
- data/lib/ffi-geos/version.rb +1 -1
- data/lib/ffi-geos/wkb_reader.rb +1 -1
- data/lib/ffi-geos/wkb_writer.rb +4 -5
- data/lib/ffi-geos/wkt_reader.rb +1 -1
- data/lib/ffi-geos/wkt_writer.rb +7 -13
- data/lib/ffi-geos.rb +134 -48
- data/sonar-project.properties +16 -0
- data/test/coordinate_sequence_tests.rb +148 -126
- data/test/geometry_collection_tests.rb +41 -67
- data/test/geometry_tests.rb +341 -40
- data/test/interrupt_tests.rb +7 -7
- data/test/line_string_tests.rb +23 -15
- data/test/point_tests.rb +5 -5
- data/test/polygon_tests.rb +6 -7
- data/test/prepared_geometry_tests.rb +8 -8
- data/test/strtree_tests.rb +13 -12
- data/test/test_helper.rb +74 -56
- data/test/utils_tests.rb +69 -59
- data/test/wkb_reader_tests.rb +9 -9
- data/test/wkb_writer_tests.rb +14 -12
- data/test/wkt_reader_tests.rb +0 -1
- data/test/wkt_writer_tests.rb +2 -5
- metadata +12 -10
- data/.travis.yml +0 -21
@@ -69,28 +69,26 @@ module Geos
|
|
69
69
|
lengths = points.collect(&:length).uniq
|
70
70
|
|
71
71
|
if lengths.empty?
|
72
|
-
[
|
72
|
+
[0, 0]
|
73
73
|
elsif lengths.length != 1
|
74
74
|
raise ParseError, 'Different sized points found in Array'
|
75
75
|
elsif !lengths.first.between?(1, 3)
|
76
76
|
raise ParseError, 'Expected points to contain 1-3 elements'
|
77
77
|
else
|
78
|
-
[
|
78
|
+
[points.length, points.first.length]
|
79
79
|
end
|
80
80
|
elsif args.first.is_a?(Hash)
|
81
81
|
args.first.values_at(:size, :dimensions)
|
82
|
+
elsif !args.length.between?(0, 2)
|
83
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 0-2)"
|
82
84
|
else
|
83
|
-
|
84
|
-
raise ArgumentError, "wrong number of arguments (#{args.length} for 0-2)"
|
85
|
-
else
|
86
|
-
[ args[0], args[1] ]
|
87
|
-
end
|
85
|
+
[args[0], args[1]]
|
88
86
|
end
|
89
87
|
|
90
88
|
size ||= 0
|
91
89
|
dimensions ||= 0
|
92
90
|
|
93
|
-
[
|
91
|
+
[FFIGeos.GEOSCoordSeq_create_r(Geos.current_handle_pointer, size, dimensions), true]
|
94
92
|
end
|
95
93
|
|
96
94
|
@ptr = FFI::AutoPointer.new(
|
@@ -125,7 +123,7 @@ module Geos
|
|
125
123
|
@z = CoordinateAccessor.new(self, 2)
|
126
124
|
end
|
127
125
|
|
128
|
-
def self.release(ptr)
|
126
|
+
def self.release(ptr) # :nodoc:
|
129
127
|
FFIGeos.GEOSCoordSeq_destroy_r(Geos.current_handle_pointer, ptr)
|
130
128
|
end
|
131
129
|
|
@@ -147,7 +145,7 @@ module Geos
|
|
147
145
|
def [](*args)
|
148
146
|
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
149
147
|
i = args.first
|
150
|
-
ary = [
|
148
|
+
ary = [get_x(i), get_y(i)]
|
151
149
|
ary << get_z(i) if has_z?
|
152
150
|
ary
|
153
151
|
else
|
@@ -235,6 +233,16 @@ module Geos
|
|
235
233
|
end
|
236
234
|
end
|
237
235
|
|
236
|
+
if FFIGeos.respond_to?(:GEOSCoordSeq_isCCW_r)
|
237
|
+
# Available in GEOS 3.7+.
|
238
|
+
def counter_clockwise?
|
239
|
+
char_ptr = FFI::MemoryPointer.new(:char)
|
240
|
+
FFIGeos.GEOSCoordSeq_isCCW_r(Geos.current_handle_pointer, ptr, char_ptr)
|
241
|
+
Tools.bool_result(char_ptr.read_char)
|
242
|
+
end
|
243
|
+
alias ccw? counter_clockwise?
|
244
|
+
end
|
245
|
+
|
238
246
|
def to_point(options = {})
|
239
247
|
Geos.create_point(self, srid: options[:srid])
|
240
248
|
end
|
@@ -258,11 +266,11 @@ module Geos
|
|
258
266
|
end
|
259
267
|
|
260
268
|
%w{ x y z }.each do |m|
|
261
|
-
class_eval(<<-
|
269
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
262
270
|
def #{m}_max
|
263
271
|
ret = nil
|
264
|
-
|
265
|
-
value =
|
272
|
+
length.times do |i|
|
273
|
+
value = get_#{m}(i)
|
266
274
|
ret = value if !ret || value >= ret
|
267
275
|
end
|
268
276
|
ret
|
@@ -270,34 +278,32 @@ module Geos
|
|
270
278
|
|
271
279
|
def #{m}_min
|
272
280
|
ret = nil
|
273
|
-
|
274
|
-
value =
|
281
|
+
length.times do |i|
|
282
|
+
value = get_#{m}(i)
|
275
283
|
ret = value if !ret || value <= ret
|
276
284
|
end
|
277
285
|
ret
|
278
286
|
end
|
279
|
-
|
287
|
+
RUBY
|
280
288
|
end
|
281
289
|
|
282
|
-
def snap_to_grid!(*args)
|
290
|
+
def snap_to_grid!(*args, **kwargs)
|
283
291
|
grid = {
|
284
|
-
:
|
285
|
-
:
|
286
|
-
:
|
287
|
-
:
|
288
|
-
:
|
289
|
-
:
|
292
|
+
offset_x: 0, # 1
|
293
|
+
offset_y: 0, # 2
|
294
|
+
offset_z: 0, # -
|
295
|
+
size_x: 0, # 3
|
296
|
+
size_y: 0, # 4
|
297
|
+
size_z: 0 # -
|
290
298
|
}
|
291
299
|
|
292
300
|
if args.length == 1 && args[0].is_a?(Numeric)
|
293
301
|
grid[:size_x] = grid[:size_y] = grid[:size_z] = args[0]
|
294
|
-
elsif
|
295
|
-
grid.merge!(
|
302
|
+
elsif !kwargs.empty?
|
303
|
+
grid.merge!(kwargs)
|
296
304
|
end
|
297
305
|
|
298
|
-
if grid[:size]
|
299
|
-
grid[:size_x] = grid[:size_y] = grid[:size_z] = grid[:size]
|
300
|
-
end
|
306
|
+
grid[:size_x] = grid[:size_y] = grid[:size_z] = grid[:size] if grid[:size]
|
301
307
|
|
302
308
|
if grid[:offset]
|
303
309
|
case grid[:offset]
|
@@ -310,58 +316,54 @@ module Geos
|
|
310
316
|
when Array
|
311
317
|
grid[:offset_x], grid[:offset_y], grid[:offset_z] = grid[:offset]
|
312
318
|
else
|
313
|
-
raise ArgumentError
|
319
|
+
raise ArgumentError, 'Expected :offset option to be a Geos::Point'
|
314
320
|
end
|
315
321
|
end
|
316
322
|
|
317
|
-
|
318
|
-
if grid[:size_x] != 0
|
319
|
-
self.x[i] = ((self.x[i] - grid[:offset_x]) / grid[:size_x]).round * grid[:size_x] + grid[:offset_x]
|
320
|
-
end
|
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
|
321
325
|
|
322
|
-
if grid[:size_y] != 0
|
323
|
-
self.y[i] = ((self.y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y] + grid[:offset_y]
|
324
|
-
end
|
326
|
+
y[i] = (((y[i] - grid[:offset_y]) / grid[:size_y]).round * grid[:size_y]) + grid[:offset_y] if grid[:size_y] != 0
|
325
327
|
|
326
|
-
if
|
327
|
-
self.z[i] = ((self.z[i] - grid[:offset_z]) / grid[:size_z]).round * grid[:size_z] + grid[:offset_z]
|
328
|
-
end
|
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
|
-
cs =
|
331
|
+
cs = remove_duplicate_coords
|
332
332
|
@ptr = cs.ptr
|
333
333
|
|
334
334
|
self
|
335
335
|
end
|
336
336
|
|
337
|
-
def snap_to_grid(*args)
|
338
|
-
|
337
|
+
def snap_to_grid(*args, **)
|
338
|
+
dup.snap_to_grid!(*args)
|
339
339
|
end
|
340
340
|
|
341
341
|
def remove_duplicate_coords
|
342
|
-
Geos::CoordinateSequence.new(
|
342
|
+
Geos::CoordinateSequence.new(to_a.each_with_object([]) do |v, memo|
|
343
343
|
memo << v unless memo.last == v
|
344
|
-
|
345
|
-
})
|
344
|
+
end)
|
346
345
|
end
|
347
346
|
|
348
347
|
def affine!(options)
|
349
348
|
options.default = 0.0
|
350
349
|
|
351
|
-
if
|
352
|
-
|
353
|
-
x
|
350
|
+
if has_z?
|
351
|
+
length.times do |i|
|
352
|
+
x = self.x[i]
|
353
|
+
y = self.y[i]
|
354
|
+
z = self.z[i]
|
354
355
|
|
355
|
-
self.x[i] = options[:afac] * x + options[:bfac] * y + options[:cfac] * z + options[:xoff]
|
356
|
-
self.y[i] = options[:dfac] * x + options[:efac] * y + options[:ffac] * z + options[:yoff]
|
357
|
-
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]
|
358
359
|
end
|
359
360
|
else
|
360
|
-
|
361
|
-
x
|
361
|
+
length.times do |i|
|
362
|
+
x = self.x[i]
|
363
|
+
y = self.y[i]
|
362
364
|
|
363
|
-
self.x[i] = options[:afac] * x + options[:bfac] * y + options[:xoff]
|
364
|
-
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]
|
365
367
|
end
|
366
368
|
end
|
367
369
|
|
@@ -369,126 +371,126 @@ module Geos
|
|
369
371
|
end
|
370
372
|
|
371
373
|
def affine(options)
|
372
|
-
|
374
|
+
dup.affine!(options)
|
373
375
|
end
|
374
376
|
|
375
|
-
def rotate!(radians, origin = [
|
377
|
+
def rotate!(radians, origin = [0.0, 0.0])
|
376
378
|
origin = case origin
|
377
379
|
when Array
|
378
380
|
origin
|
379
381
|
when Geos::Geometry
|
380
382
|
center = origin.centroid
|
381
|
-
[
|
383
|
+
[center.x, center.y]
|
382
384
|
else
|
383
|
-
raise ArgumentError
|
385
|
+
raise ArgumentError, 'Expected an Array or a Geos::Geometry for the origin'
|
384
386
|
end
|
385
387
|
|
386
|
-
|
387
|
-
:
|
388
|
-
:
|
389
|
-
:
|
390
|
-
:
|
391
|
-
:
|
392
|
-
:
|
393
|
-
:
|
394
|
-
:
|
395
|
-
:
|
396
|
-
:
|
397
|
-
:
|
398
|
-
:
|
399
|
-
|
388
|
+
affine!(
|
389
|
+
afac: Math.cos(radians),
|
390
|
+
bfac: -Math.sin(radians),
|
391
|
+
cfac: 0,
|
392
|
+
dfac: Math.sin(radians),
|
393
|
+
efac: Math.cos(radians),
|
394
|
+
ffac: 0,
|
395
|
+
gfac: 0,
|
396
|
+
hfac: 0,
|
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]),
|
400
|
+
zoff: 0
|
401
|
+
)
|
400
402
|
end
|
401
403
|
|
402
|
-
def rotate(radians, origin = [
|
403
|
-
|
404
|
+
def rotate(radians, origin = [0.0, 0.0])
|
405
|
+
dup.rotate!(radians, origin)
|
404
406
|
end
|
405
407
|
|
406
408
|
def rotate_x!(radians)
|
407
|
-
|
408
|
-
:
|
409
|
-
:
|
410
|
-
:
|
411
|
-
:
|
412
|
-
:
|
413
|
-
:
|
414
|
-
:
|
415
|
-
:
|
416
|
-
:
|
417
|
-
:
|
418
|
-
:
|
419
|
-
:
|
420
|
-
|
409
|
+
affine!(
|
410
|
+
afac: 1,
|
411
|
+
bfac: 0,
|
412
|
+
cfac: 0,
|
413
|
+
dfac: 0,
|
414
|
+
efac: Math.cos(radians),
|
415
|
+
ffac: -Math.sin(radians),
|
416
|
+
gfac: 0,
|
417
|
+
hfac: Math.sin(radians),
|
418
|
+
ifac: Math.cos(radians),
|
419
|
+
xoff: 0,
|
420
|
+
yoff: 0,
|
421
|
+
zoff: 0
|
422
|
+
)
|
421
423
|
end
|
422
424
|
|
423
425
|
def rotate_x(radians)
|
424
|
-
|
426
|
+
dup.rotate_x!(radians)
|
425
427
|
end
|
426
428
|
|
427
429
|
def rotate_y!(radians)
|
428
|
-
|
429
|
-
:
|
430
|
-
:
|
431
|
-
:
|
432
|
-
:
|
433
|
-
:
|
434
|
-
:
|
435
|
-
:
|
436
|
-
:
|
437
|
-
:
|
438
|
-
:
|
439
|
-
:
|
440
|
-
:
|
441
|
-
|
430
|
+
affine!(
|
431
|
+
afac: Math.cos(radians),
|
432
|
+
bfac: 0,
|
433
|
+
cfac: Math.sin(radians),
|
434
|
+
dfac: 0,
|
435
|
+
efac: 1,
|
436
|
+
ffac: 0,
|
437
|
+
gfac: -Math.sin(radians),
|
438
|
+
hfac: 0,
|
439
|
+
ifac: Math.cos(radians),
|
440
|
+
xoff: 0,
|
441
|
+
yoff: 0,
|
442
|
+
zoff: 0
|
443
|
+
)
|
442
444
|
end
|
443
445
|
|
444
446
|
def rotate_y(radians)
|
445
|
-
|
447
|
+
dup.rotate_y!(radians)
|
446
448
|
end
|
447
449
|
|
448
450
|
def rotate_z!(radians)
|
449
|
-
|
451
|
+
rotate!(radians)
|
450
452
|
end
|
451
453
|
|
452
454
|
def rotate_z(radians)
|
453
|
-
|
455
|
+
dup.rotate!(radians)
|
454
456
|
end
|
455
457
|
|
456
|
-
def scale!(*args)
|
457
|
-
x, y, z = if
|
458
|
-
|
458
|
+
def scale!(*args, **kwargs)
|
459
|
+
x, y, z = if !kwargs.empty?
|
460
|
+
kwargs.values_at(:x, :y, :z)
|
459
461
|
elsif args.length.between?(1, 3)
|
460
462
|
args.values_at(0...3)
|
461
463
|
else
|
462
|
-
raise ArgumentError
|
464
|
+
raise ArgumentError, "Wrong number of arguments #{args.length} for 1-3"
|
463
465
|
end
|
464
466
|
|
465
|
-
|
466
|
-
:
|
467
|
-
:
|
468
|
-
:
|
469
|
-
:
|
470
|
-
:
|
471
|
-
:
|
472
|
-
:
|
473
|
-
:
|
474
|
-
:
|
475
|
-
:
|
476
|
-
:
|
477
|
-
:
|
478
|
-
|
479
|
-
end
|
480
|
-
|
481
|
-
def scale(*args)
|
482
|
-
|
483
|
-
end
|
484
|
-
|
485
|
-
def trans_scale!(*args)
|
486
|
-
delta_x, delta_y, x_factor, y_factor = if
|
487
|
-
|
467
|
+
affine!(
|
468
|
+
afac: x || 1,
|
469
|
+
bfac: 0,
|
470
|
+
cfac: 0,
|
471
|
+
dfac: 0,
|
472
|
+
efac: y || 1,
|
473
|
+
ffac: 0,
|
474
|
+
gfac: 0,
|
475
|
+
hfac: 0,
|
476
|
+
ifac: z || 1,
|
477
|
+
xoff: 0,
|
478
|
+
yoff: 0,
|
479
|
+
zoff: 0
|
480
|
+
)
|
481
|
+
end
|
482
|
+
|
483
|
+
def scale(*args, **kwargs)
|
484
|
+
dup.scale!(*args, **kwargs)
|
485
|
+
end
|
486
|
+
|
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)
|
488
490
|
elsif args.length.between?(1, 4)
|
489
491
|
args.values_at(0...4)
|
490
492
|
else
|
491
|
-
raise ArgumentError
|
493
|
+
raise ArgumentError, "Wrong number of arguments #{args.length} for 1-4"
|
492
494
|
end
|
493
495
|
|
494
496
|
x_factor ||= 1
|
@@ -496,62 +498,62 @@ module Geos
|
|
496
498
|
delta_x ||= 0
|
497
499
|
delta_y ||= 0
|
498
500
|
|
499
|
-
|
500
|
-
:
|
501
|
-
:
|
502
|
-
:
|
503
|
-
:
|
504
|
-
:
|
505
|
-
:
|
506
|
-
:
|
507
|
-
:
|
508
|
-
:
|
509
|
-
:
|
510
|
-
:
|
511
|
-
:
|
512
|
-
|
513
|
-
end
|
514
|
-
|
515
|
-
def trans_scale(*args)
|
516
|
-
|
517
|
-
end
|
518
|
-
|
519
|
-
def translate!(*args)
|
520
|
-
x, y, z = if
|
521
|
-
|
501
|
+
affine!(
|
502
|
+
afac: x_factor,
|
503
|
+
bfac: 0,
|
504
|
+
cfac: 0,
|
505
|
+
dfac: 0,
|
506
|
+
efac: y_factor,
|
507
|
+
ffac: 0,
|
508
|
+
gfac: 0,
|
509
|
+
hfac: 0,
|
510
|
+
ifac: 1,
|
511
|
+
xoff: delta_x * x_factor,
|
512
|
+
yoff: delta_y * y_factor,
|
513
|
+
zoff: 0
|
514
|
+
)
|
515
|
+
end
|
516
|
+
|
517
|
+
def trans_scale(*args, **kwargs)
|
518
|
+
dup.trans_scale!(*args, **kwargs)
|
519
|
+
end
|
520
|
+
|
521
|
+
def translate!(*args, **kwargs)
|
522
|
+
x, y, z = if !kwargs.empty?
|
523
|
+
kwargs.values_at(:x, :y, :z)
|
522
524
|
elsif args.length.between?(1, 3)
|
523
525
|
args.values_at(0...3)
|
524
526
|
else
|
525
|
-
raise ArgumentError
|
527
|
+
raise ArgumentError, "Wrong number of arguments #{args.length} for 1-3"
|
526
528
|
end
|
527
529
|
|
528
|
-
|
529
|
-
:
|
530
|
-
:
|
531
|
-
:
|
532
|
-
:
|
533
|
-
:
|
534
|
-
:
|
535
|
-
:
|
536
|
-
:
|
537
|
-
:
|
538
|
-
:
|
539
|
-
:
|
540
|
-
:
|
541
|
-
|
530
|
+
affine!(
|
531
|
+
afac: 1,
|
532
|
+
bfac: 0,
|
533
|
+
cfac: 0,
|
534
|
+
dfac: 0,
|
535
|
+
efac: 1,
|
536
|
+
ffac: 0,
|
537
|
+
gfac: 0,
|
538
|
+
hfac: 0,
|
539
|
+
ifac: 1,
|
540
|
+
xoff: x || 0,
|
541
|
+
yoff: y || 0,
|
542
|
+
zoff: z || 1
|
543
|
+
)
|
542
544
|
end
|
543
545
|
|
544
|
-
def translate(*args)
|
545
|
-
|
546
|
+
def translate(*args, **kwargs)
|
547
|
+
dup.translate!(*args, **kwargs)
|
546
548
|
end
|
547
549
|
|
548
550
|
protected
|
549
551
|
|
550
|
-
def check_bounds(idx)
|
552
|
+
def check_bounds(idx) # :nodoc:
|
551
553
|
raise Geos::IndexBoundsError, 'Index out of bounds' if idx.negative? || idx >= length
|
552
554
|
end
|
553
555
|
|
554
|
-
def build_coordinate(n)
|
556
|
+
def build_coordinate(n) # :nodoc:
|
555
557
|
[
|
556
558
|
get_x(n),
|
557
559
|
(dimensions >= 2 ? get_y(n) : nil),
|