bribera-rubyvor 0.0.3 → 0.0.4
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 +9 -0
- data/Manifest.txt +7 -0
- data/Rakefile +1 -1
- data/ext/extconf.rb +2 -2
- data/ext/output.c +2 -0
- data/ext/rb_cComputation.c +281 -0
- data/ext/rb_cPriorityQueue.c +106 -0
- data/ext/ruby_vor.c +41 -0
- data/ext/ruby_vor.h +23 -0
- data/ext/vdefs.h +2 -1
- data/ext/voronoi.c +2 -11
- data/lib/ruby_vor/computation.rb +126 -15
- data/lib/ruby_vor/point.rb +4 -0
- data/lib/ruby_vor/priority_queue.rb +60 -0
- data/lib/ruby_vor/version.rb +1 -1
- data/lib/ruby_vor.rb +3 -2
- data/rubyvor.gemspec +8 -6
- data/test/test_computation.rb +175 -0
- data/test/test_priority_queue.rb +56 -0
- data/test/test_voronoi_interface.rb +6 -3
- metadata +11 -2
- data/ext/voronoi_interface.c +0 -217
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 0.0.5 / 2008-12-10
|
2
|
+
|
3
|
+
* Beginnings of clustering and useful graph algorithms.
|
4
|
+
* Some refactoring of C methods.
|
5
|
+
|
6
|
+
=== 0.0.4 / 2008-12-04
|
7
|
+
|
8
|
+
* Fixed 64-bit segfaults due to improper definition of the myrealloc() function.
|
9
|
+
|
1
10
|
=== 0.0.3 / 2008-12-03
|
2
11
|
|
3
12
|
* Fixed a segfault by using rb_ary_push instead of direct pointer manipulation. Much simpler.
|
data/Manifest.txt
CHANGED
@@ -9,12 +9,19 @@ ext/geometry.c
|
|
9
9
|
ext/heap.c
|
10
10
|
ext/memory.c
|
11
11
|
ext/output.c
|
12
|
+
ext/rb_cComputation.c
|
13
|
+
ext/rb_cPriorityQueue.c
|
14
|
+
ext/ruby_vor.c
|
15
|
+
ext/ruby_vor.h
|
12
16
|
ext/vdefs.h
|
13
17
|
ext/voronoi.c
|
14
18
|
ext/voronoi_interface.c
|
15
19
|
lib/ruby_vor.rb
|
16
20
|
lib/ruby_vor/computation.rb
|
17
21
|
lib/ruby_vor/point.rb
|
22
|
+
lib/ruby_vor/priority_queue.rb
|
18
23
|
lib/ruby_vor/version.rb
|
19
24
|
rubyvor.gemspec
|
25
|
+
test/test_computation.rb
|
26
|
+
test/test_priority_queue.rb
|
20
27
|
test/test_voronoi_interface.rb
|
data/Rakefile
CHANGED
data/ext/extconf.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
dir_config('
|
3
|
-
create_makefile('
|
2
|
+
dir_config('ruby_vor')
|
3
|
+
create_makefile('ruby_vor')
|
data/ext/output.c
CHANGED
@@ -237,12 +237,14 @@ debug_memory(void)
|
|
237
237
|
FILE* pf;
|
238
238
|
|
239
239
|
unsigned size;// total program size
|
240
|
+
/*
|
240
241
|
unsigned resident;// resident set size
|
241
242
|
unsigned share;// shared pages
|
242
243
|
unsigned text;// text (code)
|
243
244
|
unsigned lib;// library
|
244
245
|
unsigned data;// data/stack
|
245
246
|
unsigned dt;// dirty pages (unused in Linux 2.6)
|
247
|
+
*/
|
246
248
|
|
247
249
|
int retVal;
|
248
250
|
|
@@ -0,0 +1,281 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor.h>
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <stdlib.h>
|
6
|
+
|
7
|
+
static Site * nextone(void);
|
8
|
+
static int scomp(const void *, const void *);
|
9
|
+
|
10
|
+
//
|
11
|
+
// Class methods for RubyVor::VDDT::Computation
|
12
|
+
//
|
13
|
+
|
14
|
+
|
15
|
+
/*
|
16
|
+
* Compute the voronoi diagram and delaunay triangulation from a set of points.
|
17
|
+
*
|
18
|
+
* This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
|
19
|
+
* It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
|
20
|
+
*/
|
21
|
+
VALUE
|
22
|
+
from_points(VALUE self, VALUE pointsArray)
|
23
|
+
{
|
24
|
+
//VALUE returnValue;
|
25
|
+
VALUE * inPtr, newComp;
|
26
|
+
ID x, y;
|
27
|
+
|
28
|
+
long i, inSize;
|
29
|
+
|
30
|
+
// Require T_ARRAY
|
31
|
+
Check_Type(pointsArray, T_ARRAY);
|
32
|
+
|
33
|
+
// Intern our point access methods
|
34
|
+
x = rb_intern("x");
|
35
|
+
y = rb_intern("y");
|
36
|
+
|
37
|
+
// Load up point count & points pointer.
|
38
|
+
inSize = RARRAY(pointsArray)->len;
|
39
|
+
inPtr = RARRAY(pointsArray)->ptr;
|
40
|
+
|
41
|
+
// Require nonzero size and x & y methods on each array object
|
42
|
+
if (inSize < 1)
|
43
|
+
rb_raise(rb_eRuntimeError, "points array have a nonzero length");
|
44
|
+
for (i = 0; i < inSize; i++) {
|
45
|
+
if(!rb_respond_to(inPtr[i], x) || !rb_respond_to(inPtr[i], y))
|
46
|
+
rb_raise(rb_eRuntimeError, "members of points array must respond to 'x' and 'y'");
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
// Initialize rubyvorState
|
51
|
+
initialize_state(/* debug? */ 0);
|
52
|
+
debug_memory();
|
53
|
+
|
54
|
+
// Create our return object.
|
55
|
+
newComp = rb_funcall(self, rb_intern("new"), 1, pointsArray);
|
56
|
+
// Store it in rubyvorState so we can populate its values.
|
57
|
+
rubyvorState.comp = (void *) &newComp;
|
58
|
+
//
|
59
|
+
// Read in the sites, sort, and compute xmin, xmax, ymin, ymax
|
60
|
+
//
|
61
|
+
// TODO: refactor this block into a separate method for clarity?
|
62
|
+
//
|
63
|
+
{
|
64
|
+
// Allocate memory for 4000 sites...
|
65
|
+
rubyvorState.sites = (Site *) myalloc(4000 * sizeof(Site));
|
66
|
+
|
67
|
+
|
68
|
+
// Iterate over the arrays, doubling the incoming values.
|
69
|
+
for (i=0; i<inSize; i++)
|
70
|
+
{
|
71
|
+
rubyvorState.sites[rubyvorState.nsites].coord.x = NUM2DBL(rb_funcall(inPtr[i], x, 0));
|
72
|
+
rubyvorState.sites[rubyvorState.nsites].coord.y = NUM2DBL(rb_funcall(inPtr[i], y, 0));
|
73
|
+
|
74
|
+
//
|
75
|
+
rubyvorState.sites[rubyvorState.nsites].sitenbr = rubyvorState.nsites;
|
76
|
+
rubyvorState.sites[rubyvorState.nsites++].refcnt = 0;
|
77
|
+
|
78
|
+
// Allocate for 4000 more if we just hit a multiple of 4000...
|
79
|
+
if (rubyvorState.nsites % 4000 == 0)
|
80
|
+
{
|
81
|
+
rubyvorState.sites = (Site *)myrealloc(rubyvorState.sites,(rubyvorState.nsites+4000)*sizeof(Site),rubyvorState.nsites*sizeof(Site));
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
// Sort the Sites
|
86
|
+
qsort((void *)rubyvorState.sites, rubyvorState.nsites, sizeof(Site), scomp) ;
|
87
|
+
|
88
|
+
// Pull the minimum values.
|
89
|
+
rubyvorState.xmin = rubyvorState.sites[0].coord.x;
|
90
|
+
rubyvorState.xmax = rubyvorState.sites[0].coord.x;
|
91
|
+
for (i=1; i < rubyvorState.nsites; ++i)
|
92
|
+
{
|
93
|
+
if (rubyvorState.sites[i].coord.x < rubyvorState.xmin)
|
94
|
+
{
|
95
|
+
rubyvorState.xmin = rubyvorState.sites[i].coord.x;
|
96
|
+
}
|
97
|
+
if (rubyvorState.sites[i].coord.x > rubyvorState.xmax)
|
98
|
+
{
|
99
|
+
rubyvorState.xmax = rubyvorState.sites[i].coord.x;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
rubyvorState.ymin = rubyvorState.sites[0].coord.y;
|
103
|
+
rubyvorState.ymax = rubyvorState.sites[rubyvorState.nsites-1].coord.y;
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
// Perform the computation
|
109
|
+
voronoi(nextone);
|
110
|
+
debug_memory();
|
111
|
+
|
112
|
+
// Get rid of our comp reference
|
113
|
+
rubyvorState.comp = (void *)NULL;
|
114
|
+
|
115
|
+
// Free our allocated objects
|
116
|
+
free_all();
|
117
|
+
debug_memory();
|
118
|
+
|
119
|
+
return newComp;
|
120
|
+
}
|
121
|
+
|
122
|
+
|
123
|
+
//
|
124
|
+
// Instance methods (none)
|
125
|
+
//
|
126
|
+
|
127
|
+
VALUE
|
128
|
+
minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
|
129
|
+
{
|
130
|
+
VALUE dist_proc, nodes, nnGraph, points, queue, tmpHash, tmpArray, adjList, latestAddition;
|
131
|
+
long i, j;
|
132
|
+
|
133
|
+
/* 0 mandatory, 1 optional */
|
134
|
+
rb_scan_args(argc, argv, "01", &dist_proc);
|
135
|
+
|
136
|
+
if (NIL_P(dist_proc)) {
|
137
|
+
// Use our default Proc
|
138
|
+
dist_proc = rb_eval_string("lambda{|a,b| a.distance_from(b)}");
|
139
|
+
} else if (rb_class_of(dist_proc) != rb_cProc) {
|
140
|
+
// Blow up if we have a non-nil, non-Proc
|
141
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(dist_proc), rb_class2name(rb_cProc));
|
142
|
+
}
|
143
|
+
|
144
|
+
points = rb_iv_get(self, "@points");
|
145
|
+
nodes = rb_ary_new2(RARRAY(points)->len);
|
146
|
+
queue = rb_eval_string("RubyVor::PriorityQueue.new(lambda{|a,b| a[:min_distance] < b[:min_distance]})");
|
147
|
+
nnGraph = nn_graph(self);
|
148
|
+
|
149
|
+
for (i=0; i < RARRAY(points)->len; i++) {
|
150
|
+
tmpHash = rb_hash_new();
|
151
|
+
|
152
|
+
// :node => n,
|
153
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("node")), INT2FIX(i));
|
154
|
+
// :min_distance => (n == 0) ? 0.0 : Float::MAX,
|
155
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_distance")), (i == 0) ? INT2FIX(0) : rb_const_get(rb_cFloat, rb_intern("MAX")));
|
156
|
+
// :parent => nil,
|
157
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("parent")), Qnil);
|
158
|
+
// :adjacency_list => nn_graph[n].clone,
|
159
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("adjacency_list")), rb_funcall(RARRAY(nnGraph)->ptr[i], rb_intern("clone"), 0));
|
160
|
+
// :min_adjacency_list => [],
|
161
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_adjacency_list")), rb_ary_new());
|
162
|
+
// :in_q => true
|
163
|
+
rb_hash_aset(tmpHash, ID2SYM(rb_intern("in_q")), Qtrue);
|
164
|
+
|
165
|
+
rb_funcall(queue, rb_intern("push"), 1, tmpHash);
|
166
|
+
}
|
167
|
+
|
168
|
+
tmpArray = rb_funcall(queue, rb_intern("data"), 0);
|
169
|
+
for (i = 0; i < RARRAY(tmpArray)->len; i++) {
|
170
|
+
tmpHash = RARRAY(tmpArray)->ptr[i];
|
171
|
+
adjList = rb_hash_aref(tmpHash, ID2SYM(rb_intern("adjacency_list")));
|
172
|
+
|
173
|
+
for (j = 0; j < RARRAY(adjList)->len; j++)
|
174
|
+
rb_ary_store(adjList, j, RARRAY(tmpArray)->ptr[ FIX2INT(RARRAY(adjList)->ptr[j]) ]);
|
175
|
+
}
|
176
|
+
|
177
|
+
latestAddition = rb_funcall(queue, rb_intern("pop"), 0);
|
178
|
+
while (RTEST(latestAddition)) {
|
179
|
+
rb_hash_aset(latestAddition, ID2SYM(rb_intern("in_q")), Qfalse);
|
180
|
+
|
181
|
+
if (RTEST(rb_hash_aref(latestAddition, ID2SYM(rb_intern("parent"))))) {
|
182
|
+
}
|
183
|
+
break;
|
184
|
+
}
|
185
|
+
|
186
|
+
return tmpArray;
|
187
|
+
}
|
188
|
+
|
189
|
+
VALUE
|
190
|
+
nn_graph(VALUE self)
|
191
|
+
{
|
192
|
+
long i;
|
193
|
+
VALUE dtRaw, graph, points, * dtPtr, * tripletPtr, * graphPtr;
|
194
|
+
ID has_key;
|
195
|
+
graph = rb_iv_get(self, "@nn_graph");
|
196
|
+
|
197
|
+
if (RTEST(graph))
|
198
|
+
return graph;
|
199
|
+
|
200
|
+
// Create an array of same size as points for the graph
|
201
|
+
points = rb_iv_get(self, "@points");
|
202
|
+
graph = rb_ary_new2(RARRAY(points)->len);
|
203
|
+
for (i = 0; i < RARRAY(points)->len; i++)
|
204
|
+
rb_ary_push(graph, rb_ary_new());
|
205
|
+
|
206
|
+
// Get our pointer into this array.
|
207
|
+
graphPtr = RARRAY(graph)->ptr;
|
208
|
+
|
209
|
+
// Iterate over the triangulation
|
210
|
+
dtRaw = rb_iv_get(self, "@delaunay_triangulation_raw");
|
211
|
+
dtPtr = RARRAY(dtRaw)->ptr;
|
212
|
+
for (i = 0; i < RARRAY(dtRaw)->len; i++) {
|
213
|
+
tripletPtr = RARRAY(dtPtr[i])->ptr;
|
214
|
+
|
215
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[0])], tripletPtr[1]);
|
216
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[1])], tripletPtr[0]);
|
217
|
+
|
218
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[0])], tripletPtr[2]);
|
219
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[2])], tripletPtr[0]);
|
220
|
+
|
221
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[1])], tripletPtr[2]);
|
222
|
+
rb_ary_push(graphPtr[FIX2INT(tripletPtr[2])], tripletPtr[1]);
|
223
|
+
}
|
224
|
+
|
225
|
+
for (i = 0; i < RARRAY(graph)->len; i++)
|
226
|
+
rb_funcall(graphPtr[i], rb_intern("uniq!"), 0);
|
227
|
+
|
228
|
+
rb_iv_set(self, "@nn_graph", graph);
|
229
|
+
|
230
|
+
return graph;
|
231
|
+
}
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
//
|
236
|
+
// Static C helper methods
|
237
|
+
//
|
238
|
+
|
239
|
+
|
240
|
+
/*** sort sites on y, then x, coord ***/
|
241
|
+
static int
|
242
|
+
scomp(const void * vs1, const void * vs2)
|
243
|
+
{
|
244
|
+
Point * s1 = (Point *)vs1 ;
|
245
|
+
Point * s2 = (Point *)vs2 ;
|
246
|
+
|
247
|
+
if (s1->y < s2->y)
|
248
|
+
{
|
249
|
+
return (-1) ;
|
250
|
+
}
|
251
|
+
if (s1->y > s2->y)
|
252
|
+
{
|
253
|
+
return (1) ;
|
254
|
+
}
|
255
|
+
if (s1->x < s2->x)
|
256
|
+
{
|
257
|
+
return (-1) ;
|
258
|
+
}
|
259
|
+
if (s1->x > s2->x)
|
260
|
+
{
|
261
|
+
return (1) ;
|
262
|
+
}
|
263
|
+
return (0) ;
|
264
|
+
}
|
265
|
+
|
266
|
+
/*** return a single in-storage site ***/
|
267
|
+
static Site *
|
268
|
+
nextone(void)
|
269
|
+
{
|
270
|
+
Site * s ;
|
271
|
+
|
272
|
+
if (rubyvorState.siteidx < rubyvorState.nsites)
|
273
|
+
{
|
274
|
+
s = &rubyvorState.sites[rubyvorState.siteidx++];
|
275
|
+
return (s) ;
|
276
|
+
}
|
277
|
+
else
|
278
|
+
{
|
279
|
+
return ((Site *)NULL) ;
|
280
|
+
}
|
281
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor.h>
|
4
|
+
|
5
|
+
VALUE
|
6
|
+
compare(VALUE a, VALUE b)
|
7
|
+
{
|
8
|
+
double aD, bD;
|
9
|
+
ID minDistance;
|
10
|
+
minDistance = ID2SYM(rb_intern("min_distance"));
|
11
|
+
|
12
|
+
if (rb_class_of(a) == rb_cQueueItem)
|
13
|
+
aD = NUM2DBL(rb_funcall(a, rb_intern("priority"), 0));
|
14
|
+
else
|
15
|
+
aD = NUM2DBL(a);
|
16
|
+
|
17
|
+
if (rb_class_of(b) == rb_cQueueItem)
|
18
|
+
bD = NUM2DBL(rb_funcall(b, rb_intern("priority"), 0));
|
19
|
+
else
|
20
|
+
bD = NUM2DBL(b);
|
21
|
+
|
22
|
+
return RTEST(aD < bD);
|
23
|
+
}
|
24
|
+
|
25
|
+
VALUE
|
26
|
+
percolate_up(VALUE self, VALUE index)
|
27
|
+
{
|
28
|
+
VALUE item, data;
|
29
|
+
long i, j;
|
30
|
+
|
31
|
+
data = rb_iv_get(self, "@data");
|
32
|
+
Check_Type(data, T_ARRAY);
|
33
|
+
|
34
|
+
i = FIX2INT(index);
|
35
|
+
|
36
|
+
|
37
|
+
j = i / 2;
|
38
|
+
|
39
|
+
item = RARRAY(data)->ptr[i - 1];
|
40
|
+
|
41
|
+
while(j > 0 && compare(item, RARRAY(data)->ptr[j - 1]))
|
42
|
+
{
|
43
|
+
rb_ary_store(data, i-1, RARRAY(data)->ptr[j - 1]);
|
44
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
45
|
+
i = j;
|
46
|
+
j = j / 2;
|
47
|
+
}
|
48
|
+
|
49
|
+
rb_ary_store(data, i-1, item);
|
50
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
51
|
+
|
52
|
+
return Qnil;
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
VALUE
|
57
|
+
percolate_down(VALUE self, VALUE index)
|
58
|
+
{
|
59
|
+
VALUE item, data;
|
60
|
+
long i, j, k, size;
|
61
|
+
|
62
|
+
data = rb_iv_get(self, "@data");
|
63
|
+
Check_Type(data, T_ARRAY);
|
64
|
+
|
65
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
66
|
+
i = FIX2INT(index);
|
67
|
+
|
68
|
+
|
69
|
+
j = size / 2;
|
70
|
+
|
71
|
+
item = RARRAY(data)->ptr[i - 1];
|
72
|
+
|
73
|
+
while (!(i > j))
|
74
|
+
{
|
75
|
+
k = i * 2;
|
76
|
+
if (k < size && compare(RARRAY(data)->ptr[k], RARRAY(data)->ptr[k - 1]))
|
77
|
+
k++;
|
78
|
+
|
79
|
+
if (compare(item, RARRAY(data)->ptr[k - 1]))
|
80
|
+
j = -1;
|
81
|
+
else
|
82
|
+
{
|
83
|
+
rb_ary_store(data, i-1, RARRAY(data)->ptr[k - 1]);
|
84
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
85
|
+
i = k;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
rb_ary_store(data, i-1, item);
|
90
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
91
|
+
|
92
|
+
return Qnil;
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
VALUE
|
97
|
+
heapify(VALUE self)
|
98
|
+
{
|
99
|
+
long i, size;
|
100
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
101
|
+
|
102
|
+
for(i = size / 2; i >= 1; i--)
|
103
|
+
percolate_down(self, INT2FIX(i));
|
104
|
+
|
105
|
+
return Qnil;
|
106
|
+
}
|
data/ext/ruby_vor.c
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor.h>
|
4
|
+
|
5
|
+
void
|
6
|
+
Init_ruby_vor(void)
|
7
|
+
{
|
8
|
+
//
|
9
|
+
// Set up our Modules and Class.
|
10
|
+
//
|
11
|
+
|
12
|
+
/*
|
13
|
+
* Main RubyVor namespace.
|
14
|
+
*/
|
15
|
+
rb_mRubyVor = rb_define_module("RubyVor");
|
16
|
+
|
17
|
+
|
18
|
+
/*
|
19
|
+
* Voronoi Digram and Delaunay Triangulation namespace.
|
20
|
+
*/
|
21
|
+
rb_mVDDT = rb_define_module_under(rb_mRubyVor, "VDDT");
|
22
|
+
|
23
|
+
|
24
|
+
/*
|
25
|
+
* Class representing a VD/DT computation based on a set of 2-dimensional points
|
26
|
+
*/
|
27
|
+
rb_cComputation = rb_define_class_under(rb_mVDDT, "Computation", rb_cObject);
|
28
|
+
rb_define_singleton_method(rb_cComputation, "from_points", from_points, 1);
|
29
|
+
rb_define_method(rb_cComputation, "nn_graph", nn_graph, 0);
|
30
|
+
//rb_define_method(rb_cComputation, "minimum_spanning_tree", minimum_spanning_tree, -1);
|
31
|
+
|
32
|
+
|
33
|
+
/*
|
34
|
+
* A priority queue with a customizable heap-order property.
|
35
|
+
*/
|
36
|
+
rb_cPriorityQueue = rb_define_class_under(rb_mRubyVor, "PriorityQueue", rb_cObject);
|
37
|
+
rb_cQueueItem = rb_define_class_under(rb_cPriorityQueue, "QueueItem", rb_cObject);
|
38
|
+
rb_define_method(rb_cPriorityQueue, "percolate_up", percolate_up, 1);
|
39
|
+
rb_define_method(rb_cPriorityQueue, "percolate_down", percolate_down, 1);
|
40
|
+
rb_define_method(rb_cPriorityQueue, "heapify", heapify, 0);
|
41
|
+
}
|
data/ext/ruby_vor.h
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#ifndef __RUBY_VOR_H
|
2
|
+
#define __RUBY_VOR_H
|
3
|
+
|
4
|
+
extern VoronoiState rubyvorState;
|
5
|
+
|
6
|
+
/* Base modules */
|
7
|
+
VALUE rb_mRubyVor;
|
8
|
+
VALUE rb_mVDDT;
|
9
|
+
|
10
|
+
/* Computation */
|
11
|
+
VALUE rb_cComputation;
|
12
|
+
VALUE from_points(VALUE, VALUE);
|
13
|
+
VALUE nn_graph(VALUE);
|
14
|
+
VALUE minimum_spanning_tree(int, VALUE*, VALUE);
|
15
|
+
|
16
|
+
/* PriorityQueue */
|
17
|
+
VALUE rb_cPriorityQueue;
|
18
|
+
VALUE rb_cQueueItem;
|
19
|
+
VALUE percolate_up(VALUE, VALUE);
|
20
|
+
VALUE percolate_down(VALUE, VALUE);
|
21
|
+
VALUE heapify(VALUE);
|
22
|
+
|
23
|
+
#endif
|
data/ext/vdefs.h
CHANGED
@@ -125,6 +125,7 @@ void freeinit(Freelist *, int) ;
|
|
125
125
|
char *getfree(Freelist *) ;
|
126
126
|
void makefree(Freenode *, Freelist *) ;
|
127
127
|
char *myalloc(unsigned) ;
|
128
|
+
char *myrealloc(void *, unsigned, unsigned);
|
128
129
|
void free_all(void);
|
129
130
|
|
130
131
|
/* output.c */
|
@@ -144,6 +145,6 @@ void debug_memory(void);
|
|
144
145
|
/* voronoi.c */
|
145
146
|
void voronoi(Site *(*)()) ;
|
146
147
|
void initialize_state(int);
|
147
|
-
#endif
|
148
|
+
#endif
|
148
149
|
|
149
150
|
|
data/ext/voronoi.c
CHANGED
@@ -56,16 +56,12 @@ voronoi(Site *(*nextsite)(void))
|
|
56
56
|
|
57
57
|
PQinitialize() ;
|
58
58
|
rubyvorState.bottomsite = (*nextsite)() ;
|
59
|
-
if (rubyvorState.debug) fprintf(stderr, "bnys ");
|
60
59
|
out_site(rubyvorState.bottomsite) ;
|
61
60
|
ELinitialize() ;
|
62
61
|
newsite = (*nextsite)() ;
|
63
62
|
|
64
63
|
while (1)
|
65
64
|
{
|
66
|
-
|
67
|
-
if (rubyvorState.debug) fprintf(stderr, "%d ", c++);
|
68
|
-
|
69
65
|
if(!PQempty())
|
70
66
|
newintstar = PQ_min() ;
|
71
67
|
|
@@ -74,10 +70,8 @@ voronoi(Site *(*nextsite)(void))
|
|
74
70
|
|| (newsite->coord.y == newintstar.y
|
75
71
|
&& newsite->coord.x < newintstar.x)))
|
76
72
|
{
|
77
|
-
if (rubyvorState.debug) fprintf(stderr, "nss ");
|
78
73
|
/* new site is smallest */
|
79
74
|
{
|
80
|
-
if (rubyvorState.debug) fprintf(stderr, "bnys ");
|
81
75
|
out_site(newsite) ;
|
82
76
|
}
|
83
77
|
lbnd = ELleftbnd(&(newsite->coord)) ;
|
@@ -104,14 +98,12 @@ voronoi(Site *(*nextsite)(void))
|
|
104
98
|
}
|
105
99
|
else if (!PQempty()) /* intersection is smallest */
|
106
100
|
{
|
107
|
-
if (rubyvorState.debug) fprintf(stderr, "!pqe ");
|
108
101
|
lbnd = PQextractmin() ;
|
109
102
|
llbnd = ELleft(lbnd) ;
|
110
103
|
rbnd = ELright(lbnd) ;
|
111
104
|
rrbnd = ELright(rbnd) ;
|
112
105
|
bot = leftreg(lbnd) ;
|
113
106
|
top = rightreg(rbnd) ;
|
114
|
-
if (rubyvorState.debug) fprintf(stderr, "bnyt ");
|
115
107
|
out_triple(bot, top, rightreg(lbnd)) ;
|
116
108
|
v = lbnd->vertex ;
|
117
109
|
makevertex(v) ;
|
@@ -156,7 +148,6 @@ voronoi(Site *(*nextsite)(void))
|
|
156
148
|
lbnd = ELright(lbnd))
|
157
149
|
{
|
158
150
|
e = lbnd->ELedge ;
|
159
|
-
if (rubyvorState.debug) fprintf(stderr, "bnye ");
|
160
151
|
out_ep(e) ;
|
161
152
|
}
|
162
153
|
}
|
@@ -168,15 +159,15 @@ voronoi(Site *(*nextsite)(void))
|
|
168
159
|
// Static storage methods
|
169
160
|
//
|
170
161
|
|
171
|
-
|
172
162
|
/*** stores a triplet of point indices that comprise a Delaunay triangle ***/
|
173
163
|
static void
|
174
164
|
storeTriangulationTriplet(const int a, const int b, const int c)
|
175
165
|
{
|
176
166
|
VALUE trArray, triplet;
|
177
|
-
|
167
|
+
|
178
168
|
// Create a new triplet from the three incoming points
|
179
169
|
triplet = rb_ary_new2(3);
|
170
|
+
|
180
171
|
rb_ary_push(triplet, INT2FIX(a));
|
181
172
|
rb_ary_push(triplet, INT2FIX(b));
|
182
173
|
rb_ary_push(triplet, INT2FIX(c));
|