rubyvor 0.1.3

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,251 @@
1
+
2
+ /*** OUTPUT.C ***/
3
+
4
+ #include <vdefs.h>
5
+ #include <stdio.h>
6
+ #include <unistd.h>
7
+
8
+ static float pxmin, pxmax, pymin, pymax, cradius;
9
+
10
+ void openpl(void) {}
11
+ void line(float ax, float ay, float bx, float by) {}
12
+ void circle(float ax, float ay, float radius) {}
13
+ void range(float pxmin, float pxmax, float pymin, float pymax) {}
14
+
15
+ void
16
+ out_bisector(Edge * e)
17
+ {
18
+ /* Save line to our ruby object */
19
+ (*rubyvorState.storeL)(e->a, e->b, e->c);
20
+
21
+
22
+ /* printf("l %f %f %f\n", e->a, e->b, e->c); */
23
+
24
+ if (rubyvorState.plot)
25
+ line(e->reg[0]->coord.x, e->reg[0]->coord.y, e->reg[1]->coord.x, e->reg[1]->coord.y);
26
+
27
+ if (rubyvorState.debug)
28
+ printf("line(%d) %gx+%gy=%g, bisecting %d %d\n", e->edgenbr, e->a, e->b, e->c, e->reg[le]->sitenbr, e->reg[re]->sitenbr);
29
+ }
30
+
31
+ void
32
+ out_ep(Edge * e)
33
+ {
34
+ /* Save endpoint to our ruby object */
35
+ (*rubyvorState.storeE)(e->edgenbr,
36
+ e->ep[le] != (Site *)NULL ? e->ep[le]->sitenbr : -1,
37
+ e->ep[re] != (Site *)NULL ? e->ep[re]->sitenbr : -1);
38
+
39
+ /*
40
+ printf("e %d", e->edgenbr);
41
+ printf(" %d ", e->ep[le] != (Site *)NULL ? e->ep[le]->sitenbr : -1) ;
42
+ printf("%d\n", e->ep[re] != (Site *)NULL ? e->ep[re]->sitenbr : -1) ;
43
+ */
44
+
45
+ if (rubyvorState.plot)
46
+ clip_line(e) ;
47
+ }
48
+
49
+ void
50
+ out_vertex(Site * v)
51
+ {
52
+ /* Save vertex to our ruby object */
53
+ (*rubyvorState.storeV)(v->coord.x, v->coord.y);
54
+
55
+ /* printf ("v %f %f\n", v->coord.x, v->coord.y) ; */
56
+
57
+ if (rubyvorState.debug)
58
+ printf("vertex(%d) at %f %f\n", v->sitenbr, v->coord.x, v->coord.y);
59
+ }
60
+
61
+ void
62
+ out_site(Site * s)
63
+ {
64
+ /* Save site to our ruby object */
65
+ (*rubyvorState.storeS)(s->coord.x, s->coord.y);
66
+
67
+ /* printf("s %f %f\n", s->coord.x, s->coord.y) ; */
68
+
69
+ if (rubyvorState.plot)
70
+ circle (s->coord.x, s->coord.y, cradius);
71
+
72
+ if (rubyvorState.debug)
73
+ printf("site (%d) at %f %f\n", s->sitenbr, s->coord.x, s->coord.y);
74
+ }
75
+
76
+ void
77
+ out_triple(Site * s1, Site * s2, Site * s3)
78
+ {
79
+ /* Save triplet to our ruby object */
80
+ (*rubyvorState.storeT)(s1->sitenbr, s2->sitenbr, s3->sitenbr);
81
+
82
+ if (rubyvorState.debug)
83
+ {
84
+ printf("%d %d %d\n", s1->sitenbr, s2->sitenbr, s3->sitenbr);
85
+ printf("circle through left=%d right=%d bottom=%d\n",
86
+ s1->sitenbr, s2->sitenbr, s3->sitenbr) ;
87
+ }
88
+ }
89
+
90
+ void
91
+ plotinit(void)
92
+ {
93
+ float dx, dy, d ;
94
+
95
+ dy = rubyvorState.ymax - rubyvorState.ymin ;
96
+ dx = rubyvorState.xmax - rubyvorState.xmin ;
97
+ d = ( dx > dy ? dx : dy) * 1.1 ;
98
+ pxmin = rubyvorState.xmin - (d-dx) / 2.0 ;
99
+ pxmax = rubyvorState.xmax + (d-dx) / 2.0 ;
100
+ pymin = rubyvorState.ymin - (d-dy) / 2.0 ;
101
+ pymax = rubyvorState.ymax + (d-dy) / 2.0 ;
102
+ cradius = (pxmax - pxmin) / 350.0 ;
103
+ openpl() ;
104
+ range(pxmin, pymin, pxmax, pymax) ;
105
+ }
106
+
107
+ void
108
+ clip_line(Edge * e)
109
+ {
110
+ Site * s1, * s2 ;
111
+ float x1, x2, y1, y2 ;
112
+
113
+ if (e->a == 1.0 && e->b >= 0.0)
114
+ {
115
+ s1 = e->ep[1] ;
116
+ s2 = e->ep[0] ;
117
+ }
118
+ else
119
+ {
120
+ s1 = e->ep[0] ;
121
+ s2 = e->ep[1] ;
122
+ }
123
+ if (e->a == 1.0)
124
+ {
125
+ y1 = pymin ;
126
+ if (s1 != (Site *)NULL && s1->coord.y > pymin)
127
+ {
128
+ y1 = s1->coord.y ;
129
+ }
130
+ if (y1 > pymax)
131
+ {
132
+ return ;
133
+ }
134
+ x1 = e->c - e->b * y1 ;
135
+ y2 = pymax ;
136
+ if (s2 != (Site *)NULL && s2->coord.y < pymax)
137
+ {
138
+ y2 = s2->coord.y ;
139
+ }
140
+ if (y2 < pymin)
141
+ {
142
+ return ;
143
+ }
144
+ x2 = e->c - e->b * y2 ;
145
+ if (((x1 > pxmax) && (x2 > pxmax)) || ((x1 < pxmin) && (x2 < pxmin)))
146
+ {
147
+ return ;
148
+ }
149
+ if (x1 > pxmax)
150
+ {
151
+ x1 = pxmax ;
152
+ y1 = (e->c - x1) / e->b ;
153
+ }
154
+ if (x1 < pxmin)
155
+ {
156
+ x1 = pxmin ;
157
+ y1 = (e->c - x1) / e->b ;
158
+ }
159
+ if (x2 > pxmax)
160
+ {
161
+ x2 = pxmax ;
162
+ y2 = (e->c - x2) / e->b ;
163
+ }
164
+ if (x2 < pxmin)
165
+ {
166
+ x2 = pxmin ;
167
+ y2 = (e->c - x2) / e->b ;
168
+ }
169
+ }
170
+ else
171
+ {
172
+ x1 = pxmin ;
173
+ if (s1 != (Site *)NULL && s1->coord.x > pxmin)
174
+ {
175
+ x1 = s1->coord.x ;
176
+ }
177
+ if (x1 > pxmax)
178
+ {
179
+ return ;
180
+ }
181
+ y1 = e->c - e->a * x1 ;
182
+ x2 = pxmax ;
183
+ if (s2 != (Site *)NULL && s2->coord.x < pxmax)
184
+ {
185
+ x2 = s2->coord.x ;
186
+ }
187
+ if (x2 < pxmin)
188
+ {
189
+ return ;
190
+ }
191
+ y2 = e->c - e->a * x2 ;
192
+ if (((y1 > pymax) && (y2 > pymax)) || ((y1 < pymin) && (y2 <pymin)))
193
+ {
194
+ return ;
195
+ }
196
+ if (y1> pymax)
197
+ {
198
+ y1 = pymax ;
199
+ x1 = (e->c - y1) / e->a ;
200
+ }
201
+ if (y1 < pymin)
202
+ {
203
+ y1 = pymin ;
204
+ x1 = (e->c - y1) / e->a ;
205
+ }
206
+ if (y2 > pymax)
207
+ {
208
+ y2 = pymax ;
209
+ x2 = (e->c - y2) / e->a ;
210
+ }
211
+ if (y2 < pymin)
212
+ {
213
+ y2 = pymin ;
214
+ x2 = (e->c - y2) / e->a ;
215
+ }
216
+ }
217
+ line(x1,y1,x2,y2);
218
+ }
219
+
220
+ /* Linux-specific. */
221
+ void
222
+ debug_memory(void)
223
+ {
224
+ char buf[30];
225
+ FILE* pf;
226
+ int tmp;
227
+ float totalSize;
228
+ unsigned size;/* total program size */
229
+
230
+ /*
231
+ unsigned resident;// resident set size
232
+ unsigned share;// shared pages
233
+ unsigned text;// text (code)
234
+ unsigned lib;// library
235
+ unsigned data;// data/stack
236
+ unsigned dt;// dirty pages (unused in Linux 2.6)
237
+ */
238
+
239
+ if (!rubyvorState.debug)
240
+ return;
241
+
242
+ snprintf(buf, 30, "/proc/%u/statm", (unsigned)getpid());
243
+ pf = fopen(buf, "r");
244
+ if (NULL != pf)
245
+ {
246
+ tmp = fscanf(pf, "%u", &size); /*, %u, %u ... etc &resident, &share, &text, &lib, &data); */
247
+ totalSize = (float)size / 1024.0;
248
+ fprintf(stderr, "%f ", totalSize);
249
+ }
250
+ fclose(pf);
251
+ }
@@ -0,0 +1,369 @@
1
+ #include <ruby.h>
2
+ #include <vdefs.h>
3
+ #include <ruby_vor_c.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
+ * See ruby_vor.c for RDOC
12
+ */
13
+
14
+
15
+ /*
16
+ * Class methods for RubyVor::VDDT::Computation
17
+ */
18
+
19
+ VALUE
20
+ RubyVor_from_points(VALUE self, VALUE pointsArray)
21
+ {
22
+ VALUE * inPtr, newComp;
23
+ ID x, y;
24
+
25
+ long i, inSize;
26
+
27
+ /* Require T_ARRAY */
28
+ Check_Type(pointsArray, T_ARRAY);
29
+
30
+ /* Intern our point access methods */
31
+ x = rb_intern("x");
32
+ y = rb_intern("y");
33
+
34
+
35
+ /* Require nonzero size and x & y methods on each array object */
36
+ if (RARRAY_LEN(pointsArray) < 1)
37
+ rb_raise(rb_eRuntimeError, "input points array must have a nonzero length");
38
+ for (i = 0; i < RARRAY_LEN(pointsArray); i++) {
39
+ if(!rb_respond_to(RARRAY_PTR(pointsArray)[i], x) || !rb_respond_to(RARRAY_PTR(pointsArray)[i], y))
40
+ rb_raise(rb_eRuntimeError, "members of points array must respond to 'x' and 'y'");
41
+ }
42
+
43
+ /* Load up point count & points pointer. */
44
+ pointsArray = rb_funcall(pointsArray, rb_intern("uniq"), 0);
45
+ inSize = RARRAY_LEN(pointsArray);
46
+ inPtr = RARRAY_PTR(pointsArray);
47
+
48
+
49
+ /* Initialize rubyvorState */
50
+ initialize_state(0 /* debug? */);
51
+ debug_memory();
52
+
53
+ /* Create our return object. */
54
+ newComp = rb_funcall(self, rb_intern("new"), 0);
55
+ rb_iv_set(newComp, "@points", pointsArray);
56
+
57
+ /* Store it in rubyvorState so we can populate its values. */
58
+ rubyvorState.comp = (void *) &newComp;
59
+
60
+ /*
61
+ * Read in the sites, sort, and compute xmin, xmax, ymin, ymax
62
+ *
63
+ * TODO: refactor this block into a separate method for clarity?
64
+ */
65
+ {
66
+ /* Allocate memory for N sites... */
67
+ rubyvorState.sites = (Site *) myalloc(inSize * sizeof(Site));
68
+
69
+
70
+ /* Iterate over the arrays, doubling the incoming values. */
71
+ for (i=0; i<inSize; i++)
72
+ {
73
+ rubyvorState.sites[rubyvorState.nsites].coord.x = NUM2DBL(rb_funcall(inPtr[i], x, 0));
74
+ rubyvorState.sites[rubyvorState.nsites].coord.y = NUM2DBL(rb_funcall(inPtr[i], y, 0));
75
+
76
+ rubyvorState.sites[rubyvorState.nsites].sitenbr = rubyvorState.nsites;
77
+ rubyvorState.sites[rubyvorState.nsites++].refcnt = 0;
78
+
79
+ /* Allocate for N more if we just hit a multiple of N... */
80
+ if (rubyvorState.nsites % inSize == 0)
81
+ {
82
+ rubyvorState.sites = (Site *)myrealloc(rubyvorState.sites,(rubyvorState.nsites+inSize)*sizeof(Site),rubyvorState.nsites*sizeof(Site));
83
+ }
84
+ }
85
+
86
+ /* Sort the Sites */
87
+ qsort((void *)rubyvorState.sites, rubyvorState.nsites, sizeof(Site), scomp) ;
88
+
89
+ /* Pull the minimum values. */
90
+ rubyvorState.xmin = rubyvorState.sites[0].coord.x;
91
+ rubyvorState.xmax = rubyvorState.sites[0].coord.x;
92
+ for (i=1; i < rubyvorState.nsites; ++i)
93
+ {
94
+ if (rubyvorState.sites[i].coord.x < rubyvorState.xmin)
95
+ {
96
+ rubyvorState.xmin = rubyvorState.sites[i].coord.x;
97
+ }
98
+ if (rubyvorState.sites[i].coord.x > rubyvorState.xmax)
99
+ {
100
+ rubyvorState.xmax = rubyvorState.sites[i].coord.x;
101
+ }
102
+ }
103
+ rubyvorState.ymin = rubyvorState.sites[0].coord.y;
104
+ rubyvorState.ymax = rubyvorState.sites[rubyvorState.nsites-1].coord.y;
105
+
106
+ }
107
+
108
+
109
+ /* Perform the computation */
110
+ voronoi(nextone);
111
+ debug_memory();
112
+
113
+ /* Get rid of our comp reference */
114
+ rubyvorState.comp = (void *)NULL;
115
+
116
+ /* Free our allocated objects */
117
+ free_all();
118
+ debug_memory();
119
+
120
+ return newComp;
121
+ }
122
+
123
+
124
+ /*
125
+ * Instance methods
126
+ */
127
+
128
+ VALUE
129
+ RubyVor_nn_graph(VALUE self)
130
+ {
131
+ VALUE dtRaw, graph, points, * dtPtr, * tripletPtr, * graphPtr;
132
+ long i, j, noNeighborResponse;
133
+
134
+ graph = rb_iv_get(self, "@nn_graph");
135
+
136
+ if (RTEST(graph))
137
+ return graph;
138
+
139
+ /* Figure out our "no neighbor" response value */
140
+ if (SYM2ID(rb_iv_get(self, "@no_neighbor_response")) == rb_intern("raise")) {
141
+ noNeighborResponse = 1;
142
+ } else if (SYM2ID(rb_iv_get(self, "@no_neighbor_response")) == rb_intern("use_all")) {
143
+ noNeighborResponse = 2;
144
+ } else {
145
+ noNeighborResponse = 0;
146
+ }
147
+
148
+ /* Create an array of same size as points for the graph */
149
+ points = rb_iv_get(self, "@points");
150
+
151
+ graph = rb_ary_new2(RARRAY_LEN(points));
152
+ for (i = 0; i < RARRAY_LEN(points); i++)
153
+ rb_ary_push(graph, rb_ary_new());
154
+
155
+ /* Get our pointer into this array. */
156
+ graphPtr = RARRAY_PTR(graph);
157
+
158
+ /* Iterate over the triangulation */
159
+ dtRaw = rb_iv_get(self, "@delaunay_triangulation_raw");
160
+ dtPtr = RARRAY_PTR(dtRaw);
161
+ for (i = 0; i < RARRAY_LEN(dtRaw); i++) {
162
+ tripletPtr = RARRAY_PTR(dtPtr[i]);
163
+
164
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[0])], tripletPtr[1]);
165
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[1])], tripletPtr[0]);
166
+
167
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[0])], tripletPtr[2]);
168
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[2])], tripletPtr[0]);
169
+
170
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[1])], tripletPtr[2]);
171
+ rb_ary_push(graphPtr[FIX2INT(tripletPtr[2])], tripletPtr[1]);
172
+
173
+ }
174
+ for (i = 0; i < RARRAY_LEN(graph); i++) {
175
+ if (RARRAY_LEN(graphPtr[i]) < 1) {
176
+ /* Evaluate noNeighborResponse and respond accordingly */
177
+ if (noNeighborResponse == 1) {
178
+ rb_raise(rb_eIndexError, "index of 0 (no neighbors) at %li", i);
179
+ } else if (noNeighborResponse == 2) {
180
+ /* No valid triangles touched this node -- include *all* possible neighbors
181
+ *
182
+ * Note that this can make for exceptionally slow (ie O(n^2) time) clustering,
183
+ * but should only happen in rare cases.
184
+ */
185
+ for(j = 0; j < RARRAY_LEN(points); j++) {
186
+ if (j != i) {
187
+ rb_ary_push(graphPtr[i], INT2FIX(j));
188
+ if (RARRAY_LEN(graphPtr[j]) > 0 && !rb_ary_includes(graphPtr[j], INT2FIX(i)))
189
+ rb_ary_push(graphPtr[j], INT2FIX(i));
190
+ }
191
+ }
192
+ }
193
+ } else {
194
+ rb_funcall(graphPtr[i], rb_intern("uniq!"), 0);
195
+ }
196
+ }
197
+
198
+ rb_iv_set(self, "@nn_graph", graph);
199
+
200
+ return graph;
201
+ }
202
+
203
+
204
+ VALUE
205
+ RubyVor_minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
206
+ {
207
+ VALUE mst, dist_proc, nodes, nnGraph, points, queue, tmp, adjacent, adjacentData, adjacentDistance, current, currentData, floatMax;
208
+ ID i_call, i_push, i_pop, i_has_key;
209
+ long i;
210
+
211
+ /* 0 mandatory, 1 optional */
212
+ rb_scan_args(argc, argv, "01", &dist_proc);
213
+
214
+ mst = rb_iv_get(self, "@mst");
215
+
216
+ if (RTEST(mst))
217
+ return mst;
218
+
219
+
220
+ if (NIL_P(dist_proc)) {
221
+ /* Use our default Proc */
222
+ dist_proc = rb_eval_string("lambda{|a,b| a.distance_from(b)}");
223
+ } else if (rb_class_of(dist_proc) != rb_cProc) {
224
+ /* Blow up if we have a non-nil, non-Proc */
225
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(dist_proc), rb_class2name(rb_cProc));
226
+ }
227
+
228
+ // Set up interned values
229
+ i_call = rb_intern("call");
230
+ i_push = rb_intern("push");
231
+ i_pop = rb_intern("pop");
232
+ i_has_key = rb_intern("has_key?");
233
+
234
+ points = rb_iv_get(self, "@points");
235
+ queue = rb_eval_string("RubyVor::PriorityQueue.new");
236
+ nnGraph = RubyVor_nn_graph(self);
237
+ floatMax= rb_iv_get(rb_cFloat, "MAX");
238
+
239
+ for (i = 0; i < RARRAY_LEN(points); i++) {
240
+ tmp = rb_ary_new2(5);
241
+ /* 0: node index */
242
+ rb_ary_push(tmp, LONG2FIX(i));
243
+ /* 1: parent */
244
+ rb_ary_push(tmp, Qnil);
245
+ /* 2: adjacency_list */
246
+ rb_ary_push(tmp, rb_obj_clone(RARRAY_PTR(nnGraph)[i]));
247
+ /* 3: min_adjacency_list */
248
+ rb_ary_push(tmp, rb_ary_new());
249
+ /* 4: in_q */
250
+ rb_ary_push(tmp, Qtrue);
251
+
252
+ rb_funcall(queue, i_push, 2, tmp, (i == 0) ? rb_float_new(0.0) : floatMax);
253
+ }
254
+ nodes = rb_obj_clone(rb_iv_get(queue, "@data"));
255
+
256
+ while(RTEST(current = rb_funcall(queue, i_pop, 0))) {
257
+ currentData = rb_iv_get(current, "@data");
258
+
259
+ /* mark in_q */
260
+ rb_ary_store(currentData, 4, Qfalse);
261
+
262
+ /* check for presence of parent */
263
+ if (RTEST(RARRAY_PTR(currentData)[1])) {
264
+ /* push this node into adjacency_list of parent */
265
+ rb_ary_push(RARRAY_PTR(rb_iv_get(RARRAY_PTR(currentData)[1], "@data"))[3], current);
266
+ /* push parent into adjacency_list of this node */
267
+ rb_ary_push(RARRAY_PTR(currentData)[3], RARRAY_PTR(currentData)[1]);
268
+ }
269
+
270
+ for (i = 0; i < RARRAY_LEN(RARRAY_PTR(currentData)[2]); i++) {
271
+ /* grab indexed node */
272
+ adjacent = RARRAY_PTR(nodes)[FIX2LONG(RARRAY_PTR(RARRAY_PTR(currentData)[2])[i])];
273
+ adjacentData = rb_iv_get(adjacent, "@data");
274
+
275
+ /* check in_q -- only look at new nodes */
276
+ if (Qtrue == RARRAY_PTR(adjacentData)[4]) {
277
+
278
+ /* compare points by node -- adjacent against current */
279
+ adjacentDistance = rb_funcall(dist_proc, i_call, 2,
280
+ RARRAY_PTR(points)[FIX2LONG(RARRAY_PTR(currentData)[0])],
281
+ RARRAY_PTR(points)[FIX2LONG(RARRAY_PTR(adjacentData)[0])]);
282
+
283
+ /* If the new distance is better than our current priority, exchange them. */
284
+ if (RFLOAT_VALUE(adjacentDistance) < RFLOAT_VALUE(rb_iv_get(adjacent, "@priority"))) {
285
+ /* set new :parent */
286
+ rb_ary_store(adjacentData, 1, current);
287
+ /* update priority */
288
+ rb_iv_set(adjacent, "@priority", adjacentDistance);
289
+ /* percolate up into correctn position */
290
+ RubyVor_percolate_up(queue, rb_iv_get(adjacent, "@index"));
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ mst = rb_hash_new();
297
+ for (i = 0; i < RARRAY_LEN(nodes); i++) {
298
+ current = RARRAY_PTR(nodes)[i];
299
+ currentData = rb_iv_get(current, "@data");
300
+ if (!NIL_P(RARRAY_PTR(currentData)[1])) {
301
+ adjacentData = rb_iv_get(RARRAY_PTR(currentData)[1], "@data");
302
+ tmp = rb_ary_new2(2);
303
+ if (FIX2LONG(RARRAY_PTR(currentData)[0]) < FIX2LONG(RARRAY_PTR(adjacentData)[0])) {
304
+ rb_ary_push(tmp, RARRAY_PTR(currentData)[0]);
305
+ rb_ary_push(tmp, RARRAY_PTR(adjacentData)[0]);
306
+ } else {
307
+ rb_ary_push(tmp, RARRAY_PTR(adjacentData)[0]);
308
+ rb_ary_push(tmp, RARRAY_PTR(currentData)[0]);
309
+ }
310
+
311
+ /* if (!st_lookup(RHASH(mst)->tbl, tmp, 0)) { */
312
+ rb_hash_aset(mst, tmp, rb_iv_get(current, "@priority"));
313
+ /* } */
314
+ }
315
+ }
316
+
317
+ rb_iv_set(self, "@mst", mst);
318
+
319
+ return mst;
320
+ }
321
+
322
+
323
+ /*
324
+ * Static C helper methods
325
+ */
326
+
327
+
328
+ /*** sort sites on y, then x, coord ***/
329
+ static int
330
+ scomp(const void * vs1, const void * vs2)
331
+ {
332
+ Point * s1 = (Point *)vs1 ;
333
+ Point * s2 = (Point *)vs2 ;
334
+
335
+ if (s1->y < s2->y)
336
+ {
337
+ return (-1) ;
338
+ }
339
+ if (s1->y > s2->y)
340
+ {
341
+ return (1) ;
342
+ }
343
+ if (s1->x < s2->x)
344
+ {
345
+ return (-1) ;
346
+ }
347
+ if (s1->x > s2->x)
348
+ {
349
+ return (1) ;
350
+ }
351
+ return (0) ;
352
+ }
353
+
354
+ /*** return a single in-storage site ***/
355
+ static Site *
356
+ nextone(void)
357
+ {
358
+ Site * s ;
359
+
360
+ if (rubyvorState.siteidx < rubyvorState.nsites)
361
+ {
362
+ s = &rubyvorState.sites[rubyvorState.siteidx++];
363
+ return (s) ;
364
+ }
365
+ else
366
+ {
367
+ return ((Site *)NULL) ;
368
+ }
369
+ }