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,56 @@
1
+ === 0.1.2 / 2009-04-24
2
+
3
+ * Compilation fixes for OSX. Thanks to jpemberthy and febuiles!
4
+
5
+ === 0.1.1 / 2009-01-15
6
+
7
+ * LibXML require conflict fix.
8
+
9
+ === 0.1.0 / 2009-01-13
10
+
11
+ * Configurable handling of "no neighbors" case.
12
+ * Tests for "no neighbors" case.
13
+
14
+ === 0.0.9 / 2009-01-01
15
+
16
+ Happy New Year!
17
+ * New speed improvements.
18
+ * Additional visualization tweaks.
19
+ * More tests.
20
+
21
+ === 0.0.8 / 2008-12-23
22
+
23
+ * Several C warning fixes (more ISO C compliance unused variables, etc)
24
+ * Moved minimum_spanning_tree computation into C, yielding large speed gain.
25
+ * Basic SVG visualization.
26
+
27
+ === 0.0.7 / 2008-12-12
28
+
29
+ * Bugfix: there are cases where performing a Delaunay triangulation on a set of points will not yield a complete nearest neighbor graph. This causes computation of the minimum spanning tree and clustering to fail for these nodes (they always appear as disconnected from the main graph).
30
+
31
+ * To fix this, the nn_graph function now treats any point that is excluded from Delaunay triangulation as having *all* other points as nearest neighbors. This is a naive approach, but is a good fix while a more efficient solution is considered.
32
+
33
+ === 0.0.6 / 2008-12-11
34
+
35
+ * Implementation of cluster_by_size to partition points into N clusters.
36
+
37
+ === 0.0.5 / 2008-12-10
38
+
39
+ * Beginnings of clustering and useful graph algorithms.
40
+ * Some refactoring of C methods.
41
+
42
+ === 0.0.4 / 2008-12-04
43
+
44
+ * Fixed 64-bit segfaults due to improper definition of the myrealloc() function.
45
+
46
+ === 0.0.3 / 2008-12-03
47
+
48
+ * Fixed a segfault by using rb_ary_push instead of direct pointer manipulation. Much simpler.
49
+
50
+ === 0.0.2 / 2008-12-03
51
+
52
+ * Computations succeed on a naive Point class, returning raw values for the associated Voronoi Diagram and Delaunay triangulation.
53
+
54
+ === 0.0.1 / 2008-12-01
55
+
56
+ * Initial release. Nothing works.
@@ -0,0 +1,30 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ ext/Doc
6
+ ext/edgelist.c
7
+ ext/extconf.rb
8
+ ext/geometry.c
9
+ ext/heap.c
10
+ ext/memory.c
11
+ ext/output.c
12
+ ext/rb_cComputation.c
13
+ ext/rb_cPoint.c
14
+ ext/rb_cPriorityQueue.c
15
+ ext/ruby_vor_c.c
16
+ ext/ruby_vor_c.h
17
+ ext/vdefs.h
18
+ ext/voronoi.c
19
+ lib/ruby_vor.rb
20
+ lib/ruby_vor/computation.rb
21
+ lib/ruby_vor/geo_ruby_extensions.rb
22
+ lib/ruby_vor/point.rb
23
+ lib/ruby_vor/priority_queue.rb
24
+ lib/ruby_vor/version.rb
25
+ lib/ruby_vor/visualizer.rb
26
+ rubyvor.gemspec
27
+ test/test_computation.rb
28
+ test/test_point.rb
29
+ test/test_priority_queue.rb
30
+ test/test_voronoi_interface.rb
@@ -0,0 +1,76 @@
1
+ = rubyvor
2
+
3
+ Efficient Voronoi diagrams and Delaunay trianglation for Ruby
4
+
5
+ == Description
6
+
7
+ RubyVor provides efficient computation of Voronoi diagrams and
8
+ Delaunay triangulation for a set of Ruby points. It is intended to
9
+ function as a complemenet to GeoRuby. These structures can be used to
10
+ compute a nearest-neighbor graph for a set of points. This graph can
11
+ in turn be used for proximity-based clustering of the input points.
12
+
13
+ == Usage:
14
+
15
+ require 'lib/ruby_vor'
16
+ require 'pp'
17
+
18
+ points = [
19
+ RubyVor::Point.new(120, 290),
20
+ RubyVor::Point.new(110, 120),
21
+ RubyVor::Point.new(160, 90.2),
22
+ RubyVor::Point.new(3.14159265, 3.14159265)
23
+ ]
24
+
25
+ # Compute the diagram & triangulation
26
+ comp = RubyVor::VDDT::Computation.from_points(points)
27
+
28
+ puts "The nearest-neighbor graph:"
29
+ pp comp.nn_graph
30
+
31
+ puts "\nThe minimum-spanning tree:"
32
+ pp comp.minimum_spanning_tree
33
+
34
+ #
35
+ # Visualize these things as SVGs
36
+ #
37
+
38
+ # Just the triangulation
39
+ RubyVor::Visualizer.make_svg(comp, :name => 'tri.svg')
40
+
41
+ # Just the MST
42
+ RubyVor::Visualizer.make_svg(comp, :name => 'mst.svg', :triangulation => false, :mst => true)
43
+
44
+ # Voronoi diagram and the triangulation
45
+ RubyVor::Visualizer.make_svg(comp, :name => 'dia.svg', :voronoi_diagram => true)
46
+
47
+
48
+ == LICENSE:
49
+
50
+ Original public-domain C code (by Steven Fortune; http://ect.bell-labs.com/who/sjf/) and
51
+ memory-management fixes for said C code (by Derek Bradley; http://www.derekbradley.ca)
52
+ used (and released under the MIT-LICENSE) with permission.
53
+
54
+
55
+ (The MIT License)
56
+
57
+ Copyright (c) 2008 Brendan Ribera <brendan.ribera+rubyvor@gmail.com>
58
+
59
+
60
+ Permission is hereby granted, free of charge, to any person obtaining a copy
61
+ of this software and associated documentation files (the "Software"), to deal
62
+ in the Software without restriction, including without limitation the rights
63
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64
+ copies of the Software, and to permit persons to whom the Software is
65
+ furnished to do so, subject to the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be included in
68
+ all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
76
+ THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/ruby_vor/version.rb'
6
+
7
+ EXT = "ext/voronoi_interface.#{Hoe::DLEXT}"
8
+
9
+ Hoe.new('rubyvor', RubyVor::VERSION) do |p|
10
+ p.developer('Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com')
11
+ p.url = 'http://github.com/bribera/rubyvor'
12
+
13
+ # C extension goodness
14
+ p.spec_extras[:extensions] = "ext/extconf.rb"
15
+ p.clean_globs << EXT << 'ext/*.o' << 'ext/Makefile'
16
+ end
17
+
18
+ desc "Compile extensions"
19
+ task :compile => EXT
20
+ task :test => :compile
21
+
22
+ file EXT => ['ext/extconf.rb', 'ext/ruby_vor_c.c'] do
23
+ Dir.chdir 'ext' do
24
+ ruby 'extconf.rb'
25
+ sh 'make'
26
+ end
27
+ end
28
+
29
+ desc "Prepare for github upload"
30
+ task :github do
31
+ system "git ls-files | egrep -v \"\\.gitignore\" > Manifest.txt"
32
+ system "rake debug_gem | egrep -v \"^\\(in\" > rubyvor.gemspec"
33
+ end
34
+
35
+ task :gem => :github
data/ext/Doc ADDED
@@ -0,0 +1,30 @@
1
+ voronoi - compute Voronoi diagram or Delaunay triangulation
2
+ SYNOPSIS
3
+ voronoi [-s -t] <pointfile >outputfile
4
+
5
+ Voronoi reads the standard input for a set of points in the plane and writes either
6
+ the Voronoi diagram or the Delaunay triangulation to the standard output.
7
+ Each input line should consist of two real numbers, separated by white space.
8
+
9
+ If option
10
+ -t
11
+ is present, the Delaunay triangulation is produced.
12
+ Each output line is a triple
13
+ i j k
14
+ which are the indices of the three points in a Delaunay triangle. Points are
15
+ numbered starting at 0. If this option is not present, the
16
+ Voronoi diagram is produced. There are four output record types.
17
+ s a b
18
+ indicates that an input point at coordinates
19
+ l a b c
20
+ indicates a line with equation ax + by = c.
21
+ v a b
22
+ indicates a vertex at a b.
23
+ e l v1 v2
24
+ indicates a Voronoi segment which is a subsegment of line number l;
25
+ with endpoints numbered v1 and v2. If v1 or v2 is -1, the line
26
+ extends to infinity.
27
+
28
+ AUTHOR
29
+ Steve J. Fortune (1987) A Sweepline Algorithm for Voronoi Diagrams,
30
+ Algorithmica 2, 153-174.
@@ -0,0 +1,204 @@
1
+
2
+ /*** EDGELIST.C ***/
3
+
4
+ #include "vdefs.h"
5
+
6
+ static int ELhashsize ;
7
+ static Halfedge * ELleftend, * ELrightend, ** ELhash ;
8
+ static Freelist hfl ;
9
+ static int ntry, totalsearch ;
10
+
11
+ void
12
+ ELinitialize(void)
13
+ {
14
+ int i ;
15
+
16
+ freeinit(&hfl, sizeof(Halfedge)) ;
17
+ ELhashsize = 2 * rubyvorState.sqrt_nsites ;
18
+ ELhash = (Halfedge **)myalloc( sizeof(*ELhash) * ELhashsize) ;
19
+ for (i = 0 ; i < ELhashsize ; i++)
20
+ {
21
+ ELhash[i] = (Halfedge *)NULL ;
22
+ }
23
+ ELleftend = HEcreate((Edge *)NULL, 0) ;
24
+ ELrightend = HEcreate((Edge *)NULL, 0) ;
25
+ ELleftend->ELleft = (Halfedge *)NULL ;
26
+ ELleftend->ELright = ELrightend ;
27
+ ELrightend->ELleft = ELleftend ;
28
+ ELrightend->ELright = (Halfedge *)NULL ;
29
+ ELhash[0] = ELleftend ;
30
+ ELhash[ELhashsize-1] = ELrightend ;
31
+ }
32
+
33
+ Halfedge *
34
+ HEcreate(Edge * e, int pm)
35
+ {
36
+ Halfedge * answer ;
37
+
38
+ answer = (Halfedge *)getfree(&hfl) ;
39
+ answer->ELedge = e ;
40
+ answer->ELpm = pm ;
41
+ answer->PQnext = (Halfedge *)NULL ;
42
+ answer->vertex = (Site *)NULL ;
43
+ answer->ELrefcnt = 0 ;
44
+ return (answer) ;
45
+ }
46
+
47
+ void
48
+ ELinsert(Halfedge * lb, Halfedge * new)
49
+ {
50
+ new->ELleft = lb ;
51
+ new->ELright = lb->ELright ;
52
+ (lb->ELright)->ELleft = new ;
53
+ lb->ELright = new ;
54
+ }
55
+
56
+ /* Get entry from hash table, pruning any deleted nodes */
57
+
58
+ Halfedge *
59
+ ELgethash(int b)
60
+ {
61
+ Halfedge * he ;
62
+
63
+ if ((b < 0) || (b >= ELhashsize))
64
+ {
65
+ return ((Halfedge *)NULL) ;
66
+ }
67
+ he = ELhash[b] ;
68
+ if ((he == (Halfedge *)NULL) || (he->ELedge != (Edge *)DELETED))
69
+ {
70
+ return (he) ;
71
+ }
72
+ /* Hash table points to deleted half edge. Patch as necessary. */
73
+ ELhash[b] = (Halfedge *)NULL ;
74
+ if ((--(he->ELrefcnt)) == 0)
75
+ {
76
+ makefree((Freenode *)he, (Freelist *)&hfl) ;
77
+ }
78
+ return ((Halfedge *)NULL) ;
79
+ }
80
+
81
+ Halfedge *
82
+ ELleftbnd(Point * p)
83
+ {
84
+ int i, bucket ;
85
+ Halfedge * he ;
86
+
87
+ /* Use hash table to get close to desired halfedge */
88
+ bucket = (p->x - rubyvorState.xmin) / rubyvorState.deltax * ELhashsize ;
89
+ if (bucket < 0)
90
+ {
91
+ bucket = 0 ;
92
+ }
93
+ if (bucket >= ELhashsize)
94
+ {
95
+ bucket = ELhashsize - 1 ;
96
+ }
97
+ he = ELgethash(bucket) ;
98
+ if (he == (Halfedge *)NULL)
99
+ {
100
+ for (i = 1 ; 1 ; i++)
101
+ {
102
+ if ((he = ELgethash(bucket-i)) != (Halfedge *)NULL)
103
+ {
104
+ break ;
105
+ }
106
+ if ((he = ELgethash(bucket+i)) != (Halfedge *)NULL)
107
+ {
108
+ break ;
109
+ }
110
+ }
111
+ totalsearch += i ;
112
+ }
113
+ ntry++ ;
114
+ /* Now search linear list of halfedges for the corect one */
115
+ if (he == ELleftend || (he != ELrightend && right_of(he,p)))
116
+ {
117
+ do {
118
+ he = he->ELright ;
119
+ } while (he != ELrightend && right_of(he,p)) ;
120
+ he = he->ELleft ;
121
+ }
122
+ else
123
+ {
124
+ do {
125
+ he = he->ELleft ;
126
+ } while (he != ELleftend && !right_of(he,p)) ;
127
+ }
128
+ /*** Update hash table and reference counts ***/
129
+ if ((bucket > 0) && (bucket < ELhashsize-1))
130
+ {
131
+ if (ELhash[bucket] != (Halfedge *)NULL)
132
+ {
133
+ (ELhash[bucket]->ELrefcnt)-- ;
134
+ }
135
+ ELhash[bucket] = he ;
136
+ (ELhash[bucket]->ELrefcnt)++ ;
137
+ }
138
+ return (he) ;
139
+ }
140
+
141
+ /*** This delete routine can't reclaim node, since pointers from hash
142
+ : table may be present.
143
+ ***/
144
+
145
+ void
146
+ ELdelete(Halfedge * he)
147
+ {
148
+ (he->ELleft)->ELright = he->ELright ;
149
+ (he->ELright)->ELleft = he->ELleft ;
150
+ he->ELedge = (Edge *)DELETED ;
151
+ }
152
+
153
+ Halfedge *
154
+ ELright(Halfedge * he)
155
+ {
156
+ return (he->ELright) ;
157
+ }
158
+
159
+ Halfedge *
160
+ ELleft(Halfedge * he)
161
+ {
162
+ return (he->ELleft) ;
163
+ }
164
+
165
+ Site *
166
+ leftreg(Halfedge * he)
167
+ {
168
+ if (he->ELedge == (Edge *)NULL)
169
+ {
170
+ return(rubyvorState.bottomsite) ;
171
+ }
172
+ return (he->ELpm == le ? he->ELedge->reg[le] :
173
+ he->ELedge->reg[re]) ;
174
+ }
175
+
176
+ Site *
177
+ rightreg(Halfedge * he)
178
+ {
179
+ if (he->ELedge == (Edge *)NULL)
180
+ {
181
+ return(rubyvorState.bottomsite) ;
182
+ }
183
+ return (he->ELpm == le ? he->ELedge->reg[re] :
184
+ he->ELedge->reg[le]) ;
185
+ }
186
+
187
+ /*
188
+ * Semi-hacky way to access these static variables. Placing them inside rubyvorState
189
+ * causes pointer issues that I don't want to debug, and they're only accessed briefly
190
+ * inside of voronoi.c. Since we're just doing pointer comparison there, this is an
191
+ * acceptable compromise.
192
+ */
193
+
194
+ Halfedge *
195
+ getELleftend(void)
196
+ {
197
+ return(ELleftend);
198
+ }
199
+
200
+ Halfedge *
201
+ getELrightend(void)
202
+ {
203
+ return(ELrightend);
204
+ }
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ dir_config('ruby_vor_c')
3
+ create_makefile('ruby_vor_c')
@@ -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
+