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.
- data/History.txt +45 -0
- data/Manifest.txt +12 -2
- data/README.txt +32 -1
- data/Rakefile +2 -3
- data/ext/extconf.rb +2 -2
- data/ext/memory.c +21 -21
- data/ext/output.c +19 -28
- data/ext/rb_cComputation.c +370 -0
- data/ext/rb_cPoint.c +35 -0
- data/ext/rb_cPriorityQueue.c +120 -0
- data/ext/ruby_vor_c.c +106 -0
- data/ext/ruby_vor_c.h +36 -0
- data/ext/vdefs.h +3 -2
- data/ext/voronoi.c +57 -65
- data/lib/ruby_vor.rb +9 -6
- data/lib/ruby_vor/computation.rb +137 -0
- data/lib/ruby_vor/geo_ruby_extensions.rb +15 -0
- data/lib/ruby_vor/point.rb +24 -11
- data/lib/ruby_vor/priority_queue.rb +84 -0
- data/lib/ruby_vor/version.rb +1 -1
- data/lib/ruby_vor/visualizer.rb +218 -0
- data/rubyvor.gemspec +8 -6
- data/test/test_computation.rb +344 -0
- data/test/test_point.rb +100 -0
- data/test/test_priority_queue.rb +129 -0
- data/test/test_voronoi_interface.rb +12 -9
- metadata +17 -4
- data/ext/voronoi_interface.c +0 -213
- data/lib/ruby_vor/decomposition.rb +0 -22
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/unit'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/ruby_vor'
|
4
|
+
|
5
|
+
class TestPriorityQueue < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def test_heap_order_property
|
8
|
+
# min heap by default
|
9
|
+
q = RubyVor::PriorityQueue.new
|
10
|
+
|
11
|
+
items = [1,2,3,4,5,6,99,4,-20,101,5412,2,-1,-1,-1,33.0,0,55,7,12321,123.123,-123.123,0,0,0]
|
12
|
+
items.each{|i| q.push(i)}
|
13
|
+
|
14
|
+
items.sort!
|
15
|
+
idx = 0
|
16
|
+
|
17
|
+
# Test peek
|
18
|
+
assert_equal q.peek.data, items[0]
|
19
|
+
|
20
|
+
while min = q.pop
|
21
|
+
# Test pop
|
22
|
+
assert_equal min.data, items[idx]
|
23
|
+
|
24
|
+
# Test peek
|
25
|
+
assert_equal q.peek.data, items[idx + 1] if idx + 1 < items.length
|
26
|
+
|
27
|
+
idx += 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_heapify
|
32
|
+
q = RubyVor::PriorityQueue.new
|
33
|
+
|
34
|
+
# Create a randomized data set.
|
35
|
+
#
|
36
|
+
# Not ideal for unit tests, since they *should* be done
|
37
|
+
# on static data so that failure/success is deterministic...
|
38
|
+
# but works for me.
|
39
|
+
|
40
|
+
100.times{ q.push(rand * 10000.0 - 5000.0)}
|
41
|
+
|
42
|
+
# Set things right.
|
43
|
+
q.heapify()
|
44
|
+
|
45
|
+
old_n = -1.0 * Float::MAX
|
46
|
+
while n = q.pop
|
47
|
+
assert n.priority >= old_n, 'Heap-order property violated'
|
48
|
+
old_n = n.priority
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_bad_data
|
53
|
+
q = RubyVor::PriorityQueue.new
|
54
|
+
10.times { q.push(rand * 100.0 - 50.0) }
|
55
|
+
|
56
|
+
#
|
57
|
+
# Heapify
|
58
|
+
#
|
59
|
+
old_data = q.data[1]
|
60
|
+
q.data[1] = 45
|
61
|
+
assert_raises TypeError do
|
62
|
+
q.heapify()
|
63
|
+
end
|
64
|
+
q.data[1] = old_data
|
65
|
+
assert_nothing_raised do
|
66
|
+
q.heapify()
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
#
|
71
|
+
# Percolation
|
72
|
+
#
|
73
|
+
[100, -100].each do |i|
|
74
|
+
assert_raises IndexError do
|
75
|
+
q.percolate_up(i)
|
76
|
+
end
|
77
|
+
assert_raises IndexError do
|
78
|
+
q.percolate_down(i)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
[:x, Class, nil, false].each do |i|
|
82
|
+
assert_raises TypeError do
|
83
|
+
q.percolate_up(i)
|
84
|
+
end
|
85
|
+
assert_raises TypeError do
|
86
|
+
q.percolate_down(i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
[0,1,2,3].each do |i|
|
90
|
+
assert_nothing_raised do
|
91
|
+
q.percolate_up(i)
|
92
|
+
end
|
93
|
+
assert_nothing_raised do
|
94
|
+
q.percolate_down(i)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_build_queue
|
100
|
+
n = 100
|
101
|
+
|
102
|
+
q = RubyVor::PriorityQueue.build_queue(n) do |queue_item|
|
103
|
+
queue_item.priority = rand * 10000.0 - 5000.0
|
104
|
+
end
|
105
|
+
|
106
|
+
assert_equal n, q.data.length
|
107
|
+
assert_equal n, q.size
|
108
|
+
|
109
|
+
old_n = -1.0 * Float::MAX
|
110
|
+
while n = q.pop
|
111
|
+
assert n.priority >= old_n, 'Heap-order property violated'
|
112
|
+
old_n = n.priority
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def assert_nothing_raised(&b)
|
119
|
+
begin
|
120
|
+
yield
|
121
|
+
rescue Exception => e
|
122
|
+
flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
|
123
|
+
return
|
124
|
+
end
|
125
|
+
pass()
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
MiniTest::Unit.autorun
|
@@ -2,24 +2,26 @@ require 'rubygems'
|
|
2
2
|
require 'minitest/unit'
|
3
3
|
require File.dirname(__FILE__) + '/../lib/ruby_vor'
|
4
4
|
|
5
|
+
|
5
6
|
class TestVoronoiInterface < MiniTest::Unit::TestCase
|
6
7
|
|
7
|
-
MAX_DELTA = 0.000001
|
8
|
-
|
9
8
|
def initialize(*args)
|
10
9
|
@points = @trianglulation_raw = @diagram_raw = nil
|
11
10
|
super(*args)
|
12
11
|
end
|
12
|
+
|
13
|
+
|
14
|
+
MAX_DELTA = 0.000001
|
13
15
|
|
14
16
|
def test_diagram_correct
|
15
|
-
# Perform the
|
16
|
-
|
17
|
+
# Perform the computation.
|
18
|
+
comp = RubyVor::VDDT::Computation.from_points(sample_points)
|
17
19
|
|
18
20
|
# Test each raw entry against three basic assertions:
|
19
21
|
# * entry lengths must match
|
20
22
|
# * entry types must match
|
21
23
|
# * entry values must match, with allowance for rounding errors (i.e. within a very small delta)
|
22
|
-
|
24
|
+
comp.voronoi_diagram_raw.each_with_index do |computed_entry, i|
|
23
25
|
sample_entry = example_diagram_raw[i]
|
24
26
|
|
25
27
|
|
@@ -36,15 +38,15 @@ class TestVoronoiInterface < MiniTest::Unit::TestCase
|
|
36
38
|
|
37
39
|
|
38
40
|
def test_triangulation_correct
|
39
|
-
# Perform the
|
40
|
-
|
41
|
+
# Perform the computation.
|
42
|
+
comp = RubyVor::VDDT::Computation.from_points(sample_points)
|
41
43
|
|
42
44
|
# One assertion:
|
43
45
|
# * raw triangulation must match exactly.
|
44
46
|
|
45
|
-
assert_equal example_triangulation_raw,
|
47
|
+
assert_equal example_triangulation_raw, comp.delaunay_triangulation_raw
|
46
48
|
end
|
47
|
-
|
49
|
+
|
48
50
|
|
49
51
|
|
50
52
|
#
|
@@ -153,6 +155,7 @@ class TestVoronoiInterface < MiniTest::Unit::TestCase
|
|
153
155
|
end
|
154
156
|
@trianglulation_raw
|
155
157
|
end
|
158
|
+
|
156
159
|
end
|
157
160
|
|
158
161
|
MiniTest::Unit.autorun
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bribera-rubyvor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brendan Ribera
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-01-15 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -44,14 +44,24 @@ files:
|
|
44
44
|
- ext/heap.c
|
45
45
|
- ext/memory.c
|
46
46
|
- ext/output.c
|
47
|
+
- ext/rb_cComputation.c
|
48
|
+
- ext/rb_cPoint.c
|
49
|
+
- ext/rb_cPriorityQueue.c
|
50
|
+
- ext/ruby_vor_c.c
|
51
|
+
- ext/ruby_vor_c.h
|
47
52
|
- ext/vdefs.h
|
48
53
|
- ext/voronoi.c
|
49
|
-
- ext/voronoi_interface.c
|
50
54
|
- lib/ruby_vor.rb
|
51
|
-
- lib/ruby_vor/
|
55
|
+
- lib/ruby_vor/computation.rb
|
56
|
+
- lib/ruby_vor/geo_ruby_extensions.rb
|
52
57
|
- lib/ruby_vor/point.rb
|
58
|
+
- lib/ruby_vor/priority_queue.rb
|
53
59
|
- lib/ruby_vor/version.rb
|
60
|
+
- lib/ruby_vor/visualizer.rb
|
54
61
|
- rubyvor.gemspec
|
62
|
+
- test/test_computation.rb
|
63
|
+
- test/test_point.rb
|
64
|
+
- test/test_priority_queue.rb
|
55
65
|
- test/test_voronoi_interface.rb
|
56
66
|
has_rdoc: true
|
57
67
|
homepage: http://github.com/bribera/rubyvor
|
@@ -82,4 +92,7 @@ signing_key:
|
|
82
92
|
specification_version: 2
|
83
93
|
summary: RubyVor provides efficient computation of Voronoi diagrams and Delaunay triangulation for a set of Ruby points
|
84
94
|
test_files:
|
95
|
+
- test/test_computation.rb
|
96
|
+
- test/test_priority_queue.rb
|
85
97
|
- test/test_voronoi_interface.rb
|
98
|
+
- test/test_point.rb
|
data/ext/voronoi_interface.c
DELETED
@@ -1,213 +0,0 @@
|
|
1
|
-
#include <ruby.h>
|
2
|
-
#include <vdefs.h>
|
3
|
-
#include <stdio.h>
|
4
|
-
#include <stdlib.h>
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
VoronoiState rubyvorState;
|
10
|
-
|
11
|
-
static VALUE rb_mRubyVor;
|
12
|
-
static VALUE rb_mVDDT;
|
13
|
-
static VALUE rb_cDecomposition;
|
14
|
-
static int repeat, rit;
|
15
|
-
|
16
|
-
// Static method definitions
|
17
|
-
static VALUE from_points(VALUE, VALUE);
|
18
|
-
|
19
|
-
static Site * readone(void), * nextone(void);
|
20
|
-
static int scomp(const void *, const void *);
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
void
|
25
|
-
Init_voronoi_interface(void)
|
26
|
-
{
|
27
|
-
// Set up our Modules and Class.
|
28
|
-
rb_mRubyVor = rb_define_module("RubyVor");
|
29
|
-
rb_mVDDT = rb_define_module_under(rb_mRubyVor, "VDDT");
|
30
|
-
rb_cDecomposition = rb_define_class_under(rb_mVDDT, "Decomposition", rb_cObject);
|
31
|
-
|
32
|
-
// Add methods.
|
33
|
-
rb_define_singleton_method(rb_cDecomposition, "from_points", from_points, 1);
|
34
|
-
}
|
35
|
-
|
36
|
-
|
37
|
-
//
|
38
|
-
// Class methods
|
39
|
-
//
|
40
|
-
static VALUE
|
41
|
-
from_points(VALUE self, VALUE pointsArray)
|
42
|
-
{
|
43
|
-
//VALUE returnValue;
|
44
|
-
VALUE * inPtr, newDecomp;
|
45
|
-
ID x, y;
|
46
|
-
|
47
|
-
long i, inSize;
|
48
|
-
|
49
|
-
// TODO: remove
|
50
|
-
repeat = 1;
|
51
|
-
|
52
|
-
for (rit = 0; rit < repeat; rit++) {
|
53
|
-
|
54
|
-
// Require T_ARRAY
|
55
|
-
Check_Type(pointsArray, T_ARRAY);
|
56
|
-
|
57
|
-
// Intern our point access methods
|
58
|
-
x = rb_intern("x");
|
59
|
-
y = rb_intern("y");
|
60
|
-
|
61
|
-
// Load up point count & points pointer.
|
62
|
-
inSize = RARRAY(pointsArray)->len;
|
63
|
-
inPtr = RARRAY(pointsArray)->ptr;
|
64
|
-
|
65
|
-
// Require nonzero size and x & y methods on each array object
|
66
|
-
if (inSize < 1)
|
67
|
-
rb_raise(rb_eRuntimeError, "points array have a nonzero length");
|
68
|
-
for (i = 0; i < inSize; i++) {
|
69
|
-
if(!rb_respond_to(inPtr[i], x) || !rb_respond_to(inPtr[i], y))
|
70
|
-
rb_raise(rb_eRuntimeError, "members of points array must respond to 'x' and 'y'");
|
71
|
-
}
|
72
|
-
|
73
|
-
|
74
|
-
// Initialize rubyvorState
|
75
|
-
initialize_state(0/* debug? */);
|
76
|
-
|
77
|
-
// Create our return object.
|
78
|
-
newDecomp = rb_funcall(self, rb_intern("new"), 0);
|
79
|
-
// Store it in rubyvorState so we can populate its values.
|
80
|
-
rubyvorState.decomp = (void *) &newDecomp;
|
81
|
-
|
82
|
-
|
83
|
-
//
|
84
|
-
// Read in the sites, sort, and compute xmin, xmax, ymin, ymax
|
85
|
-
//
|
86
|
-
// TODO: refactor this block into a separate method for clarity?
|
87
|
-
//
|
88
|
-
{
|
89
|
-
// Allocate memory for 4000 sites...
|
90
|
-
rubyvorState.sites = (Site *) myalloc(4000 * sizeof(Site));
|
91
|
-
|
92
|
-
|
93
|
-
// Iterate over the arrays, doubling the incoming values.
|
94
|
-
for (i=0; i<inSize; i++)
|
95
|
-
{
|
96
|
-
rubyvorState.sites[rubyvorState.nsites].coord.x = NUM2DBL(rb_funcall(inPtr[i], x, 0));
|
97
|
-
rubyvorState.sites[rubyvorState.nsites].coord.y = NUM2DBL(rb_funcall(inPtr[i], y, 0));
|
98
|
-
|
99
|
-
//
|
100
|
-
rubyvorState.sites[rubyvorState.nsites].sitenbr = rubyvorState.nsites;
|
101
|
-
rubyvorState.sites[rubyvorState.nsites++].refcnt = 0;
|
102
|
-
|
103
|
-
// Allocate for 4000 more if we just hit a multiple of 4000...
|
104
|
-
if (rubyvorState.nsites % 4000 == 0)
|
105
|
-
{
|
106
|
-
rubyvorState.sites = (Site *)myrealloc(rubyvorState.sites,(rubyvorState.nsites+4000)*sizeof(Site),rubyvorState.nsites*sizeof(Site));
|
107
|
-
}
|
108
|
-
}
|
109
|
-
|
110
|
-
// Sort the Sites
|
111
|
-
qsort((void *)rubyvorState.sites, rubyvorState.nsites, sizeof(Site), scomp) ;
|
112
|
-
|
113
|
-
// Pull the minimum values.
|
114
|
-
rubyvorState.xmin = rubyvorState.sites[0].coord.x;
|
115
|
-
rubyvorState.xmax = rubyvorState.sites[0].coord.x;
|
116
|
-
for (i=1; i < rubyvorState.nsites; ++i)
|
117
|
-
{
|
118
|
-
if (rubyvorState.sites[i].coord.x < rubyvorState.xmin)
|
119
|
-
{
|
120
|
-
rubyvorState.xmin = rubyvorState.sites[i].coord.x;
|
121
|
-
}
|
122
|
-
if (rubyvorState.sites[i].coord.x > rubyvorState.xmax)
|
123
|
-
{
|
124
|
-
rubyvorState.xmax = rubyvorState.sites[i].coord.x;
|
125
|
-
}
|
126
|
-
}
|
127
|
-
rubyvorState.ymin = rubyvorState.sites[0].coord.y;
|
128
|
-
rubyvorState.ymax = rubyvorState.sites[rubyvorState.nsites-1].coord.y;
|
129
|
-
|
130
|
-
}
|
131
|
-
|
132
|
-
|
133
|
-
// Perform the computation
|
134
|
-
voronoi(nextone);
|
135
|
-
|
136
|
-
// Free our allocated objects
|
137
|
-
free_all();
|
138
|
-
|
139
|
-
if (rubyvorState.debug)
|
140
|
-
fprintf(stderr,"FINISHED ITERATION %i\n", repeat + 1);
|
141
|
-
|
142
|
-
|
143
|
-
}
|
144
|
-
|
145
|
-
return newDecomp;
|
146
|
-
}
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
//
|
152
|
-
// Static C methods
|
153
|
-
//
|
154
|
-
|
155
|
-
/*** sort sites on y, then x, coord ***/
|
156
|
-
static int
|
157
|
-
scomp(const void * vs1, const void * vs2)
|
158
|
-
{
|
159
|
-
Point * s1 = (Point *)vs1 ;
|
160
|
-
Point * s2 = (Point *)vs2 ;
|
161
|
-
|
162
|
-
if (s1->y < s2->y)
|
163
|
-
{
|
164
|
-
return (-1) ;
|
165
|
-
}
|
166
|
-
if (s1->y > s2->y)
|
167
|
-
{
|
168
|
-
return (1) ;
|
169
|
-
}
|
170
|
-
if (s1->x < s2->x)
|
171
|
-
{
|
172
|
-
return (-1) ;
|
173
|
-
}
|
174
|
-
if (s1->x > s2->x)
|
175
|
-
{
|
176
|
-
return (1) ;
|
177
|
-
}
|
178
|
-
return (0) ;
|
179
|
-
}
|
180
|
-
|
181
|
-
/*** return a single in-storage site ***/
|
182
|
-
static Site *
|
183
|
-
nextone(void)
|
184
|
-
{
|
185
|
-
Site * s ;
|
186
|
-
|
187
|
-
if (rubyvorState.siteidx < rubyvorState.nsites)
|
188
|
-
{
|
189
|
-
s = &rubyvorState.sites[rubyvorState.siteidx++];
|
190
|
-
return (s) ;
|
191
|
-
}
|
192
|
-
else
|
193
|
-
{
|
194
|
-
return ((Site *)NULL) ;
|
195
|
-
}
|
196
|
-
}
|
197
|
-
|
198
|
-
|
199
|
-
/*** read one site ***/
|
200
|
-
static Site *
|
201
|
-
readone(void)
|
202
|
-
{
|
203
|
-
Site * s ;
|
204
|
-
|
205
|
-
s = (Site *)getfree(&(rubyvorState.sfl)) ;
|
206
|
-
s->refcnt = 0 ;
|
207
|
-
s->sitenbr = rubyvorState.siteidx++ ;
|
208
|
-
if (scanf("%f %f", &(s->coord.x), &(s->coord.y)) == EOF)
|
209
|
-
{
|
210
|
-
return ((Site *)NULL ) ;
|
211
|
-
}
|
212
|
-
return (s) ;
|
213
|
-
}
|