ffi-geos 1.2.2 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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),
|