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