bribera-rubyvor 0.0.2
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 +7 -0
- data/Manifest.txt +20 -0
- data/README.txt +45 -0
- data/Rakefile +36 -0
- data/ext/Doc +30 -0
- data/ext/edgelist.c +206 -0
- data/ext/extconf.rb +3 -0
- data/ext/geometry.c +221 -0
- data/ext/heap.c +120 -0
- data/ext/memory.c +120 -0
- data/ext/output.c +262 -0
- data/ext/vdefs.h +149 -0
- data/ext/voronoi.c +277 -0
- data/ext/voronoi_interface.c +213 -0
- data/lib/ruby_vor/decomposition.rb +22 -0
- data/lib/ruby_vor/point.rb +19 -0
- data/lib/ruby_vor/version.rb +3 -0
- data/lib/ruby_vor.rb +13 -0
- data/rubyvor.gemspec +34 -0
- data/test/test_voronoi_interface.rb +158 -0
- metadata +85 -0
data/ext/vdefs.h
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
#ifndef __VDEFS_H
|
2
|
+
#define __VDEFS_H
|
3
|
+
|
4
|
+
#ifndef NULL
|
5
|
+
#define NULL 0
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#define DELETED -2
|
9
|
+
|
10
|
+
typedef struct tagFreenode
|
11
|
+
{
|
12
|
+
struct tagFreenode * nextfree;
|
13
|
+
} Freenode ;
|
14
|
+
|
15
|
+
|
16
|
+
typedef struct tagFreelist
|
17
|
+
{
|
18
|
+
Freenode * head;
|
19
|
+
int nodesize;
|
20
|
+
} Freelist ;
|
21
|
+
|
22
|
+
typedef struct tagPoint
|
23
|
+
{
|
24
|
+
float x ;
|
25
|
+
float y ;
|
26
|
+
} Point ;
|
27
|
+
|
28
|
+
/* structure used both for sites and for vertices */
|
29
|
+
|
30
|
+
typedef struct tagSite
|
31
|
+
{
|
32
|
+
Point coord ;
|
33
|
+
int sitenbr ;
|
34
|
+
int refcnt ;
|
35
|
+
} Site ;
|
36
|
+
|
37
|
+
|
38
|
+
typedef struct tagEdge
|
39
|
+
{
|
40
|
+
float a, b, c ;
|
41
|
+
Site * ep[2] ;
|
42
|
+
Site * reg[2] ;
|
43
|
+
int edgenbr ;
|
44
|
+
} Edge ;
|
45
|
+
|
46
|
+
#define le 0
|
47
|
+
#define re 1
|
48
|
+
|
49
|
+
typedef struct tagHalfedge
|
50
|
+
{
|
51
|
+
struct tagHalfedge * ELleft ;
|
52
|
+
struct tagHalfedge * ELright ;
|
53
|
+
Edge * ELedge ;
|
54
|
+
int ELrefcnt ;
|
55
|
+
char ELpm ;
|
56
|
+
Site * vertex ;
|
57
|
+
float ystar ;
|
58
|
+
struct tagHalfedge * PQnext ;
|
59
|
+
} Halfedge ;
|
60
|
+
|
61
|
+
typedef struct tagVoronoiState
|
62
|
+
{
|
63
|
+
/* voronoi.c */
|
64
|
+
int sorted, plot, debug, siteidx;
|
65
|
+
float xmin, xmax, ymin, ymax;
|
66
|
+
Site * sites;
|
67
|
+
void * decomp;
|
68
|
+
void (* storeT)(int, int, int);
|
69
|
+
void (* storeL)(float, float, float);
|
70
|
+
void (* storeE)(int, int, int);
|
71
|
+
void (* storeV)(float, float);
|
72
|
+
void (* storeS)(float, float);
|
73
|
+
|
74
|
+
/* geometry.c */
|
75
|
+
float deltax, deltay;
|
76
|
+
int nsites, nedges, sqrt_nsites, nvertices;
|
77
|
+
Freelist sfl;
|
78
|
+
|
79
|
+
/* edgelist.c */
|
80
|
+
int ELhashsize;
|
81
|
+
Site * bottomsite;
|
82
|
+
} VoronoiState;
|
83
|
+
|
84
|
+
extern VoronoiState rubyvorState;
|
85
|
+
|
86
|
+
/* edgelist.c */
|
87
|
+
void ELinitialize(void) ;
|
88
|
+
Halfedge * HEcreate(Edge *, int) ;
|
89
|
+
void ELinsert(Halfedge *, Halfedge *) ;
|
90
|
+
Halfedge * ELgethash(int) ;
|
91
|
+
Halfedge * ELleftbnd(Point *) ;
|
92
|
+
void ELdelete(Halfedge *) ;
|
93
|
+
Halfedge * ELright(Halfedge *) ;
|
94
|
+
Halfedge * ELleft(Halfedge *) ;
|
95
|
+
Site * leftreg(Halfedge *) ;
|
96
|
+
Site * rightreg(Halfedge *) ;
|
97
|
+
Halfedge * getELleftend(void) ;
|
98
|
+
Halfedge * getELrightend(void) ;
|
99
|
+
|
100
|
+
/* geometry.c */
|
101
|
+
void geominit(void) ;
|
102
|
+
Edge * bisect(Site *, Site *) ;
|
103
|
+
Site * intersect(Halfedge *, Halfedge *) ;
|
104
|
+
int right_of(Halfedge *, Point *) ;
|
105
|
+
void endpoint(Edge *, int, Site *) ;
|
106
|
+
float dist(Site *, Site *) ;
|
107
|
+
void makevertex(Site *) ;
|
108
|
+
void deref(Site *) ;
|
109
|
+
void ref(Site *) ;
|
110
|
+
|
111
|
+
/* heap.c */
|
112
|
+
void PQinsert(Halfedge *, Site *, float) ;
|
113
|
+
void PQdelete(Halfedge *) ;
|
114
|
+
int PQbucket(Halfedge *) ;
|
115
|
+
int PQempty(void) ;
|
116
|
+
Point PQ_min(void) ;
|
117
|
+
Halfedge * PQextractmin(void) ;
|
118
|
+
void PQinitialize(void) ;
|
119
|
+
|
120
|
+
/* getopt.c */
|
121
|
+
extern int getopt(int, char *const *, const char *);
|
122
|
+
|
123
|
+
/* memory.c */
|
124
|
+
void freeinit(Freelist *, int) ;
|
125
|
+
char *getfree(Freelist *) ;
|
126
|
+
void makefree(Freenode *, Freelist *) ;
|
127
|
+
char *myalloc(unsigned) ;
|
128
|
+
void free_all(void);
|
129
|
+
|
130
|
+
/* output.c */
|
131
|
+
void openpl(void) ;
|
132
|
+
void line(float, float, float, float) ;
|
133
|
+
void circle(float, float, float) ;
|
134
|
+
void range(float, float, float, float) ;
|
135
|
+
void out_bisector(Edge *) ;
|
136
|
+
void out_ep(Edge *) ;
|
137
|
+
void out_vertex(Site *) ;
|
138
|
+
void out_site(Site *) ;
|
139
|
+
void out_triple(Site *, Site *, Site *) ;
|
140
|
+
void plotinit(void) ;
|
141
|
+
void clip_line(Edge *) ;
|
142
|
+
void debug_memory(void);
|
143
|
+
|
144
|
+
/* voronoi.c */
|
145
|
+
void voronoi(Site *(*)()) ;
|
146
|
+
void initialize_state(int);
|
147
|
+
#endif
|
148
|
+
|
149
|
+
|
data/ext/voronoi.c
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
|
2
|
+
/*** VORONOI.C ***/
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <vdefs.h>
|
6
|
+
|
7
|
+
|
8
|
+
// Static method definitions: C -> Ruby storage methods.
|
9
|
+
static void storeTriangulationTriplet(const int, const int, const int);
|
10
|
+
static void storeLine(const float, const float, const float);
|
11
|
+
static void storeEndpoint(const int, const int, const int);
|
12
|
+
static void storeVertex(const float, const float);
|
13
|
+
static void storeSite(const float, const float);
|
14
|
+
|
15
|
+
/*** implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
|
16
|
+
: deltax, deltay (can all be estimates).
|
17
|
+
: Performance suffers if they are wrong; better to make nsites,
|
18
|
+
: deltax, and deltay too big than too small. (?)
|
19
|
+
***/
|
20
|
+
|
21
|
+
void initialize_state(int debug)
|
22
|
+
{
|
23
|
+
// Set up our initial state
|
24
|
+
rubyvorState.debug = debug;
|
25
|
+
rubyvorState.plot = 0;
|
26
|
+
rubyvorState.nsites = 0;
|
27
|
+
rubyvorState.siteidx = 0;
|
28
|
+
|
29
|
+
rubyvorState.storeT = storeTriangulationTriplet;
|
30
|
+
rubyvorState.storeL = storeLine;
|
31
|
+
rubyvorState.storeE = storeEndpoint;
|
32
|
+
rubyvorState.storeV = storeVertex;
|
33
|
+
rubyvorState.storeS = storeSite;
|
34
|
+
|
35
|
+
// Initialize the Site Freelist
|
36
|
+
freeinit(&(rubyvorState.sfl), sizeof(Site)) ;
|
37
|
+
|
38
|
+
// Initialize the geometry module
|
39
|
+
geominit() ;
|
40
|
+
|
41
|
+
// TODO: remove C plot references
|
42
|
+
if (rubyvorState.plot)
|
43
|
+
plotinit();
|
44
|
+
|
45
|
+
debug_memory();
|
46
|
+
}
|
47
|
+
|
48
|
+
void
|
49
|
+
voronoi(Site *(*nextsite)(void))
|
50
|
+
{
|
51
|
+
Site * newsite, * bot, * top, * temp, * p, * v ;
|
52
|
+
Point newintstar ;
|
53
|
+
int pm ;
|
54
|
+
Halfedge * lbnd, * rbnd, * llbnd, * rrbnd, * bisector ;
|
55
|
+
Edge * e ;
|
56
|
+
|
57
|
+
PQinitialize() ;
|
58
|
+
rubyvorState.bottomsite = (*nextsite)() ;
|
59
|
+
out_site(rubyvorState.bottomsite) ;
|
60
|
+
ELinitialize() ;
|
61
|
+
newsite = (*nextsite)() ;
|
62
|
+
while (1)
|
63
|
+
{
|
64
|
+
if(!PQempty())
|
65
|
+
{
|
66
|
+
newintstar = PQ_min() ;
|
67
|
+
}
|
68
|
+
if (newsite != (Site *)NULL && (PQempty()
|
69
|
+
|| newsite -> coord.y < newintstar.y
|
70
|
+
|| (newsite->coord.y == newintstar.y
|
71
|
+
&& newsite->coord.x < newintstar.x)))
|
72
|
+
{
|
73
|
+
/* new site is smallest */
|
74
|
+
{
|
75
|
+
out_site(newsite) ;
|
76
|
+
}
|
77
|
+
lbnd = ELleftbnd(&(newsite->coord)) ;
|
78
|
+
rbnd = ELright(lbnd) ;
|
79
|
+
bot = rightreg(lbnd) ;
|
80
|
+
e = bisect(bot, newsite) ;
|
81
|
+
bisector = HEcreate(e, le) ;
|
82
|
+
ELinsert(lbnd, bisector) ;
|
83
|
+
p = intersect(lbnd, bisector) ;
|
84
|
+
if (p != (Site *)NULL)
|
85
|
+
{
|
86
|
+
PQdelete(lbnd) ;
|
87
|
+
PQinsert(lbnd, p, dist(p,newsite)) ;
|
88
|
+
}
|
89
|
+
lbnd = bisector ;
|
90
|
+
bisector = HEcreate(e, re) ;
|
91
|
+
ELinsert(lbnd, bisector) ;
|
92
|
+
p = intersect(bisector, rbnd) ;
|
93
|
+
if (p != (Site *)NULL)
|
94
|
+
{
|
95
|
+
PQinsert(bisector, p, dist(p,newsite)) ;
|
96
|
+
}
|
97
|
+
newsite = (*nextsite)() ;
|
98
|
+
}
|
99
|
+
else if (!PQempty()) /* intersection is smallest */
|
100
|
+
{
|
101
|
+
lbnd = PQextractmin() ;
|
102
|
+
llbnd = ELleft(lbnd) ;
|
103
|
+
rbnd = ELright(lbnd) ;
|
104
|
+
rrbnd = ELright(rbnd) ;
|
105
|
+
bot = leftreg(lbnd) ;
|
106
|
+
top = rightreg(rbnd) ;
|
107
|
+
out_triple(bot, top, rightreg(lbnd)) ;
|
108
|
+
v = lbnd->vertex ;
|
109
|
+
makevertex(v) ;
|
110
|
+
endpoint(lbnd->ELedge, lbnd->ELpm, v);
|
111
|
+
endpoint(rbnd->ELedge, rbnd->ELpm, v) ;
|
112
|
+
ELdelete(lbnd) ;
|
113
|
+
PQdelete(rbnd) ;
|
114
|
+
ELdelete(rbnd) ;
|
115
|
+
pm = le ;
|
116
|
+
if (bot->coord.y > top->coord.y)
|
117
|
+
{
|
118
|
+
temp = bot ;
|
119
|
+
bot = top ;
|
120
|
+
top = temp ;
|
121
|
+
pm = re ;
|
122
|
+
}
|
123
|
+
e = bisect(bot, top) ;
|
124
|
+
bisector = HEcreate(e, pm) ;
|
125
|
+
ELinsert(llbnd, bisector) ;
|
126
|
+
endpoint(e, re-pm, v) ;
|
127
|
+
deref(v) ;
|
128
|
+
p = intersect(llbnd, bisector) ;
|
129
|
+
if (p != (Site *) NULL)
|
130
|
+
{
|
131
|
+
PQdelete(llbnd) ;
|
132
|
+
PQinsert(llbnd, p, dist(p,bot)) ;
|
133
|
+
}
|
134
|
+
p = intersect(bisector, rrbnd) ;
|
135
|
+
if (p != (Site *) NULL)
|
136
|
+
{
|
137
|
+
PQinsert(bisector, p, dist(p,bot)) ;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
else
|
141
|
+
{
|
142
|
+
break ;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
for( lbnd = ELright(getELleftend()) ;
|
147
|
+
lbnd != getELrightend() ;
|
148
|
+
lbnd = ELright(lbnd))
|
149
|
+
{
|
150
|
+
e = lbnd->ELedge ;
|
151
|
+
out_ep(e) ;
|
152
|
+
}
|
153
|
+
|
154
|
+
// After completing calculations
|
155
|
+
debug_memory();
|
156
|
+
}
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
//
|
162
|
+
// Static storage methods
|
163
|
+
//
|
164
|
+
|
165
|
+
|
166
|
+
/*** stores a triplet of point indices that comprise a Delaunay triangle ***/
|
167
|
+
static void
|
168
|
+
storeTriangulationTriplet(const int a, const int b, const int c)
|
169
|
+
{
|
170
|
+
VALUE trArray, triplet;
|
171
|
+
|
172
|
+
// Create a new triplet from the three incoming points
|
173
|
+
triplet = rb_ary_new2(3);
|
174
|
+
RARRAY(triplet)->len = 3;
|
175
|
+
RARRAY(triplet)->ptr[0] = INT2FIX(a);
|
176
|
+
RARRAY(triplet)->ptr[1] = INT2FIX(b);
|
177
|
+
RARRAY(triplet)->ptr[2] = INT2FIX(c);
|
178
|
+
|
179
|
+
// Get the existing raw triangulation
|
180
|
+
trArray = rb_funcall(*(VALUE *)rubyvorState.decomp, rb_intern("delaunay_triangulation_raw"), 0);
|
181
|
+
|
182
|
+
// Add the new triplet to it
|
183
|
+
rb_ary_push(trArray, triplet);
|
184
|
+
}
|
185
|
+
|
186
|
+
|
187
|
+
/*** stores a line defined by ax + by = c ***/
|
188
|
+
static void
|
189
|
+
storeLine(const float a, const float b, const float c)
|
190
|
+
{
|
191
|
+
VALUE lArray, line;
|
192
|
+
|
193
|
+
// Create a new line from the three values
|
194
|
+
line = rb_ary_new2(4);
|
195
|
+
RARRAY(line)->len = 4;
|
196
|
+
RARRAY(line)->ptr[0] = ID2SYM(rb_intern("l"));
|
197
|
+
RARRAY(line)->ptr[1] = rb_float_new(a);
|
198
|
+
RARRAY(line)->ptr[2] = rb_float_new(b);
|
199
|
+
RARRAY(line)->ptr[3] = rb_float_new(c);
|
200
|
+
|
201
|
+
// Get the existing raw voronoi diagram
|
202
|
+
lArray = rb_funcall(*(VALUE *)rubyvorState.decomp, rb_intern("voronoi_diagram_raw"), 0);
|
203
|
+
|
204
|
+
// Add the new line to it
|
205
|
+
rb_ary_push(lArray, line);
|
206
|
+
}
|
207
|
+
|
208
|
+
|
209
|
+
/***
|
210
|
+
* Stores a Voronoi segment which is a subsegment of line number l;
|
211
|
+
* with endpoints numbered v1 and v2. If v1 or v2 is -1, the line
|
212
|
+
* extends to infinity.
|
213
|
+
***/
|
214
|
+
static void
|
215
|
+
storeEndpoint(const int l, const int v1, const int v2)
|
216
|
+
{
|
217
|
+
VALUE eArray, endpoint;
|
218
|
+
|
219
|
+
// Create a new endpoint from the three values
|
220
|
+
endpoint = rb_ary_new2(4);
|
221
|
+
RARRAY(endpoint)->len = 4;
|
222
|
+
RARRAY(endpoint)->ptr[0] = ID2SYM(rb_intern("e"));
|
223
|
+
RARRAY(endpoint)->ptr[1] = INT2FIX(l);
|
224
|
+
RARRAY(endpoint)->ptr[2] = INT2FIX(v1);
|
225
|
+
RARRAY(endpoint)->ptr[3] = INT2FIX(v2);
|
226
|
+
|
227
|
+
// Get the existing raw voronoi diagram
|
228
|
+
eArray = rb_funcall(*(VALUE *)rubyvorState.decomp, rb_intern("voronoi_diagram_raw"), 0);
|
229
|
+
|
230
|
+
// Add the new endpoint to it
|
231
|
+
rb_ary_push(eArray, endpoint);
|
232
|
+
}
|
233
|
+
|
234
|
+
|
235
|
+
/*** stores a vertex at (a,b) ***/
|
236
|
+
static void
|
237
|
+
storeVertex(const float a, const float b)
|
238
|
+
{
|
239
|
+
VALUE vArray, vertex;
|
240
|
+
|
241
|
+
// Create a new vertex from the coordinates
|
242
|
+
vertex = rb_ary_new2(3);
|
243
|
+
RARRAY(vertex)->len = 3;
|
244
|
+
RARRAY(vertex)->ptr[0] = ID2SYM(rb_intern("v"));
|
245
|
+
RARRAY(vertex)->ptr[1] = rb_float_new(a);
|
246
|
+
RARRAY(vertex)->ptr[2] = rb_float_new(b);
|
247
|
+
|
248
|
+
// Get the existing raw voronoi diagram
|
249
|
+
vArray = rb_funcall(*(VALUE *)rubyvorState.decomp, rb_intern("voronoi_diagram_raw"), 0);
|
250
|
+
|
251
|
+
// Add the new vertex to it
|
252
|
+
rb_ary_push(vArray, vertex);
|
253
|
+
}
|
254
|
+
|
255
|
+
|
256
|
+
/***
|
257
|
+
* stores an input site at (x,y)
|
258
|
+
* TODO: redundant?
|
259
|
+
***/
|
260
|
+
static void
|
261
|
+
storeSite(const float x, const float y)
|
262
|
+
{
|
263
|
+
VALUE sArray, site;
|
264
|
+
|
265
|
+
// Create a new site from the coordinates
|
266
|
+
site = rb_ary_new2(3);
|
267
|
+
RARRAY(site)->len = 3;
|
268
|
+
RARRAY(site)->ptr[0] = ID2SYM(rb_intern("s"));
|
269
|
+
RARRAY(site)->ptr[1] = rb_float_new(x);
|
270
|
+
RARRAY(site)->ptr[2] = rb_float_new(y);
|
271
|
+
|
272
|
+
// Get the existing raw voronoi diagram
|
273
|
+
sArray = rb_funcall(*(VALUE *)rubyvorState.decomp, rb_intern("voronoi_diagram_raw"), 0);
|
274
|
+
|
275
|
+
// Add the new site to it
|
276
|
+
rb_ary_push(sArray, site);
|
277
|
+
}
|
@@ -0,0 +1,213 @@
|
|
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
|
+
}
|