rubyvor 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }