bribera-rubyvor 0.0.2 → 0.1.1

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.
@@ -1,29 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = %q{rubyvor}
3
- s.version = "0.0.2"
5
+ s.version = "0.1.1"
4
6
 
5
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
8
  s.authors = ["Brendan Ribera"]
7
- s.date = %q{2008-12-03}
9
+ s.date = %q{2009-01-15}
8
10
  s.description = %q{RubyVor provides efficient computation of Voronoi diagrams and Delaunay triangulation for a set of Ruby points. It is intended to function as a complemenet to GeoRuby. These structures can be used to compute a nearest-neighbor graph for a set of points. This graph can in turn be used for proximity-based clustering of the input points.}
9
11
  s.email = ["brendan.ribera+rubyvor@gmail.com"]
10
12
  s.extensions = ["ext/extconf.rb"]
11
13
  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
12
- s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/vdefs.h", "ext/voronoi.c", "ext/voronoi_interface.c", "lib/ruby_vor.rb", "lib/ruby_vor/decomposition.rb", "lib/ruby_vor/point.rb", "lib/ruby_vor/version.rb", "rubyvor.gemspec", "test/test_voronoi_interface.rb"]
14
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/rb_cComputation.c", "ext/rb_cPoint.c", "ext/rb_cPriorityQueue.c", "ext/ruby_vor_c.c", "ext/ruby_vor_c.h", "ext/vdefs.h", "ext/voronoi.c", "lib/ruby_vor.rb", "lib/ruby_vor/computation.rb", "lib/ruby_vor/geo_ruby_extensions.rb", "lib/ruby_vor/point.rb", "lib/ruby_vor/priority_queue.rb", "lib/ruby_vor/version.rb", "lib/ruby_vor/visualizer.rb", "rubyvor.gemspec", "test/test_computation.rb", "test/test_point.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb"]
13
15
  s.has_rdoc = true
