ffi-geos 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +21 -3
- data/ffi-geos.gemspec +2 -0
- data/lib/ffi-geos.rb +90 -13
- data/lib/ffi-geos/coordinate_sequence.rb +29 -14
- data/lib/ffi-geos/geometry.rb +77 -42
- data/lib/ffi-geos/geometry_collection.rb +6 -2
- data/lib/ffi-geos/line_string.rb +13 -3
- data/lib/ffi-geos/linear_ring.rb +3 -0
- data/lib/ffi-geos/point.rb +60 -2
- data/lib/ffi-geos/polygon.rb +13 -2
- data/lib/ffi-geos/tools.rb +35 -2
- data/lib/ffi-geos/utils.rb +120 -62
- data/lib/ffi-geos/version.rb +1 -1
- data/lib/ffi-geos/wkb_reader.rb +8 -4
- data/lib/ffi-geos/wkt_reader.rb +4 -2
- data/test/coordinate_sequence_tests.rb +81 -27
- data/test/geometry_collection_tests.rb +79 -0
- data/test/geometry_tests.rb +235 -249
- data/test/line_string_tests.rb +167 -0
- data/test/linear_ring_tests.rb +24 -0
- data/test/misc_tests.rb +3 -3
- data/test/point_tests.rb +62 -1
- data/test/polygon_tests.rb +36 -0
- data/test/prepared_geometry_tests.rb +4 -4
- data/test/strtree_tests.rb +6 -6
- data/test/test_helper.rb +48 -1
- data/test/utils_tests.rb +116 -34
- data/test/wkb_reader_tests.rb +24 -4
- data/test/wkb_writer_tests.rb +5 -5
- data/test/wkt_reader_tests.rb +10 -5
- data/test/wkt_writer_tests.rb +3 -3
- metadata +43 -3
@@ -21,13 +21,17 @@ module Geos
|
|
21
21
|
if n < 0 || n >= self.num_geometries
|
22
22
|
nil
|
23
23
|
else
|
24
|
-
cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle, self.ptr, n), false)
|
24
|
+
cast_geometry_ptr(FFIGeos.GEOSGetGeometryN_r(Geos.current_handle, self.ptr, n), :auto_free => false)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
alias :geometry_n :get_geometry_n
|
28
28
|
|
29
29
|
def [](*args)
|
30
|
-
|
30
|
+
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
31
|
+
self.get_geometry_n(args.first)
|
32
|
+
else
|
33
|
+
self.to_a[*args]
|
34
|
+
end
|
31
35
|
end
|
32
36
|
alias :slice :[]
|
33
37
|
alias :at :[]
|
data/lib/ffi-geos/line_string.rb
CHANGED
@@ -30,12 +30,20 @@ module Geos
|
|
30
30
|
if n < 0 || n >= self.num_points
|
31
31
|
raise RuntimeError.new("Index out of bounds")
|
32
32
|
else
|
33
|
-
cast_geometry_ptr(
|
33
|
+
cast_geometry_ptr(
|
34
|
+
FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle, self.ptr, n), {
|
35
|
+
:srid_copy => self.srid
|
36
|
+
}
|
37
|
+
)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
41
|
def [](*args)
|
38
|
-
|
42
|
+
if args.length == 1 && args.first.is_a?(Numeric) && args.first >= 0
|
43
|
+
self.point_n(args.first)
|
44
|
+
else
|
45
|
+
self.to_a[*args]
|
46
|
+
end
|
39
47
|
end
|
40
48
|
alias :slice :[]
|
41
49
|
|
@@ -49,7 +57,9 @@ module Geos
|
|
49
57
|
options[:quad_segs],
|
50
58
|
options[:join],
|
51
59
|
options[:mitre_limit]
|
52
|
-
)
|
60
|
+
), {
|
61
|
+
:srid_copy => self.srid
|
62
|
+
})
|
53
63
|
end
|
54
64
|
|
55
65
|
if FFIGeos.respond_to?(:GEOSisClosed_r)
|
data/lib/ffi-geos/linear_ring.rb
CHANGED
data/lib/ffi-geos/point.rb
CHANGED
@@ -7,8 +7,12 @@ module Geos
|
|
7
7
|
FFIGeos.GEOSGeomGetX_r(Geos.current_handle, self.ptr, ret)
|
8
8
|
}.read_double
|
9
9
|
end
|
10
|
-
|
10
|
+
else
|
11
|
+
def get_x
|
12
|
+
self.coord_seq.get_x(0)
|
13
|
+
end
|
11
14
|
end
|
15
|
+
alias :x :get_x
|
12
16
|
|
13
17
|
if FFIGeos.respond_to?(:GEOSGeomGetY_r)
|
14
18
|
def get_y
|
@@ -16,7 +20,61 @@ module Geos
|
|
16
20
|
FFIGeos.GEOSGeomGetY_r(Geos.current_handle, self.ptr, ret)
|
17
21
|
}.read_double
|
18
22
|
end
|
19
|
-
|
23
|
+
else
|
24
|
+
def get_y
|
25
|
+
self.coord_seq.get_y(0)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
alias :y :get_y
|
29
|
+
|
30
|
+
if FFIGeos.respond_to?(:GEOSGeomGetZ_r)
|
31
|
+
def get_z
|
32
|
+
FFI::MemoryPointer.new(:double).tap { |ret|
|
33
|
+
FFIGeos.GEOSGeomGetZ_r(Geos.current_handle, self.ptr, ret)
|
34
|
+
}.read_double
|
35
|
+
end
|
36
|
+
else
|
37
|
+
def get_z
|
38
|
+
self.coord_seq.get_z(0)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias :z :get_z
|
42
|
+
|
43
|
+
def area
|
44
|
+
0
|
45
|
+
end
|
46
|
+
|
47
|
+
def length
|
48
|
+
0
|
49
|
+
end
|
50
|
+
|
51
|
+
def num_geometries
|
52
|
+
1
|
53
|
+
end
|
54
|
+
|
55
|
+
def num_coordinates
|
56
|
+
1
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalize!
|
60
|
+
self
|
61
|
+
end
|
62
|
+
alias :normalize :normalize!
|
63
|
+
|
64
|
+
%w{
|
65
|
+
convex_hull
|
66
|
+
point_on_surface
|
67
|
+
centroid
|
68
|
+
envelope
|
69
|
+
topology_preserve_simplify
|
70
|
+
}.each do |method|
|
71
|
+
self.class_eval(<<-EOF)
|
72
|
+
def #{method}(*args)
|
73
|
+
self.dup.tap { |ret|
|
74
|
+
ret.srid = pick_srid_according_to_policy(ret.srid)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
EOF
|
20
78
|
end
|
21
79
|
end
|
22
80
|
end
|
data/lib/ffi-geos/polygon.rb
CHANGED
@@ -9,12 +9,23 @@ module Geos
|
|
9
9
|
if n < 0 || n >= self.num_interior_rings
|
10
10
|
raise RuntimeError.new("Index out of bounds")
|
11
11
|
else
|
12
|
-
cast_geometry_ptr(
|
12
|
+
cast_geometry_ptr(
|
13
|
+
FFIGeos.GEOSGetInteriorRingN_r(Geos.current_handle, self.ptr, n), {
|
14
|
+
:auto_free => false,
|
15
|
+
:srid_copy => self.srid
|
16
|
+
}
|
17
|
+
)
|
13
18
|
end
|
14
19
|
end
|
20
|
+
alias :interior_ring :interior_ring_n
|
15
21
|
|
16
22
|
def exterior_ring
|
17
|
-
cast_geometry_ptr(
|
23
|
+
cast_geometry_ptr(
|
24
|
+
FFIGeos.GEOSGetExteriorRing_r(Geos.current_handle, self.ptr), {
|
25
|
+
:auto_free => false,
|
26
|
+
:srid_copy => self.srid
|
27
|
+
}
|
28
|
+
)
|
18
29
|
end
|
19
30
|
|
20
31
|
def interior_rings
|
data/lib/ffi-geos/tools.rb
CHANGED
@@ -3,7 +3,11 @@ module Geos
|
|
3
3
|
module Tools
|
4
4
|
include GeomTypes
|
5
5
|
|
6
|
-
def cast_geometry_ptr(geom_ptr,
|
6
|
+
def cast_geometry_ptr(geom_ptr, options = {})
|
7
|
+
options = {
|
8
|
+
:auto_free => true
|
9
|
+
}.merge(options)
|
10
|
+
|
7
11
|
if geom_ptr.null?
|
8
12
|
raise RuntimeError.new("Tried to create a Geometry from a NULL pointer!")
|
9
13
|
end
|
@@ -29,13 +33,42 @@ module Geos
|
|
29
33
|
raise RuntimeError.new("Invalid geometry type")
|
30
34
|
end
|
31
35
|
|
32
|
-
klass.new(geom_ptr, auto_free)
|
36
|
+
klass.new(geom_ptr, options[:auto_free]).tap { |ret|
|
37
|
+
if options[:srid]
|
38
|
+
ret.srid = options[:srid] || 0
|
39
|
+
elsif options[:srid_copy]
|
40
|
+
ret.srid = if Geos.srid_copy_policy == :zero
|
41
|
+
0
|
42
|
+
else
|
43
|
+
options[:srid_copy] || 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
}
|
33
47
|
end
|
34
48
|
|
35
49
|
def check_geometry(geom)
|
36
50
|
raise TypeError.new("Expected Geos::Geometry") unless geom.is_a?(Geos::Geometry)
|
37
51
|
end
|
38
52
|
|
53
|
+
def pick_srid_from_geoms(srid_a, srid_b, policy = Geos.srid_copy_policy)
|
54
|
+
case policy
|
55
|
+
when :zero
|
56
|
+
0
|
57
|
+
when :lenient
|
58
|
+
srid_a
|
59
|
+
when :strict
|
60
|
+
raise Geos::MixedSRIDsError.new(srid_a, srid_b)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def pick_srid_according_to_policy(srid, policy = Geos.srid_copy_policy)
|
65
|
+
if srid != 0 && Geos.srid_copy_policy != :zero
|
66
|
+
self.srid
|
67
|
+
else
|
68
|
+
0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
39
72
|
def bool_result(r)
|
40
73
|
case r
|
41
74
|
when 1
|
data/lib/ffi-geos/utils.rb
CHANGED
@@ -26,98 +26,140 @@ module Geos
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def create_point(
|
29
|
+
def create_point(*args)
|
30
|
+
options = if args.last.is_a?(Hash)
|
31
|
+
args.pop
|
32
|
+
else
|
33
|
+
{}
|
34
|
+
end
|
35
|
+
|
36
|
+
if args.length == 1
|
37
|
+
cs = args.first
|
38
|
+
elsif args.length == 2
|
39
|
+
cs = CoordinateSequence.new(1, 2)
|
40
|
+
cs.x[0], cs.y[0] = args[0], args[1]
|
41
|
+
elsif args.length == 3
|
42
|
+
cs = CoordinateSequence.new(1, 3)
|
43
|
+
cs.x[0], cs.y[0], cs.z[0] = args
|
44
|
+
else
|
45
|
+
raise ArgumentError.new("Wrong number of arguments (#{args.length} for 1-3)")
|
46
|
+
end
|
47
|
+
|
30
48
|
if cs.length != 1
|
31
49
|
raise RuntimeError.new("IllegalArgumentException: Point coordinate list must contain a single element")
|
32
50
|
end
|
33
51
|
|
34
|
-
|
52
|
+
cs_dup = cs.dup
|
53
|
+
cs_dup.ptr.autorelease = false
|
35
54
|
|
36
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createPoint_r(Geos.current_handle,
|
37
|
-
|
38
|
-
}
|
55
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createPoint_r(Geos.current_handle, cs_dup.ptr), {
|
56
|
+
:srid => options[:srid]
|
57
|
+
})
|
39
58
|
end
|
40
59
|
|
41
|
-
def create_line_string(cs)
|
60
|
+
def create_line_string(cs, options = {})
|
61
|
+
cs = cs_from_cs_or_geom(cs)
|
62
|
+
|
42
63
|
if cs.length <= 1 && cs.length != 0
|
43
64
|
raise RuntimeError.new("IllegalArgumentException: point array must contain 0 or >1 elements")
|
44
65
|
end
|
45
66
|
|
46
|
-
|
67
|
+
cs_dup = cs.dup
|
68
|
+
cs_dup.ptr.autorelease = false
|
47
69
|
|
48
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createLineString_r(Geos.current_handle,
|
49
|
-
|
50
|
-
}
|
70
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createLineString_r(Geos.current_handle, cs_dup.ptr), {
|
71
|
+
:srid => options[:srid]
|
72
|
+
})
|
51
73
|
end
|
52
74
|
|
53
|
-
def create_linear_ring(cs)
|
75
|
+
def create_linear_ring(cs, options = {})
|
76
|
+
cs = cs_from_cs_or_geom(cs)
|
77
|
+
|
54
78
|
if cs.length <= 1 && cs.length != 0
|
55
79
|
raise RuntimeError.new("IllegalArgumentException: point array must contain 0 or >1 elements")
|
56
80
|
end
|
57
81
|
|
58
|
-
|
82
|
+
cs.ptr.autorelease = false
|
59
83
|
|
60
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createLinearRing_r(Geos.current_handle,
|
61
|
-
|
62
|
-
}
|
84
|
+
ret = cast_geometry_ptr(FFIGeos.GEOSGeom_createLinearRing_r(Geos.current_handle, cs.ptr), {
|
85
|
+
:srid => options[:srid]
|
86
|
+
})
|
63
87
|
end
|
64
88
|
|
65
|
-
def create_polygon(outer, *
|
66
|
-
|
89
|
+
def create_polygon(outer, *args)
|
90
|
+
options = if args.last.is_a?(Hash)
|
91
|
+
args.pop
|
92
|
+
else
|
93
|
+
{}
|
94
|
+
end
|
95
|
+
|
96
|
+
inner_dups = Array(args).flatten.collect { |i|
|
67
97
|
force_to_linear_ring(i) or
|
68
98
|
raise TypeError.new("Expected inner Array to contain Geos::LinearRing or Geos::CoordinateSequence objects")
|
69
99
|
}
|
70
100
|
|
71
|
-
|
101
|
+
outer_dup = force_to_linear_ring(outer) or
|
72
102
|
raise TypeError.new("Expected outer shell to be a Geos::LinearRing or Geos::CoordinateSequence")
|
73
103
|
|
74
|
-
ary = FFI::MemoryPointer.new(:pointer,
|
75
|
-
ary.write_array_of_pointer(
|
104
|
+
ary = FFI::MemoryPointer.new(:pointer, inner_dups.length)
|
105
|
+
ary.write_array_of_pointer(inner_dups.map(&:ptr))
|
76
106
|
|
77
|
-
|
78
|
-
|
79
|
-
|
107
|
+
outer_dup.ptr.autorelease = false
|
108
|
+
inner_dups.each { |i|
|
109
|
+
i.ptr.autorelease = false
|
80
110
|
}
|
111
|
+
|
112
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createPolygon_r(Geos.current_handle, outer_dup.ptr, ary, inner_dups.length), {
|
113
|
+
:srid => options[:srid]
|
114
|
+
})
|
81
115
|
end
|
82
116
|
|
83
|
-
def create_empty_point
|
84
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPoint_r(Geos.current_handle)
|
117
|
+
def create_empty_point(options = {})
|
118
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPoint_r(Geos.current_handle), {
|
119
|
+
:srid => options[:srid]
|
120
|
+
})
|
85
121
|
end
|
86
122
|
|
87
|
-
def create_empty_line_string
|
88
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyLineString_r(Geos.current_handle)
|
123
|
+
def create_empty_line_string(options = {})
|
124
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyLineString_r(Geos.current_handle), {
|
125
|
+
:srid => options[:srid]
|
126
|
+
})
|
89
127
|
end
|
90
128
|
|
91
|
-
def create_empty_polygon
|
92
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPolygon_r(Geos.current_handle)
|
129
|
+
def create_empty_polygon(options = {})
|
130
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyPolygon_r(Geos.current_handle), {
|
131
|
+
:srid => options[:srid]
|
132
|
+
})
|
93
133
|
end
|
94
134
|
|
95
|
-
def create_empty_collection(t)
|
135
|
+
def create_empty_collection(t, options = {})
|
96
136
|
check_enum_value(Geos::GeometryTypes, t)
|
97
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyCollection_r(Geos.current_handle, t)
|
137
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createEmptyCollection_r(Geos.current_handle, t), {
|
138
|
+
:srid => options[:srid]
|
139
|
+
})
|
98
140
|
end
|
99
141
|
|
100
|
-
def create_empty_multi_point
|
101
|
-
create_empty_collection(:multi_point)
|
142
|
+
def create_empty_multi_point(options = {})
|
143
|
+
create_empty_collection(:multi_point, options)
|
102
144
|
end
|
103
145
|
|
104
|
-
def create_empty_multi_line_string
|
105
|
-
create_empty_collection(:multi_line_string)
|
146
|
+
def create_empty_multi_line_string(options = {})
|
147
|
+
create_empty_collection(:multi_line_string, options)
|
106
148
|
end
|
107
149
|
|
108
|
-
def create_empty_multi_polygon
|
109
|
-
create_empty_collection(:multi_polygon)
|
150
|
+
def create_empty_multi_polygon(options = {})
|
151
|
+
create_empty_collection(:multi_polygon, options)
|
110
152
|
end
|
111
153
|
|
112
|
-
def create_empty_geometry_collection
|
113
|
-
create_empty_collection(:geometry_collection)
|
154
|
+
def create_empty_geometry_collection(options = {})
|
155
|
+
create_empty_collection(:geometry_collection, options)
|
114
156
|
end
|
115
157
|
|
116
|
-
def create_empty_linear_ring
|
117
|
-
Geos::WktReader.new.read('LINEARRING EMPTY')
|
158
|
+
def create_empty_linear_ring(options = {})
|
159
|
+
Geos::WktReader.new.read('LINEARRING EMPTY', options)
|
118
160
|
end
|
119
161
|
|
120
|
-
def create_collection(t, *
|
162
|
+
def create_collection(t, *args)
|
121
163
|
check_enum_value(Geos::GeometryTypes, t)
|
122
164
|
|
123
165
|
klass = case t
|
@@ -131,47 +173,63 @@ module Geos
|
|
131
173
|
Geos::Geometry
|
132
174
|
end
|
133
175
|
|
134
|
-
|
176
|
+
options = if args.last.is_a?(Hash)
|
177
|
+
args.pop
|
178
|
+
else
|
179
|
+
{}
|
180
|
+
end
|
181
|
+
|
182
|
+
geoms = Array(args).flatten.tap { |i|
|
135
183
|
if i.detect { |g| !g.is_a?(klass) }
|
136
184
|
raise TypeError.new("Expected geoms Array to contain #{klass} objects")
|
137
185
|
end
|
138
186
|
}
|
139
187
|
|
140
|
-
|
188
|
+
geoms_dups = geoms.map(&:dup)
|
189
|
+
geoms_dups.each { |i|
|
190
|
+
i.ptr.autorelease = false
|
191
|
+
}
|
141
192
|
|
142
193
|
ary = FFI::MemoryPointer.new(:pointer, geoms.length)
|
143
|
-
ary.write_array_of_pointer(
|
194
|
+
ary.write_array_of_pointer(geoms_dups.map(&:ptr))
|
144
195
|
|
145
|
-
cast_geometry_ptr(FFIGeos.GEOSGeom_createCollection_r(Geos.current_handle, t, ary,
|
146
|
-
|
147
|
-
|
148
|
-
}
|
149
|
-
}
|
196
|
+
cast_geometry_ptr(FFIGeos.GEOSGeom_createCollection_r(Geos.current_handle, t, ary, geoms_dups.length), {
|
197
|
+
:srid => options[:srid]
|
198
|
+
})
|
150
199
|
end
|
151
200
|
|
152
|
-
def create_multi_point(*
|
153
|
-
create_collection(:multi_point, *
|
201
|
+
def create_multi_point(*args)
|
202
|
+
create_collection(:multi_point, *args)
|
154
203
|
end
|
155
204
|
|
156
|
-
def create_multi_line_string(*
|
157
|
-
create_collection(:multi_line_string, *
|
205
|
+
def create_multi_line_string(*args)
|
206
|
+
create_collection(:multi_line_string, *args)
|
158
207
|
end
|
159
208
|
|
160
|
-
def create_multi_polygon(*
|
161
|
-
create_collection(:multi_polygon, *
|
209
|
+
def create_multi_polygon(*args)
|
210
|
+
create_collection(:multi_polygon, *args)
|
162
211
|
end
|
163
212
|
|
164
|
-
def create_geometry_collection(*
|
165
|
-
create_collection(:geometry_collection, *
|
213
|
+
def create_geometry_collection(*args)
|
214
|
+
create_collection(:geometry_collection, *args)
|
166
215
|
end
|
167
216
|
|
168
217
|
private
|
169
|
-
def
|
170
|
-
case
|
218
|
+
def cs_from_cs_or_geom(geom_or_cs)
|
219
|
+
case geom_or_cs
|
220
|
+
when Array
|
221
|
+
Geos::CoordinateSequence.new(geom_or_cs)
|
222
|
+
when Geos::CoordinateSequence
|
223
|
+
geom_or_cs.dup
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def force_to_linear_ring(geom_or_cs)
|
228
|
+
case geom_or_cs
|
171
229
|
when Geos::CoordinateSequence
|
172
|
-
|
230
|
+
geom_or_cs.to_linear_ring
|
173
231
|
when Geos::LinearRing
|
174
|
-
|
232
|
+
geom_or_cs.dup
|
175
233
|
end
|
176
234
|
end
|
177
235
|
end
|