ffi-geos 1.2.1 → 1.2.2
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 +5 -5
- data/.rubocop.yml +20 -0
- data/.travis.yml +7 -3
- data/Gemfile +1 -1
- data/Guardfile +4 -5
- data/ffi-geos.gemspec +1 -1
- data/lib/ffi-geos.rb +212 -196
- data/lib/ffi-geos/buffer_params.rb +9 -20
- data/lib/ffi-geos/coordinate_sequence.rb +342 -58
- data/lib/ffi-geos/geometry.rb +167 -178
- data/lib/ffi-geos/geometry_collection.rb +60 -12
- data/lib/ffi-geos/interrupt.rb +2 -4
- data/lib/ffi-geos/line_string.rb +146 -37
- data/lib/ffi-geos/linear_ring.rb +2 -3
- data/lib/ffi-geos/multi_line_string.rb +1 -2
- data/lib/ffi-geos/multi_point.rb +0 -1
- data/lib/ffi-geos/multi_polygon.rb +0 -1
- data/lib/ffi-geos/point.rb +69 -14
- data/lib/ffi-geos/polygon.rb +110 -21
- data/lib/ffi-geos/prepared_geometry.rb +11 -12
- data/lib/ffi-geos/strtree.rb +41 -52
- data/lib/ffi-geos/tools.rb +15 -18
- data/lib/ffi-geos/utils.rb +27 -44
- data/lib/ffi-geos/version.rb +1 -3
- data/lib/ffi-geos/wkb_reader.rb +4 -9
- data/lib/ffi-geos/wkb_writer.rb +14 -18
- data/lib/ffi-geos/wkt_reader.rb +2 -5
- data/lib/ffi-geos/wkt_writer.rb +17 -22
- data/test/.rubocop.yml +36 -0
- data/test/coordinate_sequence_tests.rb +263 -14
- data/test/geometry_collection_tests.rb +412 -1
- data/test/geometry_tests.rb +156 -86
- data/test/interrupt_tests.rb +2 -4
- data/test/line_string_tests.rb +212 -23
- data/test/linear_ring_tests.rb +1 -2
- data/test/misc_tests.rb +28 -29
- data/test/multi_line_string_tests.rb +0 -1
- data/test/point_tests.rb +158 -1
- data/test/polygon_tests.rb +284 -1
- data/test/prepared_geometry_tests.rb +1 -3
- data/test/strtree_tests.rb +9 -10
- data/test/test_helper.rb +49 -18
- data/test/tools_tests.rb +1 -3
- data/test/utils_tests.rb +22 -22
- data/test/wkb_reader_tests.rb +10 -9
- data/test/wkb_writer_tests.rb +5 -13
- data/test/wkt_reader_tests.rb +1 -2
- data/test/wkt_writer_tests.rb +9 -14
- metadata +6 -3
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -8,34 +7,83 @@ module Geos
|
|
8
7
|
# Yields each Geometry in the GeometryCollection.
|
9
8
|
def each
|
10
9
|
if block_given?
|
11
|
-
|
12
|
-
yield
|
10
|
+
num_geometries.times do |n|
|
11
|
+
yield get_geometry_n(n)
|
13
12
|
end
|
14
13
|
self
|
15
14
|
else
|
16
|
-
|
17
|
-
|
15
|
+
num_geometries.times.collect { |n|
|
16
|
+
get_geometry_n(n)
|
18
17
|
}.to_enum
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
def get_geometry_n(n)
|
23
|
-
if n
|
22
|
+
if n.negative? || n >= num_geometries
|
24
23
|
nil
|
25
24
|
else
|
26
|
-
cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle_pointer,
|
25
|
+
cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle_pointer, ptr, n), auto_free: false)
|
27
26
|
end
|
28
27
|
end
|
29
|
-
|
28
|
+
alias geometry_n get_geometry_n
|
30
29
|
|
31
30
|
def [](*args)
|
32
31
|
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
33
|
-
|
32
|
+
get_geometry_n(args.first)
|
34
33
|
else
|
35
|
-
|
34
|
+
to_a[*args]
|
36
35
|
end
|
37
36
|
end
|
38
|
-
|
39
|
-
|
37
|
+
alias slice []
|
38
|
+
alias at []
|
39
|
+
|
40
|
+
def dump_points(cur_path = [])
|
41
|
+
each do |geom|
|
42
|
+
cur_path << geom.dump_points
|
43
|
+
end
|
44
|
+
cur_path
|
45
|
+
end
|
46
|
+
|
47
|
+
%w{ x y z }.each do |dimension|
|
48
|
+
%w{ max min }.each do |op|
|
49
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
50
|
+
def #{dimension}_#{op}
|
51
|
+
unless self.empty?
|
52
|
+
self.collect(&:#{dimension}_#{op}).#{op}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
EOF
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
%w{
|
60
|
+
affine
|
61
|
+
rotate
|
62
|
+
rotate_x
|
63
|
+
rotate_y
|
64
|
+
rotate_z
|
65
|
+
scale
|
66
|
+
snap_to_grid
|
67
|
+
trans_scale
|
68
|
+
translate
|
69
|
+
}.each do |m|
|
70
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
71
|
+
def #{m}!(*args)
|
72
|
+
unless self.empty?
|
73
|
+
self.num_geometries.times do |i|
|
74
|
+
self[i].#{m}!(*args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def #{m}(*args)
|
82
|
+
ret = self.dup.#{m}!(*args)
|
83
|
+
ret.srid = pick_srid_according_to_policy(self.srid)
|
84
|
+
ret
|
85
|
+
end
|
86
|
+
EOF
|
87
|
+
end
|
40
88
|
end
|
41
89
|
end
|
data/lib/ffi-geos/interrupt.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -27,9 +26,9 @@ module Geos
|
|
27
26
|
# up in unexpected ways while interrupts are firing.
|
28
27
|
def register(method_or_block = nil, &block)
|
29
28
|
if method_or_block.nil? && !block_given?
|
30
|
-
raise ArgumentError
|
29
|
+
raise ArgumentError, 'Expected either a method or a block for Geos::Interrupt.register'
|
31
30
|
elsif !method_or_block.nil? && block_given?
|
32
|
-
raise ArgumentError
|
31
|
+
raise ArgumentError, 'Cannot use both a method and a block for Geos::Interrupt.register'
|
33
32
|
else
|
34
33
|
retval = @current_interrupt_callback
|
35
34
|
|
@@ -72,4 +71,3 @@ module Geos
|
|
72
71
|
end
|
73
72
|
end
|
74
73
|
end
|
75
|
-
|
data/lib/ffi-geos/line_string.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -7,82 +6,192 @@ module Geos
|
|
7
6
|
|
8
7
|
def each
|
9
8
|
if block_given?
|
10
|
-
|
11
|
-
yield
|
9
|
+
num_points.times do |n|
|
10
|
+
yield point_n(n)
|
12
11
|
end
|
13
12
|
self
|
14
13
|
else
|
15
|
-
|
16
|
-
|
14
|
+
num_points.times.collect { |n|
|
15
|
+
point_n(n)
|
17
16
|
}.to_enum
|
18
17
|
end
|
19
18
|
end
|
20
19
|
|
21
20
|
if FFIGeos.respond_to?(:GEOSGeomGetNumPoints_r)
|
22
21
|
def num_points
|
23
|
-
FFIGeos.GEOSGeomGetNumPoints_r(Geos.current_handle_pointer,
|
22
|
+
FFIGeos.GEOSGeomGetNumPoints_r(Geos.current_handle_pointer, ptr)
|
24
23
|
end
|
25
24
|
else
|
26
25
|
def num_points
|
27
|
-
|
26
|
+
coord_seq.length
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def point_n(n)
|
32
|
-
if n < 0 || n >=
|
33
|
-
|
34
|
-
|
35
|
-
cast_geometry_ptr(
|
36
|
-
FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle_pointer, self.ptr, n), {
|
37
|
-
:srid_copy => self.srid
|
38
|
-
}
|
39
|
-
)
|
40
|
-
end
|
31
|
+
raise Geos::IndexBoundsError if n < 0 || n >= num_points
|
32
|
+
|
33
|
+
cast_geometry_ptr(FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle_pointer, ptr, n), srid_copy: srid)
|
41
34
|
end
|
42
35
|
|
43
36
|
def [](*args)
|
44
37
|
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
45
|
-
|
38
|
+
point_n(args.first)
|
46
39
|
else
|
47
|
-
|
40
|
+
to_a[*args]
|
48
41
|
end
|
49
42
|
end
|
50
|
-
|
43
|
+
alias slice []
|
51
44
|
|
52
45
|
def offset_curve(width, options = {})
|
53
46
|
options = Constants::BUFFER_PARAM_DEFAULTS.merge(options)
|
54
47
|
|
55
48
|
cast_geometry_ptr(FFIGeos.GEOSOffsetCurve_r(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
),
|
63
|
-
:srid_copy => self.srid
|
64
|
-
})
|
49
|
+
Geos.current_handle_pointer,
|
50
|
+
ptr,
|
51
|
+
width,
|
52
|
+
options[:quad_segs],
|
53
|
+
options[:join],
|
54
|
+
options[:mitre_limit]
|
55
|
+
), srid_copy: srid)
|
65
56
|
end
|
66
57
|
|
67
58
|
if FFIGeos.respond_to?(:GEOSisClosed_r)
|
68
59
|
def closed?
|
69
|
-
bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer,
|
60
|
+
bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
|
70
61
|
end
|
71
62
|
end
|
72
63
|
|
73
64
|
def to_linear_ring
|
74
|
-
if
|
75
|
-
Geos.create_linear_ring(self.coord_seq, :srid => pick_srid_according_to_policy(self.srid))
|
76
|
-
else
|
77
|
-
self_cs = self.coord_seq.to_a
|
78
|
-
self_cs.push(self_cs[0])
|
65
|
+
return Geos.create_linear_ring(coord_seq, srid: pick_srid_according_to_policy(srid)) if closed?
|
79
66
|
|
80
|
-
|
81
|
-
|
67
|
+
self_cs = coord_seq.to_a
|
68
|
+
self_cs.push(self_cs[0])
|
69
|
+
|
70
|
+
Geos.create_linear_ring(self_cs, srid: pick_srid_according_to_policy(srid))
|
82
71
|
end
|
83
72
|
|
84
73
|
def to_polygon
|
85
|
-
|
74
|
+
to_linear_ring.to_polygon
|
75
|
+
end
|
76
|
+
|
77
|
+
def dump_points(cur_path = [])
|
78
|
+
cur_path.concat(to_a)
|
79
|
+
end
|
80
|
+
|
81
|
+
def snap_to_grid!(*args)
|
82
|
+
if !self.empty?
|
83
|
+
cs = self.coord_seq.snap_to_grid!(*args)
|
84
|
+
|
85
|
+
if cs.length == 0
|
86
|
+
@ptr = Geos.create_empty_line_string(:srid => self.srid).ptr
|
87
|
+
elsif cs.length <= 1
|
88
|
+
raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in for a LineString - found #{cs.length} - must be 0 or > 1")
|
89
|
+
else
|
90
|
+
@ptr = Geos.create_line_string(cs).ptr
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def snap_to_grid(*args)
|
98
|
+
ret = self.dup.snap_to_grid!(*args)
|
99
|
+
ret.srid = pick_srid_according_to_policy(self.srid)
|
100
|
+
ret
|
101
|
+
end
|
102
|
+
|
103
|
+
def line_interpolate_point(fraction)
|
104
|
+
if !fraction.between?(0, 1)
|
105
|
+
raise ArgumentError.new("fraction must be between 0 and 1")
|
106
|
+
end
|
107
|
+
|
108
|
+
case fraction
|
109
|
+
when 0
|
110
|
+
self.start_point
|
111
|
+
when 1
|
112
|
+
self.end_point
|
113
|
+
else
|
114
|
+
length = self.length
|
115
|
+
total_length = 0
|
116
|
+
segs = self.num_points - 1
|
117
|
+
|
118
|
+
segs.times do |i|
|
119
|
+
p1 = self[i]
|
120
|
+
p2 = self[i + 1]
|
121
|
+
|
122
|
+
seg_length = p1.distance(p2) / length
|
123
|
+
|
124
|
+
if fraction < total_length + seg_length
|
125
|
+
dseg = (fraction - total_length) / seg_length;
|
126
|
+
|
127
|
+
args = []
|
128
|
+
args << p1.x + ((p2.x - p1.x) * dseg)
|
129
|
+
args << p1.y + ((p2.y - p1.y) * dseg)
|
130
|
+
args << p1.z + ((p2.z - p1.z) * dseg) if self.has_z?
|
131
|
+
|
132
|
+
args << { :srid => pick_srid_according_to_policy(self.srid) } unless self.srid == 0
|
133
|
+
|
134
|
+
return Geos.create_point(*args)
|
135
|
+
end
|
136
|
+
|
137
|
+
total_length += seg_length
|
138
|
+
end
|
139
|
+
|
140
|
+
# if all else fails...
|
141
|
+
self.end_point
|
142
|
+
end
|
143
|
+
end
|
144
|
+
alias_method :interpolate_point, :line_interpolate_point
|
145
|
+
|
146
|
+
%w{ max min }.each do |op|
|
147
|
+
%w{ x y }.each do |dimension|
|
148
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
149
|
+
def #{dimension}_#{op}
|
150
|
+
unless self.empty?
|
151
|
+
self.coord_seq.#{dimension}_#{op}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
EOF
|
155
|
+
end
|
156
|
+
|
157
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
158
|
+
def z_#{op}
|
159
|
+
unless self.empty?
|
160
|
+
if self.has_z?
|
161
|
+
self.coord_seq.z_#{op}
|
162
|
+
else
|
163
|
+
0
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
EOF
|
168
|
+
end
|
169
|
+
|
170
|
+
%w{
|
171
|
+
affine
|
172
|
+
rotate
|
173
|
+
rotate_x
|
174
|
+
rotate_y
|
175
|
+
rotate_z
|
176
|
+
scale
|
177
|
+
trans_scale
|
178
|
+
translate
|
179
|
+
}.each do |m|
|
180
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
181
|
+
def #{m}!(*args)
|
182
|
+
unless self.empty?
|
183
|
+
self.coord_seq.#{m}!(*args)
|
184
|
+
end
|
185
|
+
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
def #{m}(*args)
|
190
|
+
ret = self.dup.#{m}!(*args)
|
191
|
+
ret.srid = pick_srid_according_to_policy(self.srid)
|
192
|
+
ret
|
193
|
+
end
|
194
|
+
EOF
|
86
195
|
end
|
87
196
|
end
|
88
197
|
end
|
data/lib/ffi-geos/linear_ring.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
5
4
|
class LinearRing < LineString
|
6
5
|
def to_polygon
|
7
|
-
Geos.create_polygon(self, :
|
6
|
+
Geos.create_polygon(self, srid: pick_srid_according_to_policy(srid))
|
8
7
|
end
|
9
8
|
|
10
9
|
def to_line_string
|
11
|
-
Geos.create_line_string(
|
10
|
+
Geos.create_line_string(coord_seq, srid: pick_srid_according_to_policy(srid))
|
12
11
|
end
|
13
12
|
end
|
14
13
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -6,7 +5,7 @@ module Geos
|
|
6
5
|
if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::GEOS_VERSION >= '3.5.0'
|
7
6
|
# Available in GEOS 3.5.0+.
|
8
7
|
def closed?
|
9
|
-
bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer,
|
8
|
+
bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
|
10
9
|
end
|
11
10
|
end
|
12
11
|
end
|
data/lib/ffi-geos/multi_point.rb
CHANGED
data/lib/ffi-geos/point.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Geos
|
@@ -6,41 +5,41 @@ module Geos
|
|
6
5
|
if FFIGeos.respond_to?(:GEOSGeomGetX_r)
|
7
6
|
def get_x
|
8
7
|
double_ptr = FFI::MemoryPointer.new(:double)
|
9
|
-
FFIGeos.GEOSGeomGetX_r(Geos.current_handle_pointer,
|
8
|
+
FFIGeos.GEOSGeomGetX_r(Geos.current_handle_pointer, ptr, double_ptr)
|
10
9
|
double_ptr.read_double
|
11
10
|
end
|
12
11
|
else
|
13
12
|
def get_x
|
14
|
-
|
13
|
+
coord_seq.get_x(0)
|
15
14
|
end
|
16
15
|
end
|
17
|
-
|
16
|
+
alias x get_x
|
18
17
|
|
19
18
|
if FFIGeos.respond_to?(:GEOSGeomGetY_r)
|
20
19
|
def get_y
|
21
20
|
double_ptr = FFI::MemoryPointer.new(:double)
|
22
|
-
FFIGeos.GEOSGeomGetY_r(Geos.current_handle_pointer,
|
21
|
+
FFIGeos.GEOSGeomGetY_r(Geos.current_handle_pointer, ptr, double_ptr)
|
23
22
|
double_ptr.read_double
|
24
23
|
end
|
25
24
|
else
|
26
25
|
def get_y
|
27
|
-
|
26
|
+
coord_seq.get_y(0)
|
28
27
|
end
|
29
28
|
end
|
30
|
-
|
29
|
+
alias y get_y
|
31
30
|
|
32
31
|
if FFIGeos.respond_to?(:GEOSGeomGetZ_r)
|
33
32
|
def get_z
|
34
33
|
double_ptr = FFI::MemoryPointer.new(:double)
|
35
|
-
FFIGeos.GEOSGeomGetZ_r(Geos.current_handle_pointer,
|
34
|
+
FFIGeos.GEOSGeomGetZ_r(Geos.current_handle_pointer, ptr, double_ptr)
|
36
35
|
double_ptr.read_double
|
37
36
|
end
|
38
37
|
else
|
39
38
|
def get_z
|
40
|
-
|
39
|
+
coord_seq.get_z(0)
|
41
40
|
end
|
42
41
|
end
|
43
|
-
|
42
|
+
alias z get_z
|
44
43
|
|
45
44
|
def area
|
46
45
|
0
|
@@ -61,7 +60,7 @@ module Geos
|
|
61
60
|
def normalize!
|
62
61
|
self
|
63
62
|
end
|
64
|
-
|
63
|
+
alias normalize normalize!
|
65
64
|
|
66
65
|
%w{
|
67
66
|
convex_hull
|
@@ -70,11 +69,67 @@ module Geos
|
|
70
69
|
envelope
|
71
70
|
topology_preserve_simplify
|
72
71
|
}.each do |method|
|
73
|
-
|
72
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
74
73
|
def #{method}(*args)
|
75
|
-
|
74
|
+
dup.tap do |ret|
|
76
75
|
ret.srid = pick_srid_according_to_policy(ret.srid)
|
77
|
-
|
76
|
+
end
|
77
|
+
end
|
78
|
+
RUBY
|
79
|
+
end
|
80
|
+
|
81
|
+
def dump_points(cur_path = [])
|
82
|
+
cur_path.push(self.dup)
|
83
|
+
end
|
84
|
+
|
85
|
+
%w{ max min }.each do |op|
|
86
|
+
%w{ x y }.each do |dimension|
|
87
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
88
|
+
def #{dimension}_#{op}
|
89
|
+
unless self.empty?
|
90
|
+
self.#{dimension}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
EOF
|
94
|
+
end
|
95
|
+
|
96
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
97
|
+
def z_#{op}
|
98
|
+
unless self.empty?
|
99
|
+
if self.has_z?
|
100
|
+
self.z
|
101
|
+
else
|
102
|
+
0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
EOF
|
107
|
+
end
|
108
|
+
|
109
|
+
%w{
|
110
|
+
affine
|
111
|
+
rotate
|
112
|
+
rotate_x
|
113
|
+
rotate_y
|
114
|
+
rotate_z
|
115
|
+
scale
|
116
|
+
snap_to_grid
|
117
|
+
trans_scale
|
118
|
+
translate
|
119
|
+
}.each do |m|
|
120
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
121
|
+
def #{m}!(*args)
|
122
|
+
unless self.empty?
|
123
|
+
self.coord_seq.#{m}!(*args)
|
124
|
+
end
|
125
|
+
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
def #{m}(*args)
|
130
|
+
ret = self.dup.#{m}!(*args)
|
131
|
+
ret.srid = pick_srid_according_to_policy(self.srid)
|
132
|
+
ret
|
78
133
|
end
|
79
134
|
EOF
|
80
135
|
end
|