14
16
  s.homepage = %q{http://github.com/bribera/rubyvor}
15
17
  s.rdoc_options = ["--main", "README.txt"]
16
18
  s.require_paths = ["lib", "ext"]
17
19
  s.rubyforge_project = %q{rubyvor}
18
- s.rubygems_version = %q{1.2.0}
20
+ s.rubygems_version = %q{1.3.1}
19
21
  s.summary = %q{RubyVor provides efficient computation of Voronoi diagrams and Delaunay triangulation for a set of Ruby points}
20
- s.test_files = ["test/test_voronoi_interface.rb"]
22
+ s.test_files = ["test/test_computation.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb", "test/test_point.rb"]
21
23
 
22
24
  if s.respond_to? :specification_version then
23
25
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
26
  s.specification_version = 2
25
27
 
26
- if current_version >= 3 then
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
29
  s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
28
30
  else
29
31
  s.add_dependency(%q<hoe>, [">= 1.8.2"])
@@ -0,0 +1,344 @@
1
+ require 'rubygems'
2
+ require 'minitest/unit'
3
+ require File.dirname(__FILE__) + '/../lib/ruby_vor'
4
+
5
+ class TestComputation < MiniTest::Unit::TestCase
6
+
7
+ def initialize(*args)
8
+ @points = @trianglulation_raw = @diagram_raw = nil
9
+ super(*args)
10
+ end
11
+
12
+ def test_nn_graph
13
+ comp = RubyVor::VDDT::Computation.from_points(sample_points)
14
+
15
+ # based on this expected delaunay trianglulation:
16
+ # 3 2 1
17
+ # 3 0 2
18
+ # 8 2 0
19
+ # 3 8 0
20
+ # 5 6 8
21
+ # 7 6 5
22
+ # 7 4 6
23
+ # 6 2 8
24
+ # 8 7 5
25
+
26
+ expected_graph = [
27
+ [2, 3, 8], # 0
28
+ [2, 3], # 1
29
+ [0, 1, 3, 6, 8], # 2
30
+ [0, 1, 2, 8], # 3
31
+ [6, 7], # 4
32
+ [6, 7, 8], # 5
33
+ [2, 4, 5, 7, 8], # 6
34
+ [4, 5, 6, 8], # 7
35
+ [0, 2, 3, 5, 6, 7], # 8
36
+ ]
37
+
38
+
39
+ comp.nn_graph.each_with_index do |neighbors,i|
40
+ refute_empty neighbors, "@nn_graph returned empty neighbors for node #{i}"
41
+ end
42
+
43
+ assert_equal comp.nn_graph.map{|v| v.sort}.sort, \
44
+ expected_graph.map{|v| v.sort}.sort
45
+ end
46
+
47
+ def test_simple_mst
48
+ points = [
49
+ RubyVor::Point.new(0,0),
50
+ RubyVor::Point.new(1.0,1.1),
51
+ RubyVor::Point.new(4.9,3.1),
52
+ ]
53
+
54
+ comp = RubyVor::VDDT::Computation.from_points(points)
55
+ expected_mst = [
56
+ [0,1],
57
+ [1,2]
58
+ ]
59
+ computed_mst = comp.minimum_spanning_tree
60
+
61
+ # Assert nodes are correct
62
+ assert_equal expected_mst.sort, \
63
+ computed_mst.keys.sort
64
+ end
65
+
66
+ def test_advanced_mst
67
+ # Test tree taken from an example SVG included in the Wikipedia article on Euclidean minimum spanning trees:
68
+ # http://en.wikipedia.org/wiki/Image:Euclidean_minimum_spanning_tree.svg
69
+
70
+ points = [
71
+ RubyVor::Point.new(155.692, 99.783), # 0
72
+ RubyVor::Point.new(162.285, 120.245), # 1
73
+ RubyVor::Point.new(143.692, 129.893), # 2
74
+ RubyVor::Point.new(150.128, 167.924), # 3
75
+ RubyVor::Point.new(137.617, 188.953), # 4
76
+ RubyVor::Point.new(193.467, 119.345), # 5
77
+ RubyVor::Point.new(196.754, 88.47), # 6
78
+ RubyVor::Point.new(241.629, 70.845), # 7
79
+ RubyVor::Point.new(262.692, 59.97), # 8
80
+ RubyVor::Point.new(269.629, 63.158), # 9
81
+ RubyVor::Point.new(247.257, 200.669), # 10
82
+ RubyVor::Point.new(231.28, 245.974), # 11
83
+ RubyVor::Point.new(268.002, 264.693), # 12
84
+ RubyVor::Point.new(155.442, 64.473), # 13
85
+ RubyVor::Point.new(198.598, 31.804), # 14
86
+ RubyVor::Point.new(216.816, 3.513), # 15
87
+ RubyVor::Point.new(89.624, 27.344), # 16
88
+ RubyVor::Point.new(67.925, 56.999), # 17
89
+ RubyVor::Point.new(77.328, 93.404), # 18
90
+ RubyVor::Point.new(65.525, 158.783), # 19
91
+ RubyVor::Point.new(63.525,170.783), # 20
92
+ RubyVor::Point.new(15.192, 192.783), # 21
93
+ RubyVor::Point.new(7.025, 236.949), # 22
94
+ RubyVor::Point.new(40.525, 262.949), # 23
95
+ RubyVor::Point.new(61.692, 225.95) # 24
96
+ ]
97
+
98
+ comp = RubyVor::VDDT::Computation.from_points(points)
99
+
100
+ expected_mst = [
101
+ [0,1],
102
+ [0,13],
103
+ [1,2],
104
+ [1,5],
105
+ [2,3],
106
+ [3,4],
107
+ [5,6],
108
+ [5,10],
109
+ [6,7],
110
+ [7,8],
111
+ [8,9],
112
+ [10,11],
113
+ [11,12],
114
+ [13,14],
115
+ [13,16],
116
+ [14,15],
117
+ [16,17],
118
+ [17,18],
119
+ [18,19],
120
+ [19,20],
121
+ [20,21],
122
+ [21,22],
123
+ [22,23],
124
+ [23,24]
125
+ ]
126
+ computed_mst = comp.minimum_spanning_tree
127
+
128
+ assert_equal expected_mst.sort, \
129
+ computed_mst.keys.sort
130
+ end
131
+
132
+ def test_cluster_by_distance
133
+ comp = RubyVor::VDDT::Computation.from_points(sample_points)
134
+
135
+ expected_clusters = [
136
+ [0,1,2,3],
137
+ [8],
138
+ [4,5,6,7]
139
+ ]
140
+
141
+ # We want to ensure that the nn_graph isn't modified by this call
142
+ original_nn_graph = comp.nn_graph.map{|v| v.clone}
143
+
144
+ # Compute clusters within a distance of 10
145
+ computed_clusters = comp.cluster_by_distance(10)
146
+
147
+ assert_equal expected_clusters.map{|cl| cl.sort}.sort, \
148
+ computed_clusters.map{|cl| cl.sort}.sort
149
+
150
+ assert_equal original_nn_graph, \
151
+ comp.nn_graph
152
+
153
+ end
154
+
155
+
156
+ def test_duplicate_points
157
+ comp = RubyVor::VDDT::Computation.from_points([
158
+ RubyVor::Point.new(2,3), # 0
159
+ RubyVor::Point.new(1,1), # 1
160
+ RubyVor::Point.new(1,1), # 2
161
+ RubyVor::Point.new(1,1), # 3
162
+ RubyVor::Point.new(1,1), # 4
163
+ RubyVor::Point.new(1,1), # 5
164
+ RubyVor::Point.new(1,1), # 6
165
+ RubyVor::Point.new(1,1), # 7
166
+ RubyVor::Point.new(1,1), # 8
167
+ RubyVor::Point.new(4,10), # 9
168
+ RubyVor::Point.new(4,10.0), # 10
169
+ RubyVor::Point.new(4.0,10.0), # 11
170
+ RubyVor::Point.new(4.0,10.0), # 12
171
+ ])
172
+ comp.nn_graph.each_with_index do |neighbors,i|
173
+ refute_empty neighbors, "@nn_graph has empty neighbors for node #{i}"
174
+ end
175
+
176
+ =begin
177
+ assert_equal [[0], [1,2,3,4,5,6,7,8], [9,10,11,12]], \
178
+ comp.cluster_by_distance(1).map{|cl| cl.sort}.sort, \
179
+ "cluster by distance 1"
180
+
181
+ assert_equal [[0,1,2,3,4,5,6,7,8], [9,10,11,12]], \
182
+ comp.cluster_by_distance(5).map{|cl| cl.sort}.sort, \
183
+ "cluster by distance 5"
184
+
185
+ assert_equal [[0,1,2,3,4,5,6,7,8,9,10,11,12]], \
186
+ comp.cluster_by_distance(10).map{|cl| cl.sort}.sort, \
187
+ "cluster by distance 10"
188
+
189
+ assert_equal [[0,1,2,3,4,5,6,7,8], [9,10,11,12]], \
190
+ comp.cluster_by_size([2])[2].map{|cl| cl.sort}.sort, \
191
+ "cluster by size 2"
192
+ =end
193
+
194
+ assert_equal [[0], [1], [2]], \
195
+ comp.cluster_by_distance(1).map{|cl| cl.sort}.sort, \
196
+ "cluster by distance 1"
197
+
198
+ assert_equal [[0,1], [2]], \
199
+ comp.cluster_by_distance(5).map{|cl| cl.sort}.sort, \
200
+ "cluster by distance 5"
201
+
202
+ assert_equal [[0,1,2]], \
203
+ comp.cluster_by_distance(10).map{|cl| cl.sort}.sort, \
204
+ "cluster by distance 10"
205
+
206
+ assert_equal [[0,1], [2]], \
207
+ comp.cluster_by_size([2])[2].map{|cl| cl.sort}.sort, \
208
+ "cluster by size 2"
209
+
210
+ end
211
+
212
+
213
+ def test_bad_data
214
+ assert_raises TypeError do
215
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,:s)])
216
+ end
217
+
218
+ assert_raises TypeError do
219
+ comp = RubyVor::VDDT::Computation.from_points(RubyVor::Point.new(21,3))
220
+ end
221
+
222
+ assert_raises RuntimeError do
223
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), nil])
224
+ end
225
+
226
+ assert_raises RuntimeError do
227
+ comp = RubyVor::VDDT::Computation.from_points([])
228
+ end
229
+
230
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,1.5)])
231
+ assert_raises ArgumentError do
232
+ cl = comp.cluster_by_distance(nil)
233
+ end
234
+ end
235
+
236
+
237
+ def test_no_neighbors
238
+ nn_graph = nil
239
+
240
+ # Test :raise
241
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
242
+ comp.no_neighbor_response = :raise
243
+
244
+ assert_equal comp.no_neighbor_response, :raise
245
+ assert_raises(IndexError) { nn_graph = comp.nn_graph }
246
+ assert_raises(IndexError) { comp.cluster_by_distance(5) }
247
+ assert_equal nn_graph, nil
248
+
249
+
250
+ # Test :use_all (default)
251
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
252
+ comp.no_neighbor_response = :use_all
253
+
254
+ assert_equal comp.no_neighbor_response, :use_all
255
+ assert_nothing_raised { nn_graph = comp.nn_graph }
256
+ assert_nothing_raised do
257
+ assert_equal comp.cluster_by_distance(5).map{|a| a.sort}.sort, [[0,1,2,3,4]]
258
+ end
259
+ refute_equal nn_graph, nil
260
+
261
+
262
+ # Test :ignore
263
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
264
+ comp.no_neighbor_response = :ignore
265
+
266
+ assert_equal comp.no_neighbor_response, :ignore
267
+ assert_nothing_raised { nn_graph = comp.nn_graph }
268
+ assert_nothing_raised do
269
+ assert_equal comp.cluster_by_distance(5).map{|a| a.sort}.sort, [[0],[1],[2],[3],[4]]
270
+ end
271
+ refute_equal nn_graph, nil
272
+ end
273
+
274
+
275
+ def test_cluster_by_size
276
+ comp = RubyVor::VDDT::Computation.from_points([
277
+ RubyVor::Point.new(0.25, 0.25), # 0
278
+ RubyVor::Point.new(1, 0.25), # 1
279
+ RubyVor::Point.new(0.5, 1), # 2
280
+ RubyVor::Point.new(5, 5), # 3
281
+ RubyVor::Point.new(10.25, 10.25), # 4
282
+ RubyVor::Point.new(13, 9), # 5
283
+ RubyVor::Point.new(9, 9) # 6
284
+ ])
285
+
286
+ sizes = [1, 3, 5, 7]
287
+
288
+ computed_sized_clusters = comp.cluster_by_size(sizes)
289
+
290
+ # Check that we got clusters for each size requested
291
+ assert_equal sizes, \
292
+ computed_sized_clusters.keys.sort
293
+
294
+ assert_equal [[0,1,2,3,4,5,6]], \
295
+ computed_sized_clusters[1].map{|cl| cl.sort}.sort, \
296
+ 'Failed cluster of size 1'
297
+
298
+ assert_equal [[0,1,2], [3], [4,5,6]], \
299
+ computed_sized_clusters[3].map{|cl| cl.sort}.sort
300
+
301
+ assert_equal [[0,1,2], [3], [4], [5], [6]], \
302
+ computed_sized_clusters[5].map{|cl| cl.sort}.sort
303
+
304
+ assert_equal [[0], [1], [2], [3], [4], [5], [6]], \
305
+ computed_sized_clusters[7].sort
306
+ end
307
+
308
+ #
309
+ # A few helper methods
310
+ #
311
+
312
+ private
313
+
314
+ def sample_points
315
+ if @points.nil?
316
+ @points = [
317
+ [1.1,1],
318
+ [0,0],
319
+ [1,0],
320
+ [0,1.1],
321
+
322
+ [101.1,101],
323
+ [100,100],
324
+ [101,100],
325
+ [100,101.1],
326
+
327
+ [43, 55]
328
+ ].map{|x,y| RubyVor::Point.new(x,y)}
329
+ end
330
+ @points
331
+ end
332
+
333
+ def assert_nothing_raised(&b)
334
+ begin
335
+ yield
336
+ rescue Exception => e
337
+ flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
338
+ return
339
+ end
340
+ pass()
341
+ end
342
+ end
343
+
344
+ MiniTest::Unit.autorun
@@ -0,0 +1,100 @@
1
+ require 'rubygems'
2
+ require 'minitest/unit'
3
+ require File.dirname(__FILE__) + '/../lib/ruby_vor'
4
+
5
+ class TestPoint < MiniTest::Unit::TestCase
6
+
7
+ def test_instantiation
8
+ a = b = nil
9
+
10
+ assert_raises TypeError do
11
+ a = RubyVor::Point.new(:"10", 10)
12
+ end
13
+
14
+ assert_raises TypeError do
15
+ a = RubyVor::Point.new(10, :"10")
16
+ end
17
+
18
+ assert_nothing_raised do
19
+ a = RubyVor::Point.new(123.456, 789.10)
20
+ b = RubyVor::Point.new("123.456", "789.10")
21
+ end
22
+
23
+ assert_equal a, b
24
+ end
25
+
26
+ def test_comparison
27
+ a = RubyVor::Point.new(10, 10)
28
+ b = RubyVor::Point.new(1, 1)
29
+
30
+ assert a > b
31
+ assert b < a
32
+ assert_equal(-1, (b <=> a))
33
+ end
34
+
35
+ def test_equality
36
+ a = RubyVor::Point.new(10, 10)
37
+ b = RubyVor::Point.new(10.0, 10)
38
+ c = RubyVor::Point.new(10.0, 10.0)
39
+ d = RubyVor::Point.new(10, 10.0)
40
+
41
+ z = RubyVor::Point.new(Math::PI, Math::PI)
42
+ o = a
43
+
44
+
45
+ # Test equality of values; both == and eql? perform this function.
46
+ assert a == a
47
+ assert a == b
48
+ assert a == c
49
+ assert a == d
50
+ assert a == o
51
+ assert a.eql?(a)
52
+ assert a.eql?(b)
53
+ assert a.eql?(c)
54
+ assert a.eql?(d)
55
+ assert a.eql?(o)
56
+
57
+ refute a == z
58
+ refute a.eql?(z)
59
+
60
+
61
+ # Test object equality.
62
+ refute a.equal?(b)
63
+ refute a.equal?(c)
64
+ refute a.equal?(d)
65
+ refute a.equal?(z)
66
+
67
+ assert a.equal?(a)
68
+ assert a.equal?(o)
69
+ end
70
+
71
+ def test_hash
72
+ a = RubyVor::Point.new(10, 10)
73
+ b = RubyVor::Point.new(10.0, 10)
74
+ c = RubyVor::Point.new(10.0, 10.0)
75
+ d = RubyVor::Point.new(10, 10.0)
76
+
77
+ z = RubyVor::Point.new(Math::PI, Math::PI)
78
+ o = a
79
+
80
+ assert_equal a.hash, b.hash
81
+ assert_equal a.hash, c.hash
82
+ assert_equal a.hash, d.hash
83
+ assert_equal a.hash, o.hash
84
+
85
+ refute_equal a.hash, z.hash
86
+ end
87
+
88
+ private
89
+
90
+ def assert_nothing_raised(&b)
91
+ begin
92
+ yield
93
+ rescue Exception => e
94
+ flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
95
+ return
96
+ end
97
+ pass()
98
+ end
99
+
100
+ end