rubyvor 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ module RubyVor
2
+ class PriorityQueue
3
+
4
+ attr_reader :data, :size
5
+
6
+ class << self
7
+ def build_queue(max_index=-1,&block)
8
+ data = []
9
+
10
+ index = 0
11
+ loop do
12
+ x = QueueItem.new(nil, nil, nil)
13
+
14
+ yield(x)
15
+ break if !(max_index < 0 || index < max_index) || x.priority.nil?
16
+
17
+ x.index = index
18
+ data.push(x)
19
+ index += 1
20
+ end
21
+
22
+ q = new
23
+ q.instance_variable_set(:@data, data)
24
+ q.instance_variable_set(:@size, data.length)
25
+ q.heapify()
26
+
27
+ return q
28
+ end
29
+ end
30
+
31
+ def initialize
32
+ @data = []
33
+ @size = 0
34
+ heapify()
35
+ end
36
+
37
+ def peek
38
+ @data[0]
39
+ end
40
+
41
+ def pop
42
+ return nil if @size < 1
43
+
44
+ r = @data[0]
45
+
46
+ @data[0] = @data[@size-1]
47
+ @data[0].index = 0
48
+ @data.delete_at(@size-1)
49
+
50
+ @size -= 1
51
+
52
+ percolate_down(0) if @size > 0
53
+
54
+ return r
55
+ end
56
+
57
+ def push(data, priority=data)
58
+ @size += 1
59
+ @data[@size - 1] = QueueItem.new(priority, @size - 1, data)
60
+ percolate_up(@size - 1)
61
+ end
62
+
63
+ # Implemented in C
64
+ def reorder_queue;end
65
+
66
+ protected
67
+
68
+ # Implemented in C
69
+ # def heapify(data);end
70
+
71
+ # Implemented in C
72
+ # def percolate_up(i);end
73
+
74
+ # Implemented in C
75
+ # def percolate_down(i);end
76
+
77
+ class QueueItem
78
+ attr_accessor :priority, :index, :data
79
+ def initialize(p, i, d)
80
+ @priority = p
81
+ @index = i
82
+ @data = d
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,3 @@
1
+ module RubyVor
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,218 @@
1
+ require 'xml/libxml' unless defined?(LibXML)
2
+ module RubyVor
3
+ class Visualizer
4
+
5
+ COLORS = %w{black red blue lime gray yellow purple orange pink}
6
+
7
+ # Support various versions of LibXML
8
+ include LibXML if defined?(LibXML)
9
+
10
+ def self.make_svg(computation, opts={})
11
+ @opts = opts = {
12
+ :name => 'vddt.svg',
13
+ :triangulation => true,
14
+ :voronoi_diagram => false,
15
+ :mst => false,
16
+ :cbd => false,
17
+ }.merge(opts)
18
+
19
+ line_colors = COLORS.clone
20
+
21
+ doc = XML::Document.new()
22
+
23
+ doc.root = XML::Node.new('svg')
24
+ doc.root['xmlns'] = 'http://www.w3.org/2000/svg'
25
+ doc.root['xml:space'] = 'preserve'
26
+
27
+ max_x = 0
28
+ min_x = Float::MAX
29
+ max_y = 0
30
+ min_y = Float::MAX
31
+ pmax_x = 0
32
+ pmin_x = Float::MAX
33
+ pmax_y = 0
34
+ pmin_y = Float::MAX
35
+
36
+ computation.points.each do |point|
37
+ max_x = point.x if point.x > max_x
38
+ min_x = point.x if point.x < min_x
39
+ max_y = point.y if point.y > max_y
40
+ min_y = point.y if point.y < min_y
41
+ pmax_x = point.x if point.x > pmax_x
42
+ pmin_x = point.x if point.x < pmin_x
43
+ pmax_y = point.y if point.y > pmax_y
44
+ pmin_y = point.y if point.y < pmin_y
45
+ end
46
+
47
+ if opts[:voronoi_diagram]
48
+ computation.voronoi_diagram_raw.each do |item|
49
+ if item.first == :v
50
+ max_x = item[1] if item[1] > max_x
51
+ min_x = item[1] if item[1] < min_x
52
+ max_y = item[2] if item[2] > max_y
53
+ min_y = item[2] if item[2] < min_y
54
+ end
55
+ end
56
+ end
57
+
58
+ opts[:offset_x] = -1.0 * min_x + 20
59
+ opts[:offset_y] = -1.0 * min_y + 20
60
+
61
+ if opts[:triangulation]
62
+ # Draw in the triangulation
63
+ color = line_colors.shift
64
+ computation.delaunay_triangulation_raw.each do |triplet|
65
+ for i in 0..2
66
+ line = line_from_points(computation.points[triplet[i % 2 + 1]], computation.points[triplet[i & 6]])
67
+ line['style'] = "stroke:#{color};stroke-width:1;"
68
+ doc.root << line
69
+ end
70
+ end
71
+ end
72
+
73
+ if opts[:mst]
74
+ color = line_colors.shift
75
+ computation.minimum_spanning_tree.each do |edge, weight|
76
+ line = line_from_points(computation.points[edge[0]], computation.points[edge[1]])
77
+ line['style'] = "stroke:#{color};stroke-width:1;"
78
+ doc.root << line
79
+ end
80
+ end
81
+
82
+ if opts[:cbd]
83
+ mst = computation.minimum_spanning_tree
84
+
85
+ computation.cluster_by_distance(opts[:cbd]).each do |cluster|
86
+
87
+ color = new_color
88
+ min_dist = Float::MAX
89
+ set_min = false
90
+ cluster.each do |a|
91
+ cluster.each do |b|
92
+ next if a == b
93
+ k = a < b ? [a,b] : [b,a]
94
+ next unless mst.has_key?(k)
95
+
96
+ if mst[k] < min_dist
97
+ min_dist = mst[k]
98
+ set_min = true
99
+ end
100
+ end
101
+ end
102
+
103
+ min_dist = 10 unless set_min
104
+
105
+
106
+ cluster.each do |v|
107
+ node = circle_from_point(computation.points[v])
108
+ node['r'] = (min_dist + 10).to_s
109
+ node['style'] = "fill:#{color};stroke:#{color};"
110
+ node['opacity'] = '0.4'
111
+
112
+ doc.root << node
113
+ end
114
+
115
+ end
116
+ end
117
+
118
+ if opts[:voronoi_diagram]
119
+ voronoi_vertices = []
120
+ draw_lines = []
121
+ draw_points = []
122
+ line_functions = []
123
+
124
+ xcut = (pmax_x + pmin_x) / 2.0
125
+ ycut = (pmax_y + pmin_y) / 2.0
126
+
127
+ color = line_colors.shift
128
+
129
+ computation.voronoi_diagram_raw.each do |item|
130
+ case item.first
131
+ when :v
132
+ # Draw a voronoi vertex
133
+ v = RubyVor::Point.new(item[1], item[2])
134
+ voronoi_vertices.push(v)
135
+ node = circle_from_point(v)
136
+ node['fill'] = 'red'
137
+ node['r'] = '2'
138
+ node['stroke'] = 'black'
139
+ node['stroke-width'] = '1'
140
+
141
+ draw_points << node
142
+ when :l
143
+ # :l a b c --> ax + by = c
144
+ a = item[1]
145
+ b = item[2]
146
+ c = item[3]
147
+ line_functions.push({ :y => lambda{|x| (c - a * x) / b},
148
+ :x => lambda{|y| (c - b * y) / a} })
149
+ when :e
150
+ if item[2] == -1 || item[3] == -1
151
+ from_vertex = voronoi_vertices[item[2] == -1 ? item[3] : item[2]]
152
+
153
+ next if from_vertex < RubyVor::Point.new(0,0)
154
+
155
+ if item[2] == -1
156
+ inf_vertex = RubyVor::Point.new(0, line_functions[item[1]][:y][0])
157
+ else
158
+ inf_vertex = RubyVor::Point.new(max_x, line_functions[item[1]][:y][max_x])
159
+ end
160
+
161
+ line = line_from_points(from_vertex, inf_vertex)
162
+ else
163
+ line = line_from_points(voronoi_vertices[item[2]], voronoi_vertices[item[3]])
164
+ end
165
+
166
+ line['style'] = "stroke:#{color};stroke-width:1;"
167
+ draw_lines << line
168
+
169
+ end
170
+ end
171
+
172
+ draw_lines.each {|l| doc.root << l}
173
+ draw_points.each {|p| doc.root << p}
174
+ end
175
+
176
+ # Now draw in nodes
177
+ computation.points.each do |point|
178
+ node = circle_from_point(point)
179
+ node['fill'] = 'lime'
180
+
181
+ doc.root << node
182
+ end
183
+
184
+ doc.root['width'] = (max_x + opts[:offset_x] + 50).to_s
185
+ doc.root['height'] = (max_y + opts[:offset_y] + 50).to_s
186
+
187
+ doc.save(opts[:name] || 'vddt.svg')
188
+ end
189
+
190
+ private
191
+ def self.line_from_points(a, b)
192
+ line = XML::Node.new('line')
193
+ line['x1'] = (a.x + @opts[:offset_x] + 10).to_s
194
+ line['y1'] = (a.y + @opts[:offset_y] + 10).to_s
195
+ line['x2'] = (b.x + @opts[:offset_x] + 10).to_s
196
+ line['y2'] = (b.y + @opts[:offset_y] + 10).to_s
197
+ line
198
+ end
199
+
200
+ def self.circle_from_point(point)
201
+ node = XML::Node.new('circle')
202
+ node['cx'] = (point.x + @opts[:offset_x] + 10).to_s
203
+ node['cy'] = (point.y + @opts[:offset_y] + 10).to_s
204
+ node['r'] = 5.to_s
205
+ node['stroke'] = 'black'
206
+ node['stroke-width'] = 2.to_s
207
+ node
208
+ end
209
+
210
+ def self.new_color
211
+ a = rand(256)
212
+ b = rand(256) | a
213
+ c = rand(256) ^ b
214
+
215
+ "rgb(#{[a,b,c].sort{|k,l| rand(3)-1}.join(',')})"
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rubyvor}
5
+ s.version = "0.1.3"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Brendan Ribera"]
9
+ s.date = %q{2010-01-26}
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.}
11
+ s.email = ["brendan.ribera+rubyvor@gmail.com"]
12
+ s.extensions = ["ext/extconf.rb"]
13
+ s.extra_rdoc_files = ["Manifest.txt"]
14
+ s.files = ["History.rdoc", "Manifest.txt", "README.rdoc", "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"]
15
+ s.homepage = %q{http://github.com/bribera/rubyvor}
16
+ s.rdoc_options = ["--main", "README.rdoc"]
17
+ s.require_paths = ["lib", "ext"]
18
+ s.rubyforge_project = %q{rubyvor}
19
+ s.rubygems_version = %q{1.3.5}
20
+ s.summary = %q{Efficient Voronoi diagrams and Delaunay trianglation for Ruby}
21
+ s.test_files = ["test/test_computation.rb", "test/test_point.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 3
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_development_dependency(%q<hoe>, [">= 2.4.0"])
29
+ else
30
+ s.add_dependency(%q<hoe>, [">= 2.4.0"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<hoe>, [">= 2.4.0"])
34
+ end
35
+ end
@@ -0,0 +1,354 @@
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_empty_points
13
+ assert_raises TypeError do
14
+ RubyVor::VDDT::Computation.from_points(nil)
15
+ end
16
+
17
+ assert_raises RuntimeError do
18
+ RubyVor::VDDT::Computation.from_points([])
19
+ end
20
+ end
21
+
22
+ def test_nn_graph
23
+ comp = RubyVor::VDDT::Computation.from_points(sample_points)
24
+
25
+ # based on this expected delaunay trianglulation:
26
+ # 3 2 1
27
+ # 3 0 2
28
+ # 8 2 0
29
+ # 3 8 0
30
+ # 5 6 8
31
+ # 7 6 5
32
+ # 7 4 6
33
+ # 6 2 8
34
+ # 8 7 5
35
+
36
+ expected_graph = [
37
+ [2, 3, 8], # 0
38
+ [2, 3], # 1
39
+ [0, 1, 3, 6, 8], # 2
40
+ [0, 1, 2, 8], # 3
41
+ [6, 7], # 4
42
+ [6, 7, 8], # 5
43
+ [2, 4, 5, 7, 8], # 6
44
+ [4, 5, 6, 8], # 7
45
+ [0, 2, 3, 5, 6, 7], # 8
46
+ ]
47
+
48
+
49
+ comp.nn_graph.each_with_index do |neighbors,i|
50
+ refute_empty neighbors, "@nn_graph returned empty neighbors for node #{i}"
51
+ end
52
+
53
+ assert_equal comp.nn_graph.map{|v| v.sort}.sort, \
54
+ expected_graph.map{|v| v.sort}.sort
55
+ end
56
+
57
+ def test_simple_mst
58
+ points = [
59
+ RubyVor::Point.new(0,0),
60
+ RubyVor::Point.new(1.0,1.1),
61
+ RubyVor::Point.new(4.9,3.1),
62
+ ]
63
+
64
+ comp = RubyVor::VDDT::Computation.from_points(points)
65
+ expected_mst = [
66
+ [0,1],
67
+ [1,2]
68
+ ]
69
+ computed_mst = comp.minimum_spanning_tree
70
+
71
+ # Assert nodes are correct
72
+ assert_equal expected_mst.sort, \
73
+ computed_mst.keys.sort
74
+ end
75
+
76
+ def test_advanced_mst
77
+ # Test tree taken from an example SVG included in the Wikipedia article on Euclidean minimum spanning trees:
78
+ # http://en.wikipedia.org/wiki/Image:Euclidean_minimum_spanning_tree.svg
79
+
80
+ points = [
81
+ RubyVor::Point.new(155.692, 99.783), # 0
82
+ RubyVor::Point.new(162.285, 120.245), # 1
83
+ RubyVor::Point.new(143.692, 129.893), # 2
84
+ RubyVor::Point.new(150.128, 167.924), # 3
85
+ RubyVor::Point.new(137.617, 188.953), # 4
86
+ RubyVor::Point.new(193.467, 119.345), # 5
87
+ RubyVor::Point.new(196.754, 88.47), # 6
88
+ RubyVor::Point.new(241.629, 70.845), # 7
89
+ RubyVor::Point.new(262.692, 59.97), # 8
90
+ RubyVor::Point.new(269.629, 63.158), # 9
91
+ RubyVor::Point.new(247.257, 200.669), # 10
92
+ RubyVor::Point.new(231.28, 245.974), # 11
93
+ RubyVor::Point.new(268.002, 264.693), # 12
94
+ RubyVor::Point.new(155.442, 64.473), # 13
95
+ RubyVor::Point.new(198.598, 31.804), # 14
96
+ RubyVor::Point.new(216.816, 3.513), # 15
97
+ RubyVor::Point.new(89.624, 27.344), # 16
98
+ RubyVor::Point.new(67.925, 56.999), # 17
99
+ RubyVor::Point.new(77.328, 93.404), # 18
100
+ RubyVor::Point.new(65.525, 158.783), # 19
101
+ RubyVor::Point.new(63.525,170.783), # 20
102
+ RubyVor::Point.new(15.192, 192.783), # 21
103
+ RubyVor::Point.new(7.025, 236.949), # 22
104
+ RubyVor::Point.new(40.525, 262.949), # 23
105
+ RubyVor::Point.new(61.692, 225.95) # 24
106
+ ]
107
+
108
+ comp = RubyVor::VDDT::Computation.from_points(points)
109
+
110
+ expected_mst = [
111
+ [0,1],
112
+ [0,13],
113
+ [1,2],
114
+ [1,5],
115
+ [2,3],
116
+ [3,4],
117
+ [5,6],
118
+ [5,10],
119
+ [6,7],
120
+ [7,8],
121
+ [8,9],
122
+ [10,11],
123
+ [11,12],
124
+ [13,14],
125
+ [13,16],
126
+ [14,15],
127
+ [16,17],
128
+ [17,18],
129
+ [18,19],
130
+ [19,20],
131
+ [20,21],
132
+ [21,22],
133
+ [22,23],
134
+ [23,24]
135
+ ]
136
+ computed_mst = comp.minimum_spanning_tree
137
+
138
+ assert_equal expected_mst.sort, \
139
+ computed_mst.keys.sort
140
+ end
141
+
142
+ def test_cluster_by_distance
143
+ comp = RubyVor::VDDT::Computation.from_points(sample_points)
144
+
145
+ expected_clusters = [
146
+ [0,1,2,3],
147
+ [8],
148
+ [4,5,6,7]
149
+ ]
150
+
151
+ # We want to ensure that the nn_graph isn't modified by this call
152
+ original_nn_graph = comp.nn_graph.map{|v| v.clone}
153
+
154
+ # Compute clusters within a distance of 10
155
+ computed_clusters = comp.cluster_by_distance(10)
156
+
157
+ assert_equal expected_clusters.map{|cl| cl.sort}.sort, \
158
+ computed_clusters.map{|cl| cl.sort}.sort
159
+
160
+ assert_equal original_nn_graph, \
161
+ comp.nn_graph
162
+
163
+ end
164
+
165
+
166
+ def test_duplicate_points
167
+ comp = RubyVor::VDDT::Computation.from_points([
168
+ RubyVor::Point.new(2,3), # 0
169
+ RubyVor::Point.new(1,1), # 1
170
+ RubyVor::Point.new(1,1), # 2
171
+ RubyVor::Point.new(1,1), # 3
172
+ RubyVor::Point.new(1,1), # 4
173
+ RubyVor::Point.new(1,1), # 5
174
+ RubyVor::Point.new(1,1), # 6
175
+ RubyVor::Point.new(1,1), # 7
176
+ RubyVor::Point.new(1,1), # 8
177
+ RubyVor::Point.new(4,10), # 9
178
+ RubyVor::Point.new(4,10.0), # 10
179
+ RubyVor::Point.new(4.0,10.0), # 11
180
+ RubyVor::Point.new(4.0,10.0), # 12
181
+ ])
182
+ comp.nn_graph.each_with_index do |neighbors,i|
183
+ refute_empty neighbors, "@nn_graph has empty neighbors for node #{i}"
184
+ end
185
+
186
+ =begin
187
+ assert_equal [[0], [1,2,3,4,5,6,7,8], [9,10,11,12]], \
188
+ comp.cluster_by_distance(1).map{|cl| cl.sort}.sort, \
189
+ "cluster by distance 1"
190
+
191
+ assert_equal [[0,1,2,3,4,5,6,7,8], [9,10,11,12]], \
192
+ comp.cluster_by_distance(5).map{|cl| cl.sort}.sort, \
193
+ "cluster by distance 5"
194
+
195
+ assert_equal [[0,1,2,3,4,5,6,7,8,9,10,11,12]], \
196
+ comp.cluster_by_distance(10).map{|cl| cl.sort}.sort, \
197
+ "cluster by distance 10"
198
+
199
+ assert_equal [[0,1,2,3,4,5,6,7,8], [9,10,11,12]], \
200
+ comp.cluster_by_size([2])[2].map{|cl| cl.sort}.sort, \
201
+ "cluster by size 2"
202
+ =end
203
+
204
+ assert_equal [[0], [1], [2]], \
205
+ comp.cluster_by_distance(1).map{|cl| cl.sort}.sort, \
206
+ "cluster by distance 1"
207
+
208
+ assert_equal [[0,1], [2]], \
209
+ comp.cluster_by_distance(5).map{|cl| cl.sort}.sort, \
210
+ "cluster by distance 5"
211
+
212
+ assert_equal [[0,1,2]], \
213
+ comp.cluster_by_distance(10).map{|cl| cl.sort}.sort, \
214
+ "cluster by distance 10"
215
+
216
+ assert_equal [[0,1], [2]], \
217
+ comp.cluster_by_size([2])[2].map{|cl| cl.sort}.sort, \
218
+ "cluster by size 2"
219
+
220
+ end
221
+
222
+
223
+ def test_bad_data
224
+ assert_raises TypeError do
225
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,:s)])
226
+ end
227
+
228
+ assert_raises TypeError do
229
+ comp = RubyVor::VDDT::Computation.from_points(RubyVor::Point.new(21,3))
230
+ end
231
+
232
+ assert_raises RuntimeError do
233
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), nil])
234
+ end
235
+
236
+ assert_raises RuntimeError do
237
+ comp = RubyVor::VDDT::Computation.from_points([])
238
+ end
239
+
240
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,1.5)])
241
+ assert_raises ArgumentError do
242
+ cl = comp.cluster_by_distance(nil)
243
+ end
244
+ end
245
+
246
+
247
+ def test_no_neighbors
248
+ nn_graph = nil
249
+
250
+ # Test :raise
251
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
252
+ comp.no_neighbor_response = :raise
253
+
254
+ assert_equal comp.no_neighbor_response, :raise
255
+ assert_raises(IndexError) { nn_graph = comp.nn_graph }
256
+ assert_raises(IndexError) { comp.cluster_by_distance(5) }
257
+ assert_equal nn_graph, nil
258
+
259
+
260
+ # Test :use_all (default)
261
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
262
+ comp.no_neighbor_response = :use_all
263
+
264
+ assert_equal comp.no_neighbor_response, :use_all
265
+ assert_nothing_raised { nn_graph = comp.nn_graph }
266
+ assert_nothing_raised do
267
+ assert_equal comp.cluster_by_distance(5).map{|a| a.sort}.sort, [[0,1,2,3,4]]
268
+ end
269
+ refute_equal nn_graph, nil
270
+
271
+
272
+ # Test :ignore
273
+ comp = RubyVor::VDDT::Computation.from_points([1,2,3,4,5].map{|xy| RubyVor::Point.new(xy,xy)})
274
+ comp.no_neighbor_response = :ignore
275
+
276
+ assert_equal comp.no_neighbor_response, :ignore
277
+ assert_nothing_raised { nn_graph = comp.nn_graph }
278
+ assert_nothing_raised do
279
+ assert_equal comp.cluster_by_distance(5).map{|a| a.sort}.sort, [[0],[1],[2],[3],[4]]
280
+ end
281
+ refute_equal nn_graph, nil
282
+ end
283
+
284
+
285
+ def test_cluster_by_size
286
+ comp = RubyVor::VDDT::Computation.from_points([
287
+ RubyVor::Point.new(0.25, 0.25), # 0
288
+ RubyVor::Point.new(1, 0.25), # 1
289
+ RubyVor::Point.new(0.5, 1), # 2
290
+ RubyVor::Point.new(5, 5), # 3
291
+ RubyVor::Point.new(10.25, 10.25), # 4
292
+ RubyVor::Point.new(13, 9), # 5
293
+ RubyVor::Point.new(9, 9) # 6
294
+ ])
295
+
296
+ sizes = [1, 3, 5, 7]
297
+
298
+ computed_sized_clusters = comp.cluster_by_size(sizes)
299
+
300
+ # Check that we got clusters for each size requested
301
+ assert_equal sizes, \
302
+ computed_sized_clusters.keys.sort
303
+
304
+ assert_equal [[0,1,2,3,4,5,6]], \
305
+ computed_sized_clusters[1].map{|cl| cl.sort}.sort, \
306
+ 'Failed cluster of size 1'
307
+
308
+ assert_equal [[0,1,2], [3], [4,5,6]], \
309
+ computed_sized_clusters[3].map{|cl| cl.sort}.sort
310
+
311
+ assert_equal [[0,1,2], [3], [4], [5], [6]], \
312
+ computed_sized_clusters[5].map{|cl| cl.sort}.sort
313
+
314
+ assert_equal [[0], [1], [2], [3], [4], [5], [6]], \
315
+ computed_sized_clusters[7].sort
316
+ end
317
+
318
+ #
319
+ # A few helper methods
320
+ #
321
+
322
+ private
323
+
324
+ def sample_points
325
+ if @points.nil?
326
+ @points = [
327
+ [1.1,1],
328
+ [0,0],
329
+ [1,0],
330
+ [0,1.1],
331
+
332
+ [101.1,101],
333
+ [100,100],
334
+ [101,100],
335
+ [100,101.1],
336
+
337
+ [43, 55]
338
+ ].map{|x,y| RubyVor::Point.new(x,y)}
339
+ end
340
+ @points
341
+ end
342
+
343
+ def assert_nothing_raised(&b)
344
+ begin
345
+ yield
346
+ rescue Exception => e
347
+ flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
348
+ return
349
+ end
350
+ pass()
351
+ end
352
+ end
353
+
354
+ MiniTest::Unit.autorun