abscondment-rubyvor 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,115 @@
1
+ #include <ruby.h>
2
+ #include <vdefs.h>
3
+ #include <ruby_vor_c.h>
4
+
5
+ /* Classes & Modules */
6
+ static VALUE RubyVor_rb_mRubyVor;
7
+ static VALUE RubyVor_rb_mVDDT;
8
+
9
+ static VALUE RubyVor_rb_cComputation;
10
+ static VALUE RubyVor_rb_cPriorityQueue;
11
+ static VALUE RubyVor_rb_cQueueItem;
12
+ static VALUE RubyVor_rb_cPoint;
13
+
14
+ /*
15
+ * Extension initialization
16
+ */
17
+ void
18
+ Init_ruby_vor_c(void)
19
+ {
20
+ /*
21
+ * Set up our Modules and Class.
22
+ */
23
+
24
+ /*
25
+ * Main RubyVor namespace.
26
+ */
27
+ RubyVor_rb_mRubyVor = rb_define_module("RubyVor");
28
+
29
+
30
+ /*
31
+ * Voronoi Digram and Delaunay Triangulation namespace.
32
+ */
33
+ RubyVor_rb_mVDDT = rb_define_module_under(RubyVor_rb_mRubyVor, "VDDT");
34
+
35
+
36
+ /*
37
+ * Class representing a VD/DT computation based on a set of 2-dimensional points
38
+ */
39
+ RubyVor_rb_cComputation = rb_define_class_under(RubyVor_rb_mVDDT, "Computation", rb_cObject);
40
+ rb_define_singleton_method(RubyVor_rb_cComputation, "from_points", RubyVor_from_points, 1);
41
+ rb_define_method(RubyVor_rb_cComputation, "nn_graph", RubyVor_nn_graph, 0);
42
+ rb_define_method(RubyVor_rb_cComputation, "minimum_spanning_tree", RubyVor_minimum_spanning_tree, -1);
43
+
44
+
45
+ /*
46
+ * A priority queue with a customizable heap-order property.
47
+ */
48
+ RubyVor_rb_cPriorityQueue = rb_define_class_under(RubyVor_rb_mRubyVor, "PriorityQueue", rb_cObject);
49
+ RubyVor_rb_cQueueItem = rb_define_class_under(RubyVor_rb_cPriorityQueue, "QueueItem", rb_cObject);
50
+ rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_up", RubyVor_percolate_up, 1);
51
+ rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_down", RubyVor_percolate_down, 1);
52
+ rb_define_method(RubyVor_rb_cPriorityQueue, "heapify", RubyVor_heapify, 0);
53
+
54
+
55
+ /*
56
+ * A simple Point class
57
+ */
58
+ RubyVor_rb_cPoint = rb_define_class_under(RubyVor_rb_mRubyVor, "Point", rb_cObject);
59
+ rb_define_method(RubyVor_rb_cPoint, "distance_from", RubyVor_distance_from, 1);
60
+ rb_define_method(RubyVor_rb_cPoint, "hash", RubyVor_point_hash, 0);
61
+ }
62
+
63
+
64
+
65
+
66
+ /*
67
+ * Method declarations duplicated here for RDOC
68
+ */
69
+
70
+ /*
71
+ * Compute the voronoi diagram and delaunay triangulation from a set of points.
72
+ *
73
+ * This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
74
+ * It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
75
+ */
76
+ VALUE RubyVor_from_points(VALUE, VALUE);
77
+
78
+ /*
79
+ * Compute the nearest-neighbor graph using the existing Delaunay triangulation.
80
+ */
81
+ VALUE RubyVor_nn_graph(VALUE);
82
+
83
+ /*
84
+ * Computes the minimum spanning tree for given points, using the Delaunay triangulation as a seed.
85
+ *
86
+ * For points on a Euclidean plane, the MST is always comprised of a subset of the edges in a Delaunay triangulation. This makes computation of the tree very efficient: simply compute the Delaunay triangulation, and then run Prim's algorithm on the resulting edges.
87
+ */
88
+ VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
89
+
90
+ /*
91
+ * Move from the given index up, restoring the heap-order property.
92
+ */
93
+ VALUE RubyVor_percolate_up(VALUE, VALUE);
94
+
95
+ /*
96
+ * Move from the index down, restoring the heap-order property.
97
+ */
98
+ VALUE RubyVor_percolate_down(VALUE, VALUE);
99
+
100
+ /*
101
+ * Restore the heap-order property for a randomly ordered array of entries.
102
+ */
103
+ VALUE RubyVor_heapify(VALUE);
104
+
105
+ /*
106
+ * Compute the Euclidean distance between two points.
107
+ */
108
+ VALUE RubyVor_distance_from(VALUE, VALUE);
109
+
110
+ /*
111
+ * Hash value for a point.
112
+ */
113
+ VALUE RubyVor_point_hash(VALUE);
114
+
115
+ /* keep comment so RDOC will find the last method definition */
@@ -0,0 +1,28 @@
1
+ #ifndef __RUBY_VOR_H
2
+ #define __RUBY_VOR_H
3
+
4
+ #ifndef RB_LONG_BITS
5
+ #define RB_LONG_BITS sizeof(long)*8
6
+ #endif
7
+
8
+ #ifndef RB_HASH_FILTER
9
+ #define RB_HASH_FILTER ((2 << (RB_LONG_BITS / 2 - 1)) - 1)
10
+ #endif
11
+
12
+ extern VoronoiState rubyvorState;
13
+
14
+ /* Computation */
15
+ VALUE RubyVor_from_points(VALUE, VALUE);
16
+ VALUE RubyVor_nn_graph(VALUE);
17
+ VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
18
+
19
+ /* PriorityQueue */
20
+ VALUE RubyVor_percolate_up(VALUE, VALUE);
21
+ VALUE RubyVor_percolate_down(VALUE, VALUE);
22
+ VALUE RubyVor_heapify(VALUE);
23
+
24
+ /* Point */
25
+ VALUE RubyVor_distance_from(VALUE, VALUE);
26
+ VALUE RubyVor_point_hash(VALUE);
27
+
28
+ #endif
@@ -0,0 +1,150 @@
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 * comp;
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
+ char *myrealloc(void *, unsigned, unsigned);
129
+ void free_all(void);
130
+
131
+ /* output.c */
132
+ void openpl(void) ;
133
+ void line(float, float, float, float) ;
134
+ void circle(float, float, float) ;
135
+ void range(float, float, float, float) ;
136
+ void out_bisector(Edge *) ;
137
+ void out_ep(Edge *) ;
138
+ void out_vertex(Site *) ;
139
+ void out_site(Site *) ;
140
+ void out_triple(Site *, Site *, Site *) ;
141
+ void plotinit(void) ;
142
+ void clip_line(Edge *) ;
143
+ void debug_memory(void);
144
+
145
+ /* voronoi.c */
146
+ void voronoi(Site *(*)()) ;
147
+ void initialize_state(int);
148
+ #endif
149
+
150
+
@@ -0,0 +1,271 @@
1
+
2
+ /*** VORONOI.C ***/
3
+
4
+ #include <ruby.h>
5
+ #include <vdefs.h>
6
+ #include <stdio.h>
7
+
8
+ VoronoiState rubyvorState;
9
+
10
+ /* Static method definitions: C -> Ruby storage methods. */
11
+ static void storeTriangulationTriplet(const int, const int, const int);
12
+ static void storeLine(const float, const float, const float);
13
+ static void storeEndpoint(const int, const int, const int);
14
+ static void storeVertex(const float, const float);
15
+ static void storeSite(const float, const float);
16
+
17
+ /*** implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
18
+ : deltax, deltay (can all be estimates).
19
+ : Performance suffers if they are wrong; better to make nsites,
20
+ : deltax, and deltay too big than too small. (?)
21
+ ***/
22
+
23
+ void initialize_state(int debug)
24
+ {
25
+ /* Set up our initial state */
26
+ rubyvorState.debug = debug;
27
+ rubyvorState.plot = 0;
28
+ rubyvorState.nsites = 0;
29
+ rubyvorState.siteidx = 0;
30
+
31
+ rubyvorState.storeT = storeTriangulationTriplet;
32
+ rubyvorState.storeL = storeLine;
33
+ rubyvorState.storeE = storeEndpoint;
34
+ rubyvorState.storeV = storeVertex;
35
+ rubyvorState.storeS = storeSite;
36
+
37
+ /* Initialize the Site Freelist */
38
+ freeinit(&(rubyvorState.sfl), sizeof(Site)) ;
39
+
40
+ /* Initialize the geometry module */
41
+ geominit() ;
42
+
43
+ /* TODO: remove C plot references */
44
+ if (rubyvorState.plot)
45
+ plotinit();
46
+ }
47
+
48
+ void
49
+ voronoi(Site *(*nextsite)(void))
50
+ {
51
+ Site * newsite, * bot, * top, * temp, * p, * v ;
52
+ Point newintstar ;
53
+ int pm , c;
54
+ Halfedge * lbnd, * rbnd, * llbnd, * rrbnd, * bisector ;
55
+ Edge * e ;
56
+
57
+ newintstar.x = newintstar.y = c = 0;
58
+
59
+ PQinitialize() ;
60
+ rubyvorState.bottomsite = (*nextsite)() ;
61
+ out_site(rubyvorState.bottomsite) ;
62
+ ELinitialize() ;
63
+ newsite = (*nextsite)() ;
64
+
65
+ while (1)
66
+ {
67
+ if(!PQempty())
68
+ newintstar = PQ_min() ;
69
+
70
+ if (newsite != (Site *)NULL && (PQempty()
71
+ || newsite -> coord.y < newintstar.y
72
+ || (newsite->coord.y == newintstar.y
73
+ && newsite->coord.x < newintstar.x)))
74
+ {
75
+ /* new site is smallest */
76
+ {
77
+ out_site(newsite) ;
78
+ }
79
+ lbnd = ELleftbnd(&(newsite->coord)) ;
80
+ rbnd = ELright(lbnd) ;
81
+ bot = rightreg(lbnd) ;
82
+ e = bisect(bot, newsite) ;
83
+ bisector = HEcreate(e, le) ;
84
+ ELinsert(lbnd, bisector) ;
85
+ p = intersect(lbnd, bisector) ;
86
+ if (p != (Site *)NULL)
87
+ {
88
+ PQdelete(lbnd) ;
89
+ PQinsert(lbnd, p, dist(p,newsite)) ;
90
+ }
91
+ lbnd = bisector ;
92
+ bisector = HEcreate(e, re) ;
93
+ ELinsert(lbnd, bisector) ;
94
+ p = intersect(bisector, rbnd) ;
95
+ if (p != (Site *)NULL)
96
+ {
97
+ PQinsert(bisector, p, dist(p,newsite)) ;
98
+ }
99
+ newsite = (*nextsite)() ;
100
+ }
101
+ else if (!PQempty()) /* intersection is smallest */
102
+ {
103
+ lbnd = PQextractmin() ;
104
+ llbnd = ELleft(lbnd) ;
105
+ rbnd = ELright(lbnd) ;
106
+ rrbnd = ELright(rbnd) ;
107
+ bot = leftreg(lbnd) ;
108
+ top = rightreg(rbnd) ;
109
+ out_triple(bot, top, rightreg(lbnd)) ;
110
+ v = lbnd->vertex ;
111
+ makevertex(v) ;
112
+ endpoint(lbnd->ELedge, lbnd->ELpm, v);
113
+ endpoint(rbnd->ELedge, rbnd->ELpm, v) ;
114
+ ELdelete(lbnd) ;
115
+ PQdelete(rbnd) ;
116
+ ELdelete(rbnd) ;
117
+ pm = le ;
118
+ if (bot->coord.y > top->coord.y)
119
+ {
120
+ temp = bot ;
121
+ bot = top ;
122
+ top = temp ;
123
+ pm = re ;
124
+ }
125
+ e = bisect(bot, top) ;
126
+ bisector = HEcreate(e, pm) ;
127
+ ELinsert(llbnd, bisector) ;
128
+ endpoint(e, re-pm, v) ;
129
+ deref(v) ;
130
+ p = intersect(llbnd, bisector) ;
131
+ if (p != (Site *) NULL)
132
+ {
133
+ PQdelete(llbnd) ;
134
+ PQinsert(llbnd, p, dist(p,bot)) ;
135
+ }
136
+ p = intersect(bisector, rrbnd) ;
137
+ if (p != (Site *) NULL)
138
+ {
139
+ PQinsert(bisector, p, dist(p,bot)) ;
140
+ }
141
+ }
142
+ else
143
+ {
144
+ break ;
145
+ }
146
+ }
147
+
148
+ for( lbnd = ELright(getELleftend()) ;
149
+ lbnd != getELrightend() ;
150
+ lbnd = ELright(lbnd))
151
+ {
152
+ e = lbnd->ELedge ;
153
+ out_ep(e) ;
154
+ }
155
+ }
156
+
157
+
158
+
159
+
160
+ /*
161
+ * Static storage methods
162
+ */
163
+
164
+ /*** stores a triplet of point indices that comprise a Delaunay triangle ***/
165
+ static void
166
+ storeTriangulationTriplet(const int a, const int b, const int c)
167
+ {
168
+ VALUE trArray, triplet;
169
+
170
+ /* Create a new triplet from the three incoming points */
171
+ triplet = rb_ary_new2(3);
172
+
173
+ rb_ary_push(triplet, INT2FIX(a));
174
+ rb_ary_push(triplet, INT2FIX(b));
175
+ rb_ary_push(triplet, INT2FIX(c));
176
+
177
+ /* Get the existing raw triangulation */
178
+ trArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("delaunay_triangulation_raw"), 0);
179
+
180
+ /* Add the new triplet to it */
181
+ rb_ary_push(trArray, triplet);
182
+ }
183
+
184
+
185
+ /*** stores a line defined by ax + by = c ***/
186
+ static void
187
+ storeLine(const float a, const float b, const float c)
188
+ {
189
+ VALUE lArray, line;
190
+
191
+ /* Create a new line from the three values */
192
+ line = rb_ary_new2(4);
193
+ rb_ary_push(line, ID2SYM(rb_intern("l")));
194
+ rb_ary_push(line, rb_float_new(a));
195
+ rb_ary_push(line, rb_float_new(b));
196
+ rb_ary_push(line, rb_float_new(c));
197
+
198
+ /* Get the existing raw voronoi diagram */
199
+ lArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
200
+
201
+ /* Add the new line to it */
202
+ rb_ary_push(lArray, line);
203
+ }
204
+
205
+
206
+ /***
207
+ * Stores a Voronoi segment which is a subsegment of line number l;
208
+ * with endpoints numbered v1 and v2. If v1 or v2 is -1, the line
209
+ * extends to infinity.
210
+ ***/
211
+ static void
212
+ storeEndpoint(const int l, const int v1, const int v2)
213
+ {
214
+ VALUE eArray, endpoint;
215
+
216
+ /* Create a new endpoint from the three values */
217
+ endpoint = rb_ary_new2(4);
218
+ rb_ary_push(endpoint, ID2SYM(rb_intern("e")));
219
+ rb_ary_push(endpoint, INT2FIX(l));
220
+ rb_ary_push(endpoint, INT2FIX(v1));
221
+ rb_ary_push(endpoint, INT2FIX(v2));
222
+
223
+ /* Get the existing raw voronoi diagram */
224
+ eArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
225
+
226
+ /* Add the new endpoint to it */
227
+ rb_ary_push(eArray, endpoint);
228
+ }
229
+
230
+
231
+ /*** stores a vertex at (a,b) ***/
232
+ static void
233
+ storeVertex(const float a, const float b)
234
+ {
235
+ VALUE vArray, vertex;
236
+
237
+ /* Create a new vertex from the coordinates */
238
+ vertex = rb_ary_new2(3);
239
+ rb_ary_push(vertex, ID2SYM(rb_intern("v")));
240
+ rb_ary_push(vertex, rb_float_new(a));
241
+ rb_ary_push(vertex, rb_float_new(b));
242
+
243
+ /* Get the existing raw voronoi diagram */
244
+ vArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
245
+
246
+ /* Add the new vertex to it */
247
+ rb_ary_push(vArray, vertex);
248
+ }
249
+
250
+
251
+ /***
252
+ * stores an input site at (x,y)
253
+ * TODO: redundant?
254
+ ***/
255
+ static void
256
+ storeSite(const float x, const float y)
257
+ {
258
+ VALUE sArray, site;
259
+
260
+ /* Create a new site from the coordinates */
261
+ site = rb_ary_new2(3);
262
+ rb_ary_push(site, ID2SYM(rb_intern("s")));
263
+ rb_ary_push(site, rb_float_new(x));
264
+ rb_ary_push(site, rb_float_new(y));
265
+
266
+ /* Get the existing raw voronoi diagram */
267
+ sArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
268
+
269
+ /* Add the new site to it */
270
+ rb_ary_push(sArray, site);
271
+ }