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/rb_cPoint.c
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor_c.h>
|
4
|
+
#include <math.h>
|
5
|
+
|
6
|
+
/*
|
7
|
+
* Euclidean distance between two Points
|
8
|
+
*/
|
9
|
+
VALUE
|
10
|
+
RubyVor_distance_from(VALUE self, VALUE other)
|
11
|
+
{
|
12
|
+
return rb_float_new(sqrt(pow(NUM2DBL(rb_iv_get(self, "@x")) - NUM2DBL(rb_iv_get(other, "@x")), 2.0) +
|
13
|
+
pow(NUM2DBL(rb_iv_get(self, "@y")) - NUM2DBL(rb_iv_get(other, "@y")), 2.0)));
|
14
|
+
}
|
15
|
+
|
16
|
+
VALUE
|
17
|
+
RubyVor_point_hash(VALUE self)
|
18
|
+
{
|
19
|
+
double x, y;
|
20
|
+
char *c;
|
21
|
+
long i, xHash, yHash;
|
22
|
+
|
23
|
+
x = NUM2DBL(rb_iv_get(self, "@x"));
|
24
|
+
y = NUM2DBL(rb_iv_get(self, "@y"));
|
25
|
+
|
26
|
+
/* Bastardized from Ruby's numeric.c */
|
27
|
+
|
28
|
+
for (c = (char*)&x, xHash = 0, i = 0; i < sizeof(double); i++) xHash += c[i] * 971;
|
29
|
+
for (c = (char*)&y, yHash = 0, i = 0; i < sizeof(double); i++) yHash += c[i] * 971;
|
30
|
+
|
31
|
+
xHash = xHash & RB_HASH_FILTER;
|
32
|
+
yHash = yHash & RB_HASH_FILTER;
|
33
|
+
|
34
|
+
return LONG2FIX((xHash << (RB_LONG_BITS / 2)) | yHash);
|
35
|
+
}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor_c.h>
|
4
|
+
|
5
|
+
/*
|
6
|
+
* Instance methods for RubyVor::VDDT::PriorityQueue
|
7
|
+
*/
|
8
|
+
|
9
|
+
|
10
|
+
static VALUE
|
11
|
+
compare(VALUE a, VALUE b)
|
12
|
+
{
|
13
|
+
double aD, bD;
|
14
|
+
ID minDistance;
|
15
|
+
minDistance = ID2SYM(rb_intern("min_distance"));
|
16
|
+
|
17
|
+
if (CLASS_OF(a) == rb_path2class("RubyVor::PriorityQueue::QueueItem"))
|
18
|
+
aD = NUM2DBL(rb_funcall(a, rb_intern("priority"), 0));
|
19
|
+
else
|
20
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(a), rb_obj_classname(rb_path2class("RubyVor::PriorityQueue::QueueItem")));
|
21
|
+
|
22
|
+
if (CLASS_OF(a) == rb_path2class("RubyVor::PriorityQueue::QueueItem"))
|
23
|
+
bD = NUM2DBL(rb_funcall(b, rb_intern("priority"), 0));
|
24
|
+
else
|
25
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(a), rb_obj_classname(rb_path2class("RubyVor::PriorityQueue::QueueItem")));
|
26
|
+
|
27
|
+
return RTEST(aD < bD);
|
28
|
+
}
|
29
|
+
|
30
|
+
VALUE
|
31
|
+
RubyVor_percolate_up(VALUE self, VALUE index)
|
32
|
+
{
|
33
|
+
VALUE item, data;
|
34
|
+
long i, j, size;
|
35
|
+
|
36
|
+
Check_Type(index, T_FIXNUM);
|
37
|
+
|
38
|
+
data = rb_iv_get(self, "@data");
|
39
|
+
Check_Type(data, T_ARRAY);
|
40
|
+
|
41
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
42
|
+
i = FIX2INT(index) + 1;
|
43
|
+
|
44
|
+
if (i < 1 || i > size)
|
45
|
+
rb_raise(rb_eIndexError, "index %li out of range", i-1);
|
46
|
+
|
47
|
+
j = i / 2;
|
48
|
+
|
49
|
+
item = RARRAY_PTR(data)[i - 1];
|
50
|
+
|
51
|
+
while(j > 0 && compare(item, RARRAY_PTR(data)[j - 1]))
|
52
|
+
{
|
53
|
+
rb_ary_store(data, i-1, RARRAY_PTR(data)[j - 1]);
|
54
|
+
rb_funcall(RARRAY_PTR(data)[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
55
|
+
i = j;
|
56
|
+
j = j / 2;
|
57
|
+
}
|
58
|
+
|
59
|
+
rb_ary_store(data, i-1, item);
|
60
|
+
rb_funcall(RARRAY_PTR(data)[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
61
|
+
|
62
|
+
return Qnil;
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
VALUE
|
67
|
+
RubyVor_percolate_down(VALUE self, VALUE index)
|
68
|
+
{
|
69
|
+
VALUE item, data;
|
70
|
+
long i, j, k, size;
|
71
|
+
|
72
|
+
Check_Type(index, T_FIXNUM);
|
73
|
+
|
74
|
+
data = rb_iv_get(self, "@data");
|
75
|
+
Check_Type(data, T_ARRAY);
|
76
|
+
|
77
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
78
|
+
i = FIX2INT(index) + 1;
|
79
|
+
|
80
|
+
if (i < 1 || i > size)
|
81
|
+
rb_raise(rb_eIndexError, "index %li out of range", i-1);
|
82
|
+
|
83
|
+
j = size / 2;
|
84
|
+
|
85
|
+
item = RARRAY_PTR(data)[i - 1];
|
86
|
+
|
87
|
+
while (!(i > j))
|
88
|
+
{
|
89
|
+
k = i * 2;
|
90
|
+
if (k < size && compare(RARRAY_PTR(data)[k], RARRAY_PTR(data)[k - 1]))
|
91
|
+
k++;
|
92
|
+
|
93
|
+
if (compare(item, RARRAY_PTR(data)[k - 1]))
|
94
|
+
j = -1;
|
95
|
+
else
|
96
|
+
{
|
97
|
+
rb_ary_store(data, i-1, RARRAY_PTR(data)[k - 1]);
|
98
|
+
rb_funcall(RARRAY_PTR(data)[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
99
|
+
i = k;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
rb_ary_store(data, i-1, item);
|
104
|
+
rb_funcall(RARRAY_PTR(data)[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
105
|
+
|
106
|
+
return Qnil;
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
VALUE
|
111
|
+
RubyVor_heapify(VALUE self)
|
112
|
+
{
|
113
|
+
long i, size;
|
114
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
115
|
+
|
116
|
+
for(i = size / 2; i >= 1; i--)
|
117
|
+
RubyVor_percolate_down(self, INT2FIX(i-1));
|
118
|
+
|
119
|
+
return Qnil;
|
120
|
+
}
|
data/ext/ruby_vor_c.c
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor_c.h>
|
4
|
+
|
5
|
+
/* Classes & Modules */
|
6
|
+
static VALUE RubyVor_rb_mRubyVor;
|
7
|
+
static VALUE RubyVor_rb_mVDDT;
|
8
|
+
|
9
|
+
static VALUE RubyVor_rb_cComputation;
|
10
|
+
static VALUE RubyVor_rb_cPriorityQueue;
|
11
|
+
static VALUE RubyVor_rb_cQueueItem;
|
12
|
+
static VALUE RubyVor_rb_cPoint;
|
13
|
+
|
14
|
+
/*
|
15
|
+
* Extension initialization
|
16
|
+
*/
|
17
|
+
void
|
18
|
+
Init_ruby_vor_c(void)
|
19
|
+
{
|
20
|
+
/*
|
21
|
+
* Set up our Modules and Class.
|
22
|
+
*/
|
23
|
+
|
24
|
+
/*
|
25
|
+
* Main RubyVor namespace.
|
26
|
+
*/
|
27
|
+
RubyVor_rb_mRubyVor = rb_define_module("RubyVor");
|
28
|
+
|
29
|
+
|
30
|
+
/*
|
31
|
+
* Voronoi Digram and Delaunay Triangulation namespace.
|
32
|
+
*/
|
33
|
+
RubyVor_rb_mVDDT = rb_define_module_under(RubyVor_rb_mRubyVor, "VDDT");
|
34
|
+
|
35
|
+
|
36
|
+
/*
|
37
|
+
* Class representing a VD/DT computation based on a set of 2-dimensional points
|
38
|
+
*/
|
39
|
+
RubyVor_rb_cComputation = rb_define_class_under(RubyVor_rb_mVDDT, "Computation", rb_cObject);
|
40
|
+
rb_define_singleton_method(RubyVor_rb_cComputation, "from_points", RubyVor_from_points, 1);
|
41
|
+
rb_define_method(RubyVor_rb_cComputation, "nn_graph", RubyVor_nn_graph, 0);
|
42
|
+
rb_define_method(RubyVor_rb_cComputation, "minimum_spanning_tree", RubyVor_minimum_spanning_tree, -1);
|
43
|
+
|
44
|
+
|
45
|
+
/*
|
46
|
+
* A priority queue with a customizable heap-order property.
|
47
|
+
*/
|
48
|
+
RubyVor_rb_cPriorityQueue = rb_define_class_under(RubyVor_rb_mRubyVor, "PriorityQueue", rb_cObject);
|
49
|
+
RubyVor_rb_cQueueItem = rb_define_class_under(RubyVor_rb_cPriorityQueue, "QueueItem", rb_cObject);
|
50
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_up", RubyVor_percolate_up, 1);
|
51
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_down", RubyVor_percolate_down, 1);
|
52
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "heapify", RubyVor_heapify, 0);
|
53
|
+
|
54
|
+
|
55
|
+
/*
|
56
|
+
* A simple Point class
|
57
|
+
*/
|
58
|
+
RubyVor_rb_cPoint = rb_define_class_under(RubyVor_rb_mRubyVor, "Point", rb_cObject);
|
59
|
+
rb_define_method(RubyVor_rb_cPoint, "distance_from", RubyVor_distance_from, 1);
|
60
|
+
rb_define_method(RubyVor_rb_cPoint, "hash", RubyVor_point_hash, 0);
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
/*
|
67
|
+
* Method declarations duplicated here for RDOC
|
68
|
+
*/
|
69
|
+
|
70
|
+
/*
|
71
|
+
* Compute the voronoi diagram and delaunay triangulation from a set of points.
|
72
|
+
*
|
73
|
+
* This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
|
74
|
+
* It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
|
75
|
+
*/
|
76
|
+
VALUE RubyVor_from_points(VALUE, VALUE);
|
77
|
+
|
78
|
+
/*
|
79
|
+
* Compute the nearest-neighbor graph using the existing Delaunay triangulation.
|
80
|
+
*/
|
81
|
+
VALUE RubyVor_nn_graph(VALUE);
|
82
|
+
|
83
|
+
/*
|
84
|
+
* Computes the minimum spanning tree for given points, using the Delaunay triangulation as a seed.
|
85
|
+
*
|
86
|
+
* For points on a Euclidean plane, the MST is always comprised of a subset of the edges in a Delaunay triangulation. This makes computation of the tree very efficient: simply compute the Delaunay triangulation, and then run Prim's algorithm on the resulting edges.
|
87
|
+
*/
|
88
|
+
VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
|
89
|
+
|
90
|
+
/*
|
91
|
+
* Move from the given index up, restoring the heap-order property.
|
92
|
+
*/
|
93
|
+
VALUE RubyVor_percolate_up(VALUE, VALUE);
|
94
|
+
|
95
|
+
/*
|
96
|
+
* Move from the index down, restoring the heap-order property.
|
97
|
+
*/
|
98
|
+
VALUE RubyVor_percolate_down(VALUE, VALUE);
|
99
|
+
|
100
|
+
/*
|
101
|
+
* Restore the heap-order property for a randomly ordered array of entries.
|
102
|
+
*/
|
103
|
+
VALUE RubyVor_heapify(VALUE);
|
104
|
+
|
105
|
+
/*
|
106
|
+
* Compute the Euclidean distance between two points.
|
107
|
+
*/
|
108
|
+
VALUE RubyVor_distance_from(VALUE, VALUE);
|
109
|
+
|
110
|
+
/*
|
111
|
+
* Hash value for a point.
|
112
|
+
*/
|
113
|
+
VALUE RubyVor_point_hash(VALUE);
|
114
|
+
|
115
|
+
/* keep comment so RDOC will find the last method definition */
|
data/ext/ruby_vor_c.h
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#ifndef __RUBY_VOR_H
|
2
|
+
#define __RUBY_VOR_H
|
3
|
+
|
4
|
+
#ifndef RB_LONG_BITS
|
5
|
+
#define RB_LONG_BITS sizeof(long)*8
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#ifndef RB_HASH_FILTER
|
9
|
+
#define RB_HASH_FILTER ((2 << (RB_LONG_BITS / 2 - 1)) - 1)
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#ifndef RUBY_19
|
13
|
+
#ifndef RFLOAT_VALUE
|
14
|
+
#define RFLOAT_VALUE(v) (RFLOAT(v)->value)
|
15
|
+
#endif
|
16
|
+
#ifndef RARRAY_LEN
|
17
|
+
#define RARRAY_LEN(v) (RARRAY(v)->len)
|
18
|
+
#endif
|
19
|
+
#ifndef RARRAY_PTR
|
20
|
+
#define RARRAY_PTR(v) (RARRAY(v)->ptr)
|
21
|
+
#endif
|
22
|
+
#endif
|
23
|
+
|
24
|
+
extern VoronoiState rubyvorState;
|
25
|
+
|
26
|
+
/* Computation */
|
27
|
+
VALUE RubyVor_from_points(VALUE, VALUE);
|
28
|
+
VALUE RubyVor_nn_graph(VALUE);
|
29
|
+
VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
|
30
|
+
|
31
|
+
/* PriorityQueue */
|
32
|
+
VALUE RubyVor_percolate_up(VALUE, VALUE);
|
33
|
+
VALUE RubyVor_percolate_down(VALUE, VALUE);
|
34
|
+
VALUE RubyVor_heapify(VALUE);
|
35
|
+
|
36
|
+
/* Point */
|
37
|
+
VALUE RubyVor_distance_from(VALUE, VALUE);
|
38
|
+
VALUE RubyVor_point_hash(VALUE);
|
39
|
+
|
40
|
+
#endif
|
data/ext/vdefs.h
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
#ifndef __VDEFS_H
|
2
|
+
#define __VDEFS_H
|
3
|
+
|
4
|
+
#ifndef NULL
|
5
|
+
#define NULL 0
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#define DELETED -2
|
9
|
+
|
10
|
+
typedef struct tagFreenode
|
11
|
+
{
|
12
|
+
struct tagFreenode * nextfree;
|
13
|
+
} Freenode ;
|
14
|
+
|
15
|
+
|
16
|
+
typedef struct tagFreelist
|
17
|
+
{
|
18
|
+
Freenode * head;
|
19
|
+
int nodesize;
|
20
|
+
} Freelist ;
|
21
|
+
|
22
|
+
typedef struct tagPoint
|
23
|
+
{
|
24
|
+
float x ;
|
25
|
+
float y ;
|
26
|
+
} Point ;
|
27
|
+
|
28
|
+
/* structure used both for sites and for vertices */
|
29
|
+
|
30
|
+
typedef struct tagSite
|
31
|
+
{
|
32
|
+
Point coord ;
|
33
|
+
int sitenbr ;
|
34
|
+
int refcnt ;
|
35
|
+
} Site ;
|
36
|
+
|
37
|
+
|
38
|
+
typedef struct tagEdge
|
39
|
+
{
|
40
|
+
float a, b, c ;
|
41
|
+
Site * ep[2] ;
|
42
|
+
Site * reg[2] ;
|
43
|
+
int edgenbr ;
|
44
|
+
} Edge ;
|
45
|
+
|
46
|
+
#define le 0
|
47
|
+
#define re 1
|
48
|
+
|
49
|
+
typedef struct tagHalfedge
|
50
|
+
{
|
51
|
+
struct tagHalfedge * ELleft ;
|
52
|
+
struct tagHalfedge * ELright ;
|
53
|
+
Edge * ELedge ;
|
54
|
+
int ELrefcnt ;
|
55
|
+
char ELpm ;
|
56
|
+
Site * vertex ;
|
57
|
+
float ystar ;
|
58
|
+
struct tagHalfedge * PQnext ;
|
59
|
+
} Halfedge ;
|
60
|
+
|
61
|
+
typedef struct tagVoronoiState
|
62
|
+
{
|
63
|
+
/* voronoi.c */
|
64
|
+
int sorted, plot, debug, siteidx;
|
65
|
+
float xmin, xmax, ymin, ymax;
|
66
|
+
Site * sites;
|
67
|
+
void * comp;
|
68
|
+
void (* storeT)(int, int, int);
|
69
|
+
void (* storeL)(float, float, float);
|
70
|
+
void (* storeE)(int, int, int);
|
71
|
+
void (* storeV)(float, float);
|
72
|
+
void (* storeS)(float, float);
|
73
|
+
|
74
|
+
/* geometry.c */
|
75
|
+
float deltax, deltay;
|
76
|
+
int nsites, nedges, sqrt_nsites, nvertices;
|
77
|
+
Freelist sfl;
|
78
|
+
|
79
|
+
/* edgelist.c */
|
80
|
+
int ELhashsize;
|
81
|
+
Site * bottomsite;
|
82
|
+
} VoronoiState;
|
83
|
+
|
84
|
+
extern VoronoiState rubyvorState;
|
85
|
+
|
86
|
+
/* edgelist.c */
|
87
|
+
void ELinitialize(void) ;
|
88
|
+
Halfedge * HEcreate(Edge *, int) ;
|
89
|
+
void ELinsert(Halfedge *, Halfedge *) ;
|
90
|
+
Halfedge * ELgethash(int) ;
|
91
|
+
Halfedge * ELleftbnd(Point *) ;
|
92
|
+
void ELdelete(Halfedge *) ;
|
93
|
+
Halfedge * ELright(Halfedge *) ;
|
94
|
+
Halfedge * ELleft(Halfedge *) ;
|
95
|
+
Site * leftreg(Halfedge *) ;
|
96
|
+
Site * rightreg(Halfedge *) ;
|
97
|
+
Halfedge * getELleftend(void) ;
|
98
|
+
Halfedge * getELrightend(void) ;
|
99
|
+
|
100
|
+
/* geometry.c */
|
101
|
+
void geominit(void) ;
|
102
|
+
Edge * bisect(Site *, Site *) ;
|
103
|
+
Site * intersect(Halfedge *, Halfedge *) ;
|
104
|
+
int right_of(Halfedge *, Point *) ;
|
105
|
+
void endpoint(Edge *, int, Site *) ;
|
106
|
+
float dist(Site *, Site *) ;
|
107
|
+
void makevertex(Site *) ;
|
108
|
+
void deref(Site *) ;
|
109
|
+
void ref(Site *) ;
|
110
|
+
|
111
|
+
/* heap.c */
|
112
|
+
void PQinsert(Halfedge *, Site *, float) ;
|
113
|
+
void PQdelete(Halfedge *) ;
|
114
|
+
int PQbucket(Halfedge *) ;
|
115
|
+
int PQempty(void) ;
|
116
|
+
Point PQ_min(void) ;
|
117
|
+
Halfedge * PQextractmin(void) ;
|
118
|
+
void PQinitialize(void) ;
|
119
|
+
|
120
|
+
/* getopt.c */
|
121
|
+
extern int getopt(int, char *const *, const char *);
|
122
|
+
|
123
|
+
/* memory.c */
|
124
|
+
void freeinit(Freelist *, int) ;
|
125
|
+
char *getfree(Freelist *) ;
|
126
|
+
void makefree(Freenode *, Freelist *) ;
|
127
|
+
char *myalloc(unsigned) ;
|
128
|
+
char *myrealloc(void *, unsigned, unsigned);
|
129
|
+
void free_all(void);
|
130
|
+
|
131
|
+
/* output.c */
|
132
|
+
void openpl(void) ;
|
133
|
+
void line(float, float, float, float) ;
|
134
|
+
void circle(float, float, float) ;
|
135
|
+
void range(float, float, float, float) ;
|
136
|
+
void out_bisector(Edge *) ;
|
137
|
+
void out_ep(Edge *) ;
|
138
|
+
void out_vertex(Site *) ;
|
139
|
+
void out_site(Site *) ;
|
140
|
+
void out_triple(Site *, Site *, Site *) ;
|
141
|
+
void plotinit(void) ;
|
142
|
+
void clip_line(Edge *) ;
|
143
|
+
void debug_memory(void);
|
144
|
+
|
145
|
+
/* voronoi.c */
|
146
|
+
void voronoi(Site *(*)()) ;
|
147
|
+
void initialize_state(int);
|
148
|
+
#endif
|
149
|
+
|
150
|
+
|