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/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
+ }