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/History.rdoc
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
=== 0.1.3 / 2010-01-26
|
2
|
+
|
3
|
+
* Ruby 1.9 compatibility update; update for newer Hoe syntax.
|
4
|
+
|
5
|
+
=== 0.1.2 / 2009-04-24
|
6
|
+
|
7
|
+
* Compilation fixes for OSX. Thanks to jpemberthy and febuiles!
|
8
|
+
|
9
|
+
=== 0.1.1 / 2009-01-15
|
10
|
+
|
11
|
+
* LibXML require conflict fix.
|
12
|
+
|
13
|
+
=== 0.1.0 / 2009-01-13
|
14
|
+
|
15
|
+
* Configurable handling of "no neighbors" case.
|
16
|
+
* Tests for "no neighbors" case.
|
17
|
+
|
18
|
+
=== 0.0.9 / 2009-01-01
|
19
|
+
|
20
|
+
Happy New Year!
|
21
|
+
* New speed improvements.
|
22
|
+
* Additional visualization tweaks.
|
23
|
+
* More tests.
|
24
|
+
|
25
|
+
=== 0.0.8 / 2008-12-23
|
26
|
+
|
27
|
+
* Several C warning fixes (more ISO C compliance unused variables, etc)
|
28
|
+
* Moved minimum_spanning_tree computation into C, yielding large speed gain.
|
29
|
+
* Basic SVG visualization.
|
30
|
+
|
31
|
+
=== 0.0.7 / 2008-12-12
|
32
|
+
|
33
|
+
* 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).
|
34
|
+
|
35
|
+
* 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.
|
36
|
+
|
37
|
+
=== 0.0.6 / 2008-12-11
|
38
|
+
|
39
|
+
* Implementation of cluster_by_size to partition points into N clusters.
|
40
|
+
|
41
|
+
=== 0.0.5 / 2008-12-10
|
42
|
+
|
43
|
+
* Beginnings of clustering and useful graph algorithms.
|
44
|
+
* Some refactoring of C methods.
|
45
|
+
|
46
|
+
=== 0.0.4 / 2008-12-04
|
47
|
+
|
48
|
+
* Fixed 64-bit segfaults due to improper definition of the myrealloc() function.
|
49
|
+
|
50
|
+
=== 0.0.3 / 2008-12-03
|
51
|
+
|
52
|
+
* Fixed a segfault by using rb_ary_push instead of direct pointer manipulation. Much simpler.
|
53
|
+
|
54
|
+
=== 0.0.2 / 2008-12-03
|
55
|
+
|
56
|
+
* Computations succeed on a naive Point class, returning raw values for the associated Voronoi Diagram and Delaunay triangulation.
|
57
|
+
|
58
|
+
=== 0.0.1 / 2008-12-01
|
59
|
+
|
60
|
+
* Initial release. Nothing works.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
History.rdoc
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
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
|
data/README.rdoc
ADDED
@@ -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.
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'lib/ruby_vor/version.rb'
|
6
|
+
|
7
|
+
EXT = "ext/voronoi_interface.#{Config::CONFIG['DLEXT']}"
|
8
|
+
|
9
|
+
Hoe.spec 'rubyvor' do
|
10
|
+
developer 'Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com'
|
11
|
+
|
12
|
+
self.version = RubyVor::VERSION
|
13
|
+
self.url = 'http://github.com/bribera/rubyvor'
|
14
|
+
self.readme_file = 'README.rdoc'
|
15
|
+
self.history_file = 'History.rdoc'
|
16
|
+
self.summary = 'Efficient Voronoi diagrams and Delaunay trianglation for Ruby'
|
17
|
+
self.description = 'RubyVor provides efficient computation of Voronoi diagrams and Delaunay triangulation for a set of Ruby points. It is intended to function as a complemenet to GeoRuby. These structures can be used to compute a nearest-neighbor graph for a set of points. This graph can in turn be used for proximity-based clustering of the input points.'
|
18
|
+
|
19
|
+
# C extension goodness
|
20
|
+
self.spec_extras[:extensions] = "ext/extconf.rb"
|
21
|
+
self.clean_globs << EXT << 'ext/*.o' << 'ext/Makefile'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Compile extensions"
|
25
|
+
task :compile => EXT
|
26
|
+
task :test => :compile
|
27
|
+
|
28
|
+
file EXT => ['ext/extconf.rb', 'ext/ruby_vor_c.c'] do
|
29
|
+
Dir.chdir 'ext' do
|
30
|
+
ruby 'extconf.rb'
|
31
|
+
sh 'make'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Prepare for github upload"
|
36
|
+
task :github do
|
37
|
+
system "git ls-files | egrep -v \"\\.gitignore\" > Manifest.txt"
|
38
|
+
system "rake debug_gem | egrep -v \"^\\(in\" > rubyvor.gemspec"
|
39
|
+
end
|
40
|
+
|
41
|
+
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.
|
data/ext/edgelist.c
ADDED
@@ -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
|
+
}
|
data/ext/extconf.rb
ADDED