abscondment-rubyvor 0.1.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.
@@ -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
+ }