rubyvor 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +60 -0
- data/Manifest.txt +30 -0
- data/README.rdoc +76 -0
- data/Rakefile +41 -0
- data/ext/Doc +30 -0
- data/ext/edgelist.c +204 -0
- data/ext/extconf.rb +3 -0
- data/ext/geometry.c +219 -0
- data/ext/heap.c +118 -0
- data/ext/memory.c +118 -0
- data/ext/output.c +251 -0
- data/ext/rb_cComputation.c +369 -0
- data/ext/rb_cPoint.c +35 -0
- data/ext/rb_cPriorityQueue.c +120 -0
- data/ext/ruby_vor_c.c +115 -0
- data/ext/ruby_vor_c.h +40 -0
- data/ext/vdefs.h +150 -0
- data/ext/voronoi.c +271 -0
- data/lib/ruby_vor.rb +16 -0
- data/lib/ruby_vor/computation.rb +136 -0
- data/lib/ruby_vor/geo_ruby_extensions.rb +15 -0
- data/lib/ruby_vor/point.rb +32 -0
- data/lib/ruby_vor/priority_queue.rb +87 -0
- data/lib/ruby_vor/version.rb +3 -0
- data/lib/ruby_vor/visualizer.rb +218 -0
- data/rubyvor.gemspec +35 -0
- data/test/test_computation.rb +354 -0
- data/test/test_point.rb +100 -0
- data/test/test_priority_queue.rb +129 -0
- data/test/test_voronoi_interface.rb +161 -0
- metadata +99 -0
data/ext/geometry.c
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
|
2
|
+
/*** GEOMETRY.C ***/
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include "vdefs.h"
|
6
|
+
|
7
|
+
static Freelist efl;
|
8
|
+
|
9
|
+
void
|
10
|
+
geominit(void)
|
11
|
+
{
|
12
|
+
freeinit(&efl, sizeof(Edge)) ;
|
13
|
+
rubyvorState.nvertices = rubyvorState.nedges = 0 ;
|
14
|
+
rubyvorState.sqrt_nsites = sqrt(rubyvorState.nsites+4) ;
|
15
|
+
rubyvorState.deltay = rubyvorState.ymax - rubyvorState.ymin ;
|
16
|
+
rubyvorState.deltax = rubyvorState.xmax - rubyvorState.xmin ;
|
17
|
+
}
|
18
|
+
|
19
|
+
Edge *
|
20
|
+
bisect(Site * s1, Site * s2)
|
21
|
+
{
|
22
|
+
float dx, dy, adx, ady ;
|
23
|
+
Edge * newedge ;
|
24
|
+
|
25
|
+
newedge = (Edge *)getfree(&efl) ;
|
26
|
+
newedge->reg[0] = s1 ;
|
27
|
+
newedge->reg[1] = s2 ;
|
28
|
+
ref(s1) ;
|
29
|
+
ref(s2) ;
|
30
|
+
newedge->ep[0] = newedge->ep[1] = (Site *)NULL ;
|
31
|
+
dx = s2->coord.x - s1->coord.x ;
|
32
|
+
dy = s2->coord.y - s1->coord.y ;
|
33
|
+
adx = dx>0 ? dx : -dx ;
|
34
|
+
ady = dy>0 ? dy : -dy ;
|
35
|
+
newedge->c = s1->coord.x * dx + s1->coord.y * dy + (dx*dx +
|
36
|
+
dy*dy) * 0.5 ;
|
37
|
+
if (adx > ady)
|
38
|
+
{
|
39
|
+
newedge->a = 1.0 ;
|
40
|
+
newedge->b = dy/dx ;
|
41
|
+
newedge->c /= dx ;
|
42
|
+
}
|
43
|
+
else
|
44
|
+
{
|
45
|
+
newedge->b = 1.0 ;
|
46
|
+
newedge->a = dx/dy ;
|
47
|
+
newedge->c /= dy ;
|
48
|
+
}
|
49
|
+
newedge->edgenbr = rubyvorState.nedges ;
|
50
|
+
out_bisector(newedge) ;
|
51
|
+
rubyvorState.nedges++ ;
|
52
|
+
return (newedge) ;
|
53
|
+
}
|
54
|
+
|
55
|
+
Site *
|
56
|
+
intersect(Halfedge * el1, Halfedge * el2)
|
57
|
+
{
|
58
|
+
Edge * e1, * e2, * e ;
|
59
|
+
Halfedge * el ;
|
60
|
+
float d, xint, yint ;
|
61
|
+
int right_of_site ;
|
62
|
+
Site * v ;
|
63
|
+
|
64
|
+
e1 = el1->ELedge ;
|
65
|
+
e2 = el2->ELedge ;
|
66
|
+
if ((e1 == (Edge*)NULL) || (e2 == (Edge*)NULL))
|
67
|
+
{
|
68
|
+
return ((Site *)NULL) ;
|
69
|
+
}
|
70
|
+
if (e1->reg[1] == e2->reg[1])
|
71
|
+
{
|
72
|
+
return ((Site *)NULL) ;
|
73
|
+
}
|
74
|
+
d = (e1->a * e2->b) - (e1->b * e2->a) ;
|
75
|
+
if ((-1.0e-10 < d) && (d < 1.0e-10))
|
76
|
+
{
|
77
|
+
return ((Site *)NULL) ;
|
78
|
+
}
|
79
|
+
xint = (e1->c * e2->b - e2->c * e1->b) / d ;
|
80
|
+
yint = (e2->c * e1->a - e1->c * e2->a) / d ;
|
81
|
+
if ((e1->reg[1]->coord.y < e2->reg[1]->coord.y) ||
|
82
|
+
(e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
|
83
|
+
e1->reg[1]->coord.x < e2->reg[1]->coord.x))
|
84
|
+
{
|
85
|
+
el = el1 ;
|
86
|
+
e = e1 ;
|
87
|
+
}
|
88
|
+
else
|
89
|
+
{
|
90
|
+
el = el2 ;
|
91
|
+
e = e2 ;
|
92
|
+
}
|
93
|
+
right_of_site = (xint >= e->reg[1]->coord.x) ;
|
94
|
+
if ((right_of_site && (el->ELpm == le)) ||
|
95
|
+
(!right_of_site && (el->ELpm == re)))
|
96
|
+
{
|
97
|
+
return ((Site *)NULL) ;
|
98
|
+
}
|
99
|
+
v = (Site *)getfree(&(rubyvorState.sfl)) ;
|
100
|
+
v->refcnt = 0 ;
|
101
|
+
v->coord.x = xint ;
|
102
|
+
v->coord.y = yint ;
|
103
|
+
return (v) ;
|
104
|
+
}
|
105
|
+
|
106
|
+
/*** returns 1 if p is to right of halfedge e ***/
|
107
|
+
|
108
|
+
int
|
109
|
+
right_of(Halfedge * el, Point * p)
|
110
|
+
{
|
111
|
+
Edge * e ;
|
112
|
+
Site * topsite ;
|
113
|
+
int right_of_site, above, fast ;
|
114
|
+
float dxp, dyp, dxs, t1, t2, t3, yl ;
|
115
|
+
|
116
|
+
e = el->ELedge ;
|
117
|
+
topsite = e->reg[1] ;
|
118
|
+
right_of_site = (p->x > topsite->coord.x) ;
|
119
|
+
if (right_of_site && (el->ELpm == le))
|
120
|
+
{
|
121
|
+
return (1) ;
|
122
|
+
}
|
123
|
+
if(!right_of_site && (el->ELpm == re))
|
124
|
+
{
|
125
|
+
return (0) ;
|
126
|
+
}
|
127
|
+
if (e->a == 1.0)
|
128
|
+
{
|
129
|
+
dyp = p->y - topsite->coord.y ;
|
130
|
+
dxp = p->x - topsite->coord.x ;
|
131
|
+
fast = 0 ;
|
132
|
+
if ((!right_of_site & (e->b < 0.0)) ||
|
133
|
+
(right_of_site & (e->b >= 0.0)))
|
134
|
+
{
|
135
|
+
fast = above = (dyp >= e->b*dxp) ;
|
136
|
+
}
|
137
|
+
else
|
138
|
+
{
|
139
|
+
above = ((p->x + p->y * e->b) > (e->c)) ;
|
140
|
+
if (e->b < 0.0)
|
141
|
+
{
|
142
|
+
above = !above ;
|
143
|
+
}
|
144
|
+
if (!above)
|
145
|
+
{
|
146
|
+
fast = 1 ;
|
147
|
+
}
|
148
|
+
}
|
149
|
+
if (!fast)
|
150
|
+
{
|
151
|
+
dxs = topsite->coord.x - (e->reg[0])->coord.x ;
|
152
|
+
above = (e->b * (dxp*dxp - dyp*dyp))
|
153
|
+
<
|
154
|
+
(dxs * dyp * (1.0 + 2.0 * dxp /
|
155
|
+
dxs + e->b * e->b)) ;
|
156
|
+
if (e->b < 0.0)
|
157
|
+
{
|
158
|
+
above = !above ;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
else /*** e->b == 1.0 ***/
|
163
|
+
{
|
164
|
+
yl = e->c - e->a * p->x ;
|
165
|
+
t1 = p->y - yl ;
|
166
|
+
t2 = p->x - topsite->coord.x ;
|
167
|
+
t3 = yl - topsite->coord.y ;
|
168
|
+
above = ((t1*t1) > ((t2 * t2) + (t3 * t3))) ;
|
169
|
+
}
|
170
|
+
return (el->ELpm == le ? above : !above) ;
|
171
|
+
}
|
172
|
+
|
173
|
+
void
|
174
|
+
endpoint(Edge * e, int lr, Site * s)
|
175
|
+
{
|
176
|
+
e->ep[lr] = s ;
|
177
|
+
ref(s) ;
|
178
|
+
if (e->ep[re-lr] == (Site *)NULL)
|
179
|
+
{
|
180
|
+
return ;
|
181
|
+
}
|
182
|
+
out_ep(e) ;
|
183
|
+
deref(e->reg[le]) ;
|
184
|
+
deref(e->reg[re]) ;
|
185
|
+
makefree((Freenode *)e, (Freelist *) &efl) ;
|
186
|
+
}
|
187
|
+
|
188
|
+
float
|
189
|
+
dist(Site * s, Site * t)
|
190
|
+
{
|
191
|
+
float dx,dy ;
|
192
|
+
|
193
|
+
dx = s->coord.x - t->coord.x ;
|
194
|
+
dy = s->coord.y - t->coord.y ;
|
195
|
+
return (sqrt(dx*dx + dy*dy)) ;
|
196
|
+
}
|
197
|
+
|
198
|
+
void
|
199
|
+
makevertex(Site * v)
|
200
|
+
{
|
201
|
+
v->sitenbr = rubyvorState.nvertices++ ;
|
202
|
+
out_vertex(v) ;
|
203
|
+
}
|
204
|
+
|
205
|
+
void
|
206
|
+
deref(Site * v)
|
207
|
+
{
|
208
|
+
if (--(v->refcnt) == 0 )
|
209
|
+
{
|
210
|
+
makefree((Freenode *)v, (Freelist *)&(rubyvorState.sfl)) ;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
void
|
215
|
+
ref(Site * v)
|
216
|
+
{
|
217
|
+
++(v->refcnt) ;
|
218
|
+
}
|
219
|
+
|
data/ext/heap.c
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
|
2
|
+
/*** HEAP.C ***/
|
3
|
+
|
4
|
+
|
5
|
+
#include "vdefs.h"
|
6
|
+
|
7
|
+
static int PQmin, PQcount, PQhashsize ;
|
8
|
+
static Halfedge * PQhash ;
|
9
|
+
|
10
|
+
void
|
11
|
+
PQinsert(Halfedge * he, Site * v, float offset)
|
12
|
+
{
|
13
|
+
Halfedge * last, * next ;
|
14
|
+
|
15
|
+
he->vertex = v ;
|
16
|
+
ref(v) ;
|
17
|
+
he->ystar = v->coord.y + offset ;
|
18
|
+
last = &PQhash[ PQbucket(he)] ;
|
19
|
+
while ((next = last->PQnext) != (Halfedge *)NULL &&
|
20
|
+
(he->ystar > next->ystar ||
|
21
|
+
(he->ystar == next->ystar &&
|
22
|
+
v->coord.x > next->vertex->coord.x)))
|
23
|
+
{
|
24
|
+
last = next ;
|
25
|
+
}
|
26
|
+
he->PQnext = last->PQnext ;
|
27
|
+
last->PQnext = he ;
|
28
|
+
PQcount++ ;
|
29
|
+
}
|
30
|
+
|
31
|
+
void
|
32
|
+
PQdelete(Halfedge * he)
|
33
|
+
{
|
34
|
+
Halfedge * last;
|
35
|
+
|
36
|
+
if(he -> vertex != (Site *) NULL)
|
37
|
+
{
|
38
|
+
last = &PQhash[PQbucket(he)] ;
|
39
|
+
while (last -> PQnext != he)
|
40
|
+
{
|
41
|
+
last = last->PQnext ;
|
42
|
+
}
|
43
|
+
last->PQnext = he->PQnext;
|
44
|
+
PQcount-- ;
|
45
|
+
deref(he->vertex) ;
|
46
|
+
he->vertex = (Site *)NULL ;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
int
|
51
|
+
PQbucket(Halfedge * he)
|
52
|
+
{
|
53
|
+
int bucket ;
|
54
|
+
|
55
|
+
|
56
|
+
if (he->ystar < rubyvorState.ymin) bucket = 0;
|
57
|
+
else if (he->ystar >= rubyvorState.ymax) bucket = PQhashsize-1;
|
58
|
+
else bucket = (he->ystar - rubyvorState.ymin)/rubyvorState.deltay * PQhashsize;
|
59
|
+
if (bucket < 0)
|
60
|
+
{
|
61
|
+
bucket = 0 ;
|
62
|
+
}
|
63
|
+
if (bucket >= PQhashsize)
|
64
|
+
{
|
65
|
+
bucket = PQhashsize-1 ;
|
66
|
+
}
|
67
|
+
if (bucket < PQmin)
|
68
|
+
{
|
69
|
+
PQmin = bucket ;
|
70
|
+
}
|
71
|
+
return (bucket);
|
72
|
+
}
|
73
|
+
|
74
|
+
int
|
75
|
+
PQempty(void)
|
76
|
+
{
|
77
|
+
return (PQcount == 0) ;
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
Point
|
82
|
+
PQ_min(void)
|
83
|
+
{
|
84
|
+
Point answer ;
|
85
|
+
|
86
|
+
while (PQhash[PQmin].PQnext == (Halfedge *)NULL)
|
87
|
+
{
|
88
|
+
++PQmin ;
|
89
|
+
}
|
90
|
+
answer.x = PQhash[PQmin].PQnext->vertex->coord.x ;
|
91
|
+
answer.y = PQhash[PQmin].PQnext->ystar ;
|
92
|
+
return (answer) ;
|
93
|
+
}
|
94
|
+
|
95
|
+
Halfedge *
|
96
|
+
PQextractmin(void)
|
97
|
+
{
|
98
|
+
Halfedge * curr ;
|
99
|
+
|
100
|
+
curr = PQhash[PQmin].PQnext ;
|
101
|
+
PQhash[PQmin].PQnext = curr->PQnext ;
|
102
|
+
PQcount-- ;
|
103
|
+
return (curr) ;
|
104
|
+
}
|
105
|
+
|
106
|
+
void
|
107
|
+
PQinitialize(void)
|
108
|
+
{
|
109
|
+
int i ;
|
110
|
+
|
111
|
+
PQcount = PQmin = 0 ;
|
112
|
+
PQhashsize = 4 * rubyvorState.sqrt_nsites ;
|
113
|
+
PQhash = (Halfedge *)myalloc(PQhashsize * sizeof *PQhash) ;
|
114
|
+
for (i = 0 ; i < PQhashsize; i++)
|
115
|
+
{
|
116
|
+
PQhash[i].PQnext = (Halfedge *)NULL ;
|
117
|
+
}
|
118
|
+
}
|
data/ext/memory.c
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
|
2
|
+
/*** MEMORY.C ***/
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <stdio.h>
|
6
|
+
#include <stdlib.h> /* malloc() */
|
7
|
+
|
8
|
+
#include "vdefs.h"
|
9
|
+
|
10
|
+
static char** memory_map;
|
11
|
+
static int nallocs = 0;
|
12
|
+
|
13
|
+
void
|
14
|
+
freeinit(Freelist * fl, int size)
|
15
|
+
{
|
16
|
+
fl->head = (Freenode *)NULL ;
|
17
|
+
fl->nodesize = size ;
|
18
|
+
}
|
19
|
+
|
20
|
+
char *
|
21
|
+
getfree(Freelist * fl)
|
22
|
+
{
|
23
|
+
int i ;
|
24
|
+
Freenode * t ;
|
25
|
+
if (fl->head == (Freenode *)NULL)
|
26
|
+
{
|
27
|
+
t = (Freenode *) myalloc(rubyvorState.sqrt_nsites * fl->nodesize) ;
|
28
|
+
for(i = 0 ; i < rubyvorState.sqrt_nsites ; i++)
|
29
|
+
{
|
30
|
+
makefree((Freenode *)((char *)t+i*fl->nodesize), fl) ;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
t = fl->head ;
|
34
|
+
fl->head = (fl->head)->nextfree ;
|
35
|
+
return ((char *)t) ;
|
36
|
+
}
|
37
|
+
|
38
|
+
void
|
39
|
+
makefree(Freenode * curr, Freelist * fl)
|
40
|
+
{
|
41
|
+
curr->nextfree = fl->head ;
|
42
|
+
fl->head = curr ;
|
43
|
+
}
|
44
|
+
|
45
|
+
int total_alloc;
|
46
|
+
|
47
|
+
void
|
48
|
+
update_memory_map(char * newp)
|
49
|
+
{
|
50
|
+
if (nallocs % 1000 == 0)
|
51
|
+
{
|
52
|
+
if (nallocs == 0)
|
53
|
+
memory_map = (char **)malloc((nallocs+1000)*sizeof(char*));
|
54
|
+
else
|
55
|
+
memory_map = (char **)realloc(memory_map,(nallocs+1000)*sizeof(char*));
|
56
|
+
}
|
57
|
+
memory_map[nallocs++] = newp;
|
58
|
+
}
|
59
|
+
|
60
|
+
char *
|
61
|
+
myalloc(unsigned n)
|
62
|
+
{
|
63
|
+
char * t;
|
64
|
+
|
65
|
+
if ((t=(char*)malloc(n)) == (char *) 0)
|
66
|
+
rb_raise(rb_eNoMemError, "Insufficient memory processing site %d (%d bytes in use)\n", rubyvorState.siteidx, total_alloc);
|
67
|
+
|
68
|
+
total_alloc += n;
|
69
|
+
|
70
|
+
update_memory_map(t);
|
71
|
+
return (t);
|
72
|
+
}
|
73
|
+
|
74
|
+
char *
|
75
|
+
myrealloc(void * oldp, unsigned n, unsigned oldn)
|
76
|
+
{
|
77
|
+
char * newp;
|
78
|
+
int i;
|
79
|
+
|
80
|
+
if ((newp=(char*)realloc(oldp, n)) == (char *) 0)
|
81
|
+
rb_raise(rb_eNoMemError, "Insufficient memory processing site %d (%d bytes in use)\n", rubyvorState.siteidx, total_alloc);
|
82
|
+
|
83
|
+
total_alloc += (n - oldn);
|
84
|
+
|
85
|
+
update_memory_map(newp);
|
86
|
+
|
87
|
+
/*
|
88
|
+
* Mark oldp as freed, since free() was called by realloc.
|
89
|
+
*
|
90
|
+
* TODO: this seems naive; measure if this is a bottleneck & use a hash table or some other scheme if it is.
|
91
|
+
*/
|
92
|
+
for (i=0; i<nallocs; i++)
|
93
|
+
{
|
94
|
+
if (memory_map[i] != (char*)0 && memory_map[i] == oldp)
|
95
|
+
{
|
96
|
+
memory_map[i] = (char*)0;
|
97
|
+
break;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
return (newp);
|
102
|
+
}
|
103
|
+
|
104
|
+
|
105
|
+
void free_all(void)
|
106
|
+
{
|
107
|
+
int i;
|
108
|
+
for (i=0; i<nallocs; i++)
|
109
|
+
{
|
110
|
+
if (memory_map[i] != (char*)0)
|
111
|
+
{
|
112
|
+
free(memory_map[i]);
|
113
|
+
memory_map[i] = (char*)0;
|
114
|
+
}
|
115
|
+
}
|
116
|
+
free(memory_map);
|
117
|
+
nallocs = 0;
|
118
|
+
}
|