ffi-geos 0.0.1 → 0.0.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.
- data/README.rdoc +4 -5
- data/VERSION +1 -1
- data/ffi-geos.gemspec +3 -3
- data/lib/ffi-geos.rb +2 -2
- data/lib/ffi-geos/coordinate_sequence.rb +54 -4
- data/lib/ffi-geos/geometry_collection.rb +9 -3
- data/lib/ffi-geos/line_string.rb +9 -3
- data/lib/ffi-geos/strtree.rb +91 -29
- data/lib/ffi-geos/utils.rb +16 -7
- data/test/coordinate_sequence_tests.rb +92 -6
- data/test/geometry_tests.rb +14 -0
- data/test/strtree_tests.rb +143 -8
- data/test/utils_tests.rb +37 -32
- metadata +21 -38
data/README.rdoc
CHANGED
@@ -12,12 +12,11 @@ Ruby versions known to work:
|
|
12
12
|
* Ruby MRI 1.8.7 and 1.9.2, x86_64, OSX 10.6.5+
|
13
13
|
* Ruby MRI 1.8.7 and 1.9.2, i386, linux
|
14
14
|
* Ruby MRI 1.8.7, x86_64, linux
|
15
|
+
* JRuby 1.6.3, x86_64 OSX 10.6.5+
|
15
16
|
|
16
|
-
Note that versions of JRuby prior to
|
17
|
-
|
18
|
-
|
19
|
-
versions of JRuby should have the problem licked. For details, check out
|
20
|
-
http://jira.codehaus.org/browse/JRUBY-5813.
|
17
|
+
Note that versions of JRuby prior to version 1.6.3 have problems in their ffi
|
18
|
+
implementation when dealing with AutoPointers that can lead to segfaults during
|
19
|
+
garbage collection.
|
21
20
|
|
22
21
|
== Features
|
23
22
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/ffi-geos.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ffi-geos}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["J Smith"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-07-22}
|
13
13
|
s.description = %q{An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).}
|
14
14
|
s.email = %q{dark.panda@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -56,7 +56,7 @@ Gem::Specification.new do |s|
|
|
56
56
|
]
|
57
57
|
s.homepage = %q{http://github.com/dark-panda/ffi-geos}
|
58
58
|
s.require_paths = ["lib"]
|
59
|
-
s.rubygems_version = %q{1.
|
59
|
+
s.rubygems_version = %q{1.6.2}
|
60
60
|
s.summary = %q{An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).}
|
61
61
|
|
62
62
|
if s.respond_to? :specification_version then
|
data/lib/ffi-geos.rb
CHANGED
@@ -1026,10 +1026,10 @@ module Geos
|
|
1026
1026
|
VERSION = File.read(File.join(GEOS_BASE, %w{ .. .. VERSION })).strip
|
1027
1027
|
GEOS_JTS_PORT = Geos.jts_port
|
1028
1028
|
GEOS_VERSION,
|
1029
|
-
GEOS_VERSION_MAJOR, GEOS_VERSION_MINOR,
|
1029
|
+
GEOS_VERSION_MAJOR, GEOS_VERSION_MINOR, GEOS_VERSION_PATCH, GEOS_VERSION_PRERELEASE,
|
1030
1030
|
GEOS_CAPI_VERSION,
|
1031
1031
|
GEOS_CAPI_VERSION_MAJOR, GEOS_CAPI_VERSION_MINOR, GEOS_CAPI_VERSION_PATCH =
|
1032
|
-
if !(versions = Geos.version.scan(/^((\d+)\.(\d+)\.(\d+)((?:rc|beta|alpha)\d
|
1032
|
+
if !(versions = Geos.version.scan(/^((\d+)\.(\d+)\.(\d+)((?:dev|rc|beta|alpha)\d*)?)-CAPI-((\d+)\.(\d+)\.(\d+))$/)).empty?
|
1033
1033
|
versions = versions[0]
|
1034
1034
|
[
|
1035
1035
|
versions[0],
|
@@ -3,23 +3,53 @@ module Geos
|
|
3
3
|
|
4
4
|
# A CoordinateSequence is a list of coordinates in a Geometry.
|
5
5
|
class CoordinateSequence
|
6
|
+
class ParseError < ArgumentError
|
7
|
+
end
|
8
|
+
|
6
9
|
include Enumerable
|
7
10
|
|
8
11
|
attr_reader :ptr
|
9
12
|
|
10
13
|
# :call-seq:
|
11
14
|
# new(ptr, auto_free = true)
|
12
|
-
# new(size, dims = 0)
|
15
|
+
# new(size = 0, dims = 0)
|
16
|
+
# new(points)
|
13
17
|
#
|
14
18
|
# The ptr version of the initializer is for internal use.
|
19
|
+
#
|
20
|
+
# new(points) will try to glean the size and dimensions of your
|
21
|
+
# CoordinateSequence from an Array of points. The Array should contain
|
22
|
+
# uniform-sized Arrays which represent the [ x, y, z ] values of your
|
23
|
+
# coordinates.
|
15
24
|
def initialize(*args)
|
25
|
+
points = nil # forward declaration we can use later
|
26
|
+
|
16
27
|
ptr, auto_free = if args.first.is_a?(FFI::Pointer)
|
17
28
|
[ args.first, args[1] ]
|
18
29
|
else
|
19
|
-
size, dims = if
|
20
|
-
|
30
|
+
size, dims = if args.first.is_a?(Array)
|
31
|
+
points = if args.first.first.is_a?(Array)
|
32
|
+
args.first
|
33
|
+
else
|
34
|
+
args
|
35
|
+
end
|
36
|
+
lengths = points.collect(&:length).uniq
|
37
|
+
|
38
|
+
if lengths.empty?
|
39
|
+
[ 0, 0 ]
|
40
|
+
elsif lengths.length != 1
|
41
|
+
raise ParseError.new("Different sized points found in Array")
|
42
|
+
elsif !lengths.first.between?(1, 3)
|
43
|
+
raise ParseError.new("Expected points to contain 1-3 elements")
|
44
|
+
else
|
45
|
+
[ points.length, points.first.length ]
|
46
|
+
end
|
21
47
|
else
|
22
|
-
|
48
|
+
if !args.length.between?(0, 2)
|
49
|
+
raise ArgumentError.new("wrong number of arguments (#{args.length} for 0-2)")
|
50
|
+
else
|
51
|
+
[ args[0] || 0, args[1] || 0 ]
|
52
|
+
end
|
23
53
|
end
|
24
54
|
|
25
55
|
[ FFIGeos.GEOSCoordSeq_create_r(Geos.current_handle, size, dims), true ]
|
@@ -33,6 +63,14 @@ module Geos
|
|
33
63
|
if !auto_free
|
34
64
|
@ptr.autorelease = false
|
35
65
|
end
|
66
|
+
|
67
|
+
if points
|
68
|
+
points.each_with_index do |point, idx|
|
69
|
+
point.each_with_index do |val, dim|
|
70
|
+
self.set_ordinate(idx, dim, val)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
36
74
|
end
|
37
75
|
|
38
76
|
def initialize_copy(source)
|
@@ -122,6 +160,18 @@ module Geos
|
|
122
160
|
}.read_int
|
123
161
|
end
|
124
162
|
|
163
|
+
def to_linear_ring
|
164
|
+
Geos.create_linear_ring(self)
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_line_string
|
168
|
+
Geos.create_line_string(self)
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_polygon
|
172
|
+
Geos.create_polygon(self)
|
173
|
+
end
|
174
|
+
|
125
175
|
protected
|
126
176
|
|
127
177
|
def check_bounds(idx) #:nodoc:
|
@@ -5,10 +5,16 @@ module Geos
|
|
5
5
|
|
6
6
|
# Yields each Geometry in the GeometryCollection.
|
7
7
|
def each
|
8
|
-
|
9
|
-
|
8
|
+
if block_given?
|
9
|
+
self.num_geometries.times do |n|
|
10
|
+
yield self.get_geometry_n(n)
|
11
|
+
end
|
12
|
+
self
|
13
|
+
else
|
14
|
+
self.num_geometries.times.collect { |n|
|
15
|
+
self.get_geometry_n(n)
|
16
|
+
}.to_enum
|
10
17
|
end
|
11
|
-
nil
|
12
18
|
end
|
13
19
|
|
14
20
|
def get_geometry_n(n)
|
data/lib/ffi-geos/line_string.rb
CHANGED
@@ -4,10 +4,16 @@ module Geos
|
|
4
4
|
include Enumerable
|
5
5
|
|
6
6
|
def each
|
7
|
-
|
8
|
-
|
7
|
+
if block_given?
|
8
|
+
self.num_points.times do |n|
|
9
|
+
yield self.point_n(n)
|
10
|
+
end
|
11
|
+
self
|
12
|
+
else
|
13
|
+
self.num_points.times.collect { |n|
|
14
|
+
self.point_n(n)
|
15
|
+
}.to_enum
|
9
16
|
end
|
10
|
-
nil
|
11
17
|
end
|
12
18
|
|
13
19
|
if FFIGeos.respond_to?(:GEOSGeomGetNumPoints_r)
|
data/lib/ffi-geos/strtree.rb
CHANGED
@@ -8,7 +8,33 @@ module Geos
|
|
8
8
|
|
9
9
|
undef :clone, :dup
|
10
10
|
|
11
|
-
|
11
|
+
# :call-seq:
|
12
|
+
# new(capacity)
|
13
|
+
# new(geoms_and_objects)
|
14
|
+
#
|
15
|
+
def initialize(*args)
|
16
|
+
geoms_and_objects = nil # forward declaration
|
17
|
+
|
18
|
+
capacity = if args.length == 1 && args.first.is_a?(Fixnum)
|
19
|
+
args.first
|
20
|
+
else
|
21
|
+
geoms_and_objects = if args.first.first.is_a?(Array)
|
22
|
+
args.first
|
23
|
+
else
|
24
|
+
args
|
25
|
+
end
|
26
|
+
|
27
|
+
geoms_and_objects.each do |geom, obj|
|
28
|
+
check_geometry(geom)
|
29
|
+
end
|
30
|
+
|
31
|
+
geoms_and_objects.length
|
32
|
+
end
|
33
|
+
|
34
|
+
if capacity <= 0
|
35
|
+
raise ArgumentError.new("STRtree capacity must be greater than 0")
|
36
|
+
end
|
37
|
+
|
12
38
|
ptr = FFIGeos.GEOSSTRtree_create_r(Geos.current_handle, capacity)
|
13
39
|
|
14
40
|
@ptr = FFI::AutoPointer.new(
|
@@ -17,9 +43,16 @@ module Geos
|
|
17
43
|
)
|
18
44
|
|
19
45
|
@storage = {}
|
20
|
-
@
|
46
|
+
@ptrs = {}
|
47
|
+
|
21
48
|
@storage_key = 0
|
22
49
|
@built = false
|
50
|
+
|
51
|
+
if geoms_and_objects
|
52
|
+
geoms_and_objects.each do |geom, obj|
|
53
|
+
self.insert(geom, obj)
|
54
|
+
end
|
55
|
+
end
|
23
56
|
end
|
24
57
|
|
25
58
|
def self.release(ptr) #:nodoc:
|
@@ -36,17 +69,21 @@ module Geos
|
|
36
69
|
private :next_key
|
37
70
|
|
38
71
|
def insert(geom, item)
|
39
|
-
check_geometry(geom)
|
40
|
-
|
41
72
|
if self.built?
|
42
73
|
raise RuntimeError.new("STRtree has already been built")
|
43
74
|
else
|
75
|
+
check_geometry(geom)
|
76
|
+
|
44
77
|
key = next_key
|
45
78
|
key_ptr = FFI::MemoryPointer.new(:pointer)
|
46
79
|
key_ptr.write_int(key)
|
47
80
|
|
48
|
-
@storage[key] =
|
49
|
-
|
81
|
+
@storage[key] = {
|
82
|
+
:item => item,
|
83
|
+
:geometry => geom
|
84
|
+
}
|
85
|
+
@ptrs[key] = key_ptr
|
86
|
+
|
50
87
|
FFIGeos.GEOSSTRtree_insert_r(Geos.current_handle, self.ptr, geom.ptr, key_ptr)
|
51
88
|
end
|
52
89
|
end
|
@@ -54,41 +91,36 @@ module Geos
|
|
54
91
|
def remove(geom, item)
|
55
92
|
check_geometry(geom)
|
56
93
|
|
57
|
-
key = if @storage.
|
58
|
-
|
59
|
-
else
|
60
|
-
@storage.index(item)
|
94
|
+
key = if storage = @storage.detect { |k, v| v[:item] == item }
|
95
|
+
storage[0]
|
61
96
|
end
|
62
97
|
|
63
98
|
if key
|
64
|
-
key_ptr = @
|
99
|
+
key_ptr = @ptrs[key]
|
65
100
|
result = FFIGeos.GEOSSTRtree_remove_r(Geos.current_handle, self.ptr, geom.ptr, key_ptr)
|
66
101
|
@built = true
|
67
102
|
|
68
103
|
if result == 1
|
69
|
-
@storage
|
70
|
-
@storage_pointers[key] = nil
|
104
|
+
@storage.delete(key)
|
71
105
|
end
|
72
106
|
end
|
73
107
|
end
|
74
108
|
|
75
|
-
def
|
109
|
+
def query_all(geom)
|
76
110
|
check_geometry(geom)
|
77
111
|
|
78
112
|
@built = true
|
79
|
-
retval =
|
113
|
+
retval = []
|
80
114
|
|
81
|
-
callback =
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
}
|
91
|
-
end
|
115
|
+
callback = proc { |*args|
|
116
|
+
key = args.first.read_int
|
117
|
+
storage = @storage[key]
|
118
|
+
retval << storage
|
119
|
+
|
120
|
+
if block_given?
|
121
|
+
yield(storage)
|
122
|
+
end
|
123
|
+
}
|
92
124
|
|
93
125
|
FFIGeos.GEOSSTRtree_query_r(
|
94
126
|
Geos.current_handle,
|
@@ -98,12 +130,42 @@ module Geos
|
|
98
130
|
nil
|
99
131
|
)
|
100
132
|
|
101
|
-
if retval
|
102
|
-
retval.compact
|
103
|
-
end
|
104
133
|
retval
|
105
134
|
end
|
106
135
|
|
136
|
+
def query(geom, ret = :item)
|
137
|
+
self.query_all(geom).collect { |storage|
|
138
|
+
item = if ret.is_a?(Array)
|
139
|
+
storage.inject({}) do |memo, k|
|
140
|
+
memo.tap {
|
141
|
+
memo[k] = storage[k]
|
142
|
+
}
|
143
|
+
end
|
144
|
+
elsif ret == :all
|
145
|
+
storage
|
146
|
+
else
|
147
|
+
storage[ret]
|
148
|
+
end
|
149
|
+
|
150
|
+
item.tap {
|
151
|
+
if block_given?
|
152
|
+
yield(item)
|
153
|
+
end
|
154
|
+
}
|
155
|
+
}.compact
|
156
|
+
end
|
157
|
+
|
158
|
+
def query_geometries(geom)
|
159
|
+
self.query_all(geom).collect { |storage|
|
160
|
+
storage[:geometry].tap { |val|
|
161
|
+
if block_given?
|
162
|
+
yield(val)
|
163
|
+
end
|
164
|
+
}
|
165
|
+
}.compact
|
166
|
+
end
|
167
|
+
alias :query_geoms :query_geometries
|
168
|
+
|
107
169
|
def iterate
|
108
170
|
@storage.values.each do |v|
|
109
171
|
yield(v)
|
data/lib/ffi-geos/utils.rb
CHANGED
@@ -63,16 +63,15 @@ module Geos
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def create_polygon(outer, *inner)
|
66
|
-
|
67
|
-
|
68
|
-
raise TypeError.new("Expected inner Array to contain
|
69
|
-
end
|
66
|
+
inner_clones = Array(inner).flatten.collect { |i|
|
67
|
+
force_to_linear_ring(i) or
|
68
|
+
raise TypeError.new("Expected inner Array to contain Geos::LinearRing or Geos::CoordinateSequence objects")
|
70
69
|
}
|
71
70
|
|
72
|
-
outer_clone = outer
|
73
|
-
|
71
|
+
outer_clone = force_to_linear_ring(outer) or
|
72
|
+
raise TypeError.new("Expected outer shell to be a Geos::LinearRing or Geos::CoordinateSequence")
|
74
73
|
|
75
|
-
ary = FFI::MemoryPointer.new(:pointer,
|
74
|
+
ary = FFI::MemoryPointer.new(:pointer, inner_clones.length)
|
76
75
|
ary.write_array_of_pointer(inner_clones.map(&:ptr))
|
77
76
|
|
78
77
|
cast_geometry_ptr(FFIGeos.GEOSGeom_createPolygon_r(Geos.current_handle, outer_clone.ptr, ary, inner_clones.length)).tap {
|
@@ -161,6 +160,16 @@ module Geos
|
|
161
160
|
def create_geometry_collection(*geoms)
|
162
161
|
create_collection(:geometry_collection, *geoms)
|
163
162
|
end
|
163
|
+
|
164
|
+
private
|
165
|
+
def force_to_linear_ring(geom)
|
166
|
+
case geom
|
167
|
+
when Geos::CoordinateSequence
|
168
|
+
geom.to_linear_ring
|
169
|
+
when Geos::LinearRing
|
170
|
+
geom.clone
|
171
|
+
end
|
172
|
+
end
|
164
173
|
end
|
165
174
|
end
|
166
175
|
end
|
@@ -7,21 +7,22 @@ class CoordinateSequenceTests < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
def setup
|
9
9
|
@cs = Geos::CoordinateSequence.new(3, 0)
|
10
|
+
super
|
10
11
|
end
|
11
12
|
|
12
13
|
def test_set_and_get_x
|
13
14
|
@cs.set_x(0, 10.01)
|
14
|
-
assert_in_delta(10.01, @cs.get_x(0),
|
15
|
+
assert_in_delta(10.01, @cs.get_x(0), TOLERANCE)
|
15
16
|
end
|
16
17
|
|
17
18
|
def test_set_and_get_y
|
18
19
|
@cs.set_y(0, 20.02)
|
19
|
-
assert_in_delta(20.02, @cs.get_y(0),
|
20
|
+
assert_in_delta(20.02, @cs.get_y(0), TOLERANCE)
|
20
21
|
end
|
21
22
|
|
22
23
|
def test_set_and_get_z
|
23
24
|
@cs.set_z(0, 20.02)
|
24
|
-
assert_in_delta(20.02, @cs.get_z(0),
|
25
|
+
assert_in_delta(20.02, @cs.get_z(0), TOLERANCE)
|
25
26
|
end
|
26
27
|
|
27
28
|
def test_set_and_get_ordinate
|
@@ -29,9 +30,9 @@ class CoordinateSequenceTests < Test::Unit::TestCase
|
|
29
30
|
@cs.set_ordinate(0, 1, 20.02)
|
30
31
|
@cs.set_ordinate(0, 2, 30.03)
|
31
32
|
|
32
|
-
assert_in_delta(10.01, @cs.get_ordinate(0, 0),
|
33
|
-
assert_in_delta(20.02, @cs.get_ordinate(0, 1),
|
34
|
-
assert_in_delta(30.03, @cs.get_ordinate(0, 2),
|
33
|
+
assert_in_delta(10.01, @cs.get_ordinate(0, 0), TOLERANCE)
|
34
|
+
assert_in_delta(20.02, @cs.get_ordinate(0, 1), TOLERANCE)
|
35
|
+
assert_in_delta(30.03, @cs.get_ordinate(0, 2), TOLERANCE)
|
35
36
|
end
|
36
37
|
|
37
38
|
def test_length
|
@@ -89,4 +90,89 @@ class CoordinateSequenceTests < Test::Unit::TestCase
|
|
89
90
|
assert_equal(@cs.get_y(0), cs_b.get_y(0))
|
90
91
|
assert_equal(@cs.dimensions, cs_b.dimensions)
|
91
92
|
end
|
93
|
+
|
94
|
+
def test_with_no_arguments
|
95
|
+
cs = Geos::CoordinateSequence.new
|
96
|
+
assert_equal(0, cs.size)
|
97
|
+
assert_equal(3, cs.dimensions)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_read_from_array
|
101
|
+
cs = Geos::CoordinateSequence.new([
|
102
|
+
[ 0, 0 ],
|
103
|
+
[ 1, 1 ],
|
104
|
+
[ 2, 2 ],
|
105
|
+
[ 3, 3 ],
|
106
|
+
[ 4, 4 ]
|
107
|
+
])
|
108
|
+
|
109
|
+
assert_equal(2, cs.dimensions)
|
110
|
+
assert_equal(5, cs.length)
|
111
|
+
|
112
|
+
assert_raise(Geos::CoordinateSequence::ParseError) do
|
113
|
+
cs = Geos::CoordinateSequence.new([
|
114
|
+
[ 1, 2 ],
|
115
|
+
[ 1, 2, 3 ]
|
116
|
+
])
|
117
|
+
end
|
118
|
+
|
119
|
+
assert_raise(Geos::CoordinateSequence::ParseError) do
|
120
|
+
cs = Geos::CoordinateSequence.new([
|
121
|
+
[ 1, 2, 3, 4 ]
|
122
|
+
])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_to_to_linear_ring
|
127
|
+
cs = Geos::CoordinateSequence.new([
|
128
|
+
[ 0, 0 ],
|
129
|
+
[ 0, 5 ],
|
130
|
+
[ 5, 5 ],
|
131
|
+
[ 5, 0 ],
|
132
|
+
[ 0, 0 ]
|
133
|
+
])
|
134
|
+
|
135
|
+
assert_equal('LINEARRING (0 0, 0 5, 5 5, 5 0, 0 0)', write(cs.to_linear_ring, :trim => true))
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_to_empty_linear_ring
|
139
|
+
cs = Geos::CoordinateSequence.new
|
140
|
+
|
141
|
+
assert_equal('LINEARRING EMPTY', write(cs.to_linear_ring, :trim => true))
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_to_line_string
|
145
|
+
cs = Geos::CoordinateSequence.new([
|
146
|
+
[ 0, 0 ],
|
147
|
+
[ 0, 5 ],
|
148
|
+
[ 5, 5 ],
|
149
|
+
[ 5, 0 ]
|
150
|
+
])
|
151
|
+
|
152
|
+
assert_equal('LINESTRING (0 0, 0 5, 5 5, 5 0)', write(cs.to_line_string, :trim => true))
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_to_empty_line_string
|
156
|
+
cs = Geos::CoordinateSequence.new
|
157
|
+
|
158
|
+
assert_equal('LINESTRING EMPTY', write(cs.to_line_string, :trim => true))
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_to_polygon
|
162
|
+
cs = Geos::CoordinateSequence.new([
|
163
|
+
[ 0, 0 ],
|
164
|
+
[ 0, 5 ],
|
165
|
+
[ 5, 5 ],
|
166
|
+
[ 5, 0 ],
|
167
|
+
[ 0, 0 ]
|
168
|
+
])
|
169
|
+
|
170
|
+
assert_equal('POLYGON ((0 0, 0 5, 5 5, 5 0, 0 0))', write(cs.to_polygon, :trim => true))
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_to_empty_polygon
|
174
|
+
cs = Geos::CoordinateSequence.new
|
175
|
+
|
176
|
+
assert_equal('POLYGON EMPTY', write(cs.to_polygon, :trim => true))
|
177
|
+
end
|
92
178
|
end
|
data/test/geometry_tests.rb
CHANGED
@@ -1530,4 +1530,18 @@ class GeometryTests < Test::Unit::TestCase
|
|
1530
1530
|
|
1531
1531
|
assert(geom_a.eql?(geom_b))
|
1532
1532
|
end
|
1533
|
+
|
1534
|
+
def test_geometry_collection_enumerator
|
1535
|
+
geom = read('GEOMETRYCOLLECTION(POINT(0 0))')
|
1536
|
+
assert_kind_of(Enumerable, geom.each)
|
1537
|
+
assert_kind_of(Enumerable, geom.to_enum)
|
1538
|
+
assert_equal(geom, geom.each {})
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
def test_line_string_enumerator
|
1542
|
+
geom = read('LINESTRING(0 0, 10 10))')
|
1543
|
+
assert_kind_of(Enumerable, geom.each)
|
1544
|
+
assert_kind_of(Enumerable, geom.to_enum)
|
1545
|
+
assert_equal(geom, geom.each {})
|
1546
|
+
end
|
1533
1547
|
end
|
data/test/strtree_tests.rb
CHANGED
@@ -34,10 +34,106 @@ if defined?(Geos::STRtree)
|
|
34
34
|
def test_query
|
35
35
|
setup_tree
|
36
36
|
|
37
|
-
assert_equal(
|
38
|
-
|
39
|
-
|
40
|
-
assert_equal(
|
37
|
+
assert_equal([@item_1],
|
38
|
+
@tree.query(read('LINESTRING(5 5, 6 6)')))
|
39
|
+
|
40
|
+
assert_equal([],
|
41
|
+
@tree.query(read('LINESTRING(20 0, 30 10)')))
|
42
|
+
|
43
|
+
assert_equal([@item_2, @item_3],
|
44
|
+
@tree.query(read('LINESTRING(25 25, 26 26)')))
|
45
|
+
|
46
|
+
assert_equal([@item_1, @item_2, @item_3],
|
47
|
+
@tree.query(read('LINESTRING(0 0, 100 100)')))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_query_with_ret_keys
|
51
|
+
setup_tree
|
52
|
+
|
53
|
+
assert_equal([@item_1],
|
54
|
+
@tree.query(read('LINESTRING(5 5, 6 6)'), :item))
|
55
|
+
|
56
|
+
assert_equal([],
|
57
|
+
@tree.query(read('LINESTRING(20 0, 30 10)'), :item))
|
58
|
+
|
59
|
+
assert_equal([@item_2, @item_3],
|
60
|
+
@tree.query(read('LINESTRING(25 25, 26 26)'), :item))
|
61
|
+
|
62
|
+
assert_equal([@item_1, @item_2, @item_3],
|
63
|
+
@tree.query(read('LINESTRING(0 0, 100 100)'), :item))
|
64
|
+
|
65
|
+
|
66
|
+
assert_equal([@geom_1],
|
67
|
+
@tree.query(read('LINESTRING(5 5, 6 6)'), :geometry))
|
68
|
+
|
69
|
+
assert_equal([],
|
70
|
+
@tree.query(read('LINESTRING(20 0, 30 10)'), :geometry))
|
71
|
+
|
72
|
+
assert_equal([@geom_2, @geom_3],
|
73
|
+
@tree.query(read('LINESTRING(25 25, 26 26)'), :geometry))
|
74
|
+
|
75
|
+
assert_equal([@geom_1, @geom_2, @geom_3],
|
76
|
+
@tree.query(read('LINESTRING(0 0, 100 100)'), :geometry))
|
77
|
+
|
78
|
+
|
79
|
+
assert_equal(
|
80
|
+
[
|
81
|
+
{ :item => @item_1, :geometry => @geom_1 }
|
82
|
+
],
|
83
|
+
@tree.query(read('LINESTRING(5 5, 6 6)'), :all)
|
84
|
+
)
|
85
|
+
|
86
|
+
assert_equal([],
|
87
|
+
@tree.query(read('LINESTRING(20 0, 30 10)'), :all))
|
88
|
+
|
89
|
+
assert_equal(
|
90
|
+
[
|
91
|
+
{ :item => @item_2, :geometry => @geom_2 },
|
92
|
+
{ :item => @item_3, :geometry => @geom_3 }
|
93
|
+
],
|
94
|
+
@tree.query(read('LINESTRING(25 25, 26 26)'), :all)
|
95
|
+
)
|
96
|
+
|
97
|
+
assert_equal(
|
98
|
+
[
|
99
|
+
{ :item => @item_1, :geometry => @geom_1 },
|
100
|
+
{ :item => @item_2, :geometry => @geom_2 },
|
101
|
+
{ :item => @item_3, :geometry => @geom_3 }
|
102
|
+
],
|
103
|
+
@tree.query(read('LINESTRING(0 0, 100 100)'), :all)
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_query_all
|
108
|
+
setup_tree
|
109
|
+
|
110
|
+
assert_equal([@item_1],
|
111
|
+
@tree.query_all(read('LINESTRING(5 5, 6 6)')).collect { |v| v[:item] })
|
112
|
+
|
113
|
+
assert_equal([],
|
114
|
+
@tree.query_all(read('LINESTRING(20 0, 30 10)')))
|
115
|
+
|
116
|
+
assert_equal([@item_2, @item_3],
|
117
|
+
@tree.query_all(read('LINESTRING(25 25, 26 26)')).collect { |v| v[:item] })
|
118
|
+
|
119
|
+
assert_equal([@item_1, @item_2, @item_3],
|
120
|
+
@tree.query_all(read('LINESTRING(0 0, 100 100)')).collect { |v| v[:item] })
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_query_geometries
|
124
|
+
setup_tree
|
125
|
+
|
126
|
+
assert_equal([@geom_1],
|
127
|
+
@tree.query_geometries(read('LINESTRING(5 5, 6 6)')))
|
128
|
+
|
129
|
+
assert_equal([],
|
130
|
+
@tree.query_geometries(read('LINESTRING(20 0, 30 10)')))
|
131
|
+
|
132
|
+
assert_equal([@geom_2, @geom_3],
|
133
|
+
@tree.query_geometries(read('LINESTRING(25 25, 26 26)')))
|
134
|
+
|
135
|
+
assert_equal([@geom_1, @geom_2, @geom_3],
|
136
|
+
@tree.query_geometries(read('LINESTRING(0 0, 100 100)')))
|
41
137
|
end
|
42
138
|
|
43
139
|
def test_remove
|
@@ -45,10 +141,17 @@ if defined?(Geos::STRtree)
|
|
45
141
|
|
46
142
|
@tree.remove(read('POINT(5 5)'), @item_1)
|
47
143
|
|
48
|
-
assert_equal(
|
49
|
-
|
50
|
-
|
51
|
-
assert_equal(
|
144
|
+
assert_equal([],
|
145
|
+
@tree.query(read('LINESTRING(5 5, 6 6)')))
|
146
|
+
|
147
|
+
assert_equal([],
|
148
|
+
@tree.query(read('LINESTRING(20 0, 30 10)')))
|
149
|
+
|
150
|
+
assert_equal([@item_2, @item_3],
|
151
|
+
@tree.query(read('LINESTRING(25 25, 26 26)')))
|
152
|
+
|
153
|
+
assert_equal([@item_2, @item_3],
|
154
|
+
@tree.query(read('LINESTRING(0 0, 100 100)')))
|
52
155
|
end
|
53
156
|
|
54
157
|
def test_cant_clone
|
@@ -62,5 +165,37 @@ if defined?(Geos::STRtree)
|
|
62
165
|
Geos::STRtree.new(3).dup
|
63
166
|
end
|
64
167
|
end
|
168
|
+
|
169
|
+
def test_setup_with_array
|
170
|
+
tree = Geos::STRtree.new(
|
171
|
+
[ read('LINESTRING(0 0, 10 10)'), item_1 = { :item_1 => :test } ],
|
172
|
+
[ read('LINESTRING(20 20, 30 30)'), item_2 = [ :test ] ],
|
173
|
+
[ read('LINESTRING(20 20, 30 30)'), item_3 = Object.new ]
|
174
|
+
)
|
175
|
+
|
176
|
+
assert_equal([item_1],
|
177
|
+
tree.query(read('LINESTRING(5 5, 6 6)')))
|
178
|
+
|
179
|
+
assert_equal([],
|
180
|
+
tree.query(read('LINESTRING(20 0, 30 10)')))
|
181
|
+
|
182
|
+
assert_equal([item_2, item_3],
|
183
|
+
tree.query(read('LINESTRING(25 25, 26 26)')))
|
184
|
+
|
185
|
+
assert_equal([item_1, item_2, item_3],
|
186
|
+
tree.query(read('LINESTRING(0 0, 100 100)')))
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_capacity
|
190
|
+
assert_raise(ArgumentError) do
|
191
|
+
Geos::STRtree.new(0)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_geometries
|
196
|
+
assert_raise(TypeError) do
|
197
|
+
Geos::STRtree.new([])
|
198
|
+
end
|
199
|
+
end
|
65
200
|
end
|
66
201
|
end
|
data/test/utils_tests.rb
CHANGED
@@ -131,66 +131,71 @@ class UtilsTests < Test::Unit::TestCase
|
|
131
131
|
end
|
132
132
|
|
133
133
|
def test_create_polygon
|
134
|
-
cs = Geos::CoordinateSequence.new(
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
134
|
+
cs = Geos::CoordinateSequence.new([
|
135
|
+
[ 0, 0 ],
|
136
|
+
[ 0, 10 ],
|
137
|
+
[ 10, 10 ],
|
138
|
+
[ 10, 0 ],
|
139
|
+
[ 0, 0 ]
|
140
|
+
])
|
140
141
|
|
141
|
-
cs
|
142
|
-
cs.set_y(2, 10)
|
142
|
+
exterior_ring = Geos::create_linear_ring(cs)
|
143
143
|
|
144
|
-
|
145
|
-
|
144
|
+
geom = Geos::create_polygon(exterior_ring)
|
145
|
+
assert_instance_of(Geos::Polygon, geom)
|
146
|
+
assert_equal('Polygon', geom.geom_type)
|
147
|
+
assert_equal(Geos::GEOS_POLYGON, geom.type_id)
|
148
|
+
assert_equal('POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))', write(geom, :trim => true))
|
149
|
+
end
|
146
150
|
|
147
|
-
|
148
|
-
|
151
|
+
def test_create_polygon_with_coordinate_sequences
|
152
|
+
outer = Geos::CoordinateSequence.new(
|
153
|
+
[ 0, 0 ],
|
154
|
+
[ 0, 10 ],
|
155
|
+
[ 10, 10 ],
|
156
|
+
[ 10, 0 ],
|
157
|
+
[ 0, 0 ]
|
158
|
+
)
|
149
159
|
|
150
|
-
|
160
|
+
inner = Geos::CoordinateSequence.new(
|
161
|
+
[ 2, 2 ],
|
162
|
+
[ 2, 4 ],
|
163
|
+
[ 4, 4 ],
|
164
|
+
[ 4, 2 ],
|
165
|
+
[ 2, 2 ]
|
166
|
+
)
|
151
167
|
|
152
|
-
geom = Geos::create_polygon(
|
168
|
+
geom = Geos::create_polygon(outer, inner)
|
153
169
|
assert_instance_of(Geos::Polygon, geom)
|
154
170
|
assert_equal('Polygon', geom.geom_type)
|
155
171
|
assert_equal(Geos::GEOS_POLYGON, geom.type_id)
|
156
|
-
|
172
|
+
assert_equal('POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 4, 4 4, 4 2, 2 2))', write(geom, :trim => true))
|
157
173
|
end
|
158
174
|
|
159
175
|
def test_create_polygon_with_holes
|
160
|
-
|
161
|
-
Geos.create_linear_ring(
|
162
|
-
Geos::CoordinateSequence.new(points.length, 2).tap { |cs|
|
163
|
-
points.each_with_index do |(x, y), i|
|
164
|
-
cs.set_x(i, x)
|
165
|
-
cs.set_y(i, y)
|
166
|
-
end
|
167
|
-
}
|
168
|
-
)
|
169
|
-
}
|
170
|
-
|
171
|
-
exterior_ring = create_ring[
|
176
|
+
exterior_ring = Geos::CoordinateSequence.new(
|
172
177
|
[ 0, 0 ],
|
173
178
|
[ 0, 10 ],
|
174
179
|
[ 10, 10 ],
|
175
180
|
[ 10, 0 ],
|
176
181
|
[ 0, 0 ]
|
177
|
-
|
182
|
+
)
|
178
183
|
|
179
|
-
hole_1 =
|
184
|
+
hole_1 = Geos::CoordinateSequence.new(
|
180
185
|
[ 2, 2 ],
|
181
186
|
[ 2, 4 ],
|
182
187
|
[ 4, 4 ],
|
183
188
|
[ 4, 2 ],
|
184
189
|
[ 2, 2 ]
|
185
|
-
|
190
|
+
)
|
186
191
|
|
187
|
-
hole_2 =
|
192
|
+
hole_2 = Geos::CoordinateSequence.new(
|
188
193
|
[ 6, 6 ],
|
189
194
|
[ 6, 8 ],
|
190
195
|
[ 8, 8 ],
|
191
196
|
[ 8, 6 ],
|
192
197
|
[ 6, 6 ]
|
193
|
-
|
198
|
+
)
|
194
199
|
|
195
200
|
geom = Geos::create_polygon(exterior_ring, [ hole_1, hole_2 ])
|
196
201
|
assert_instance_of(Geos::Polygon, geom)
|
metadata
CHANGED
@@ -1,32 +1,24 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-geos
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- J Smith
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
12
|
+
date: 2011-07-22 00:00:00.000000000 -04:00
|
13
|
+
default_executable:
|
19
14
|
dependencies: []
|
20
|
-
|
21
15
|
description: An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).
|
22
16
|
email: dark.panda@gmail.com
|
23
17
|
executables: []
|
24
|
-
|
25
18
|
extensions: []
|
26
|
-
|
27
|
-
extra_rdoc_files:
|
19
|
+
extra_rdoc_files:
|
28
20
|
- README.rdoc
|
29
|
-
files:
|
21
|
+
files:
|
30
22
|
- MIT-LICENSE
|
31
23
|
- README.rdoc
|
32
24
|
- Rakefile
|
@@ -64,38 +56,29 @@ files:
|
|
64
56
|
- test/wkb_writer_tests.rb
|
65
57
|
- test/wkt_reader_tests.rb
|
66
58
|
- test/wkt_writer_tests.rb
|
59
|
+
has_rdoc: true
|
67
60
|
homepage: http://github.com/dark-panda/ffi-geos
|
68
61
|
licenses: []
|
69
|
-
|
70
62
|
post_install_message:
|
71
63
|
rdoc_options: []
|
72
|
-
|
73
|
-
require_paths:
|
64
|
+
require_paths:
|
74
65
|
- lib
|
75
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
67
|
none: false
|
77
|
-
requirements:
|
78
|
-
- -
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
|
81
|
-
|
82
|
-
- 0
|
83
|
-
version: "0"
|
84
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
73
|
none: false
|
86
|
-
requirements:
|
87
|
-
- -
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
|
90
|
-
segments:
|
91
|
-
- 0
|
92
|
-
version: "0"
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
93
78
|
requirements: []
|
94
|
-
|
95
79
|
rubyforge_project:
|
96
|
-
rubygems_version: 1.
|
80
|
+
rubygems_version: 1.6.2
|
97
81
|
signing_key:
|
98
82
|
specification_version: 3
|
99
83
|
summary: An ffi wrapper for GEOS, a C++ port of the Java Topology Suite (JTS).
|
100
84
|
test_files: []
|
101
|
-
|