abscondment-rubyvor 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +56 -0
- data/Manifest.txt +30 -0
- data/README.txt +76 -0
- data/Rakefile +35 -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 +121 -0
- data/ext/ruby_vor_c.c +115 -0
- data/ext/ruby_vor_c.h +28 -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 +137 -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 +84 -0
- data/lib/ruby_vor/version.rb +3 -0
- data/lib/ruby_vor/visualizer.rb +218 -0
- data/rubyvor.gemspec +36 -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/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,28 @@
|
|
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
|
+
extern VoronoiState rubyvorState;
|
13
|
+
|
14
|
+
/* Computation */
|
15
|
+
VALUE RubyVor_from_points(VALUE, VALUE);
|
16
|
+
VALUE RubyVor_nn_graph(VALUE);
|
17
|
+
VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
|
18
|
+
|
19
|
+
/* PriorityQueue */
|
20
|
+
VALUE RubyVor_percolate_up(VALUE, VALUE);
|
21
|
+
VALUE RubyVor_percolate_down(VALUE, VALUE);
|
22
|
+
VALUE RubyVor_heapify(VALUE);
|
23
|
+
|
24
|
+
/* Point */
|
25
|
+
VALUE RubyVor_distance_from(VALUE, VALUE);
|
26
|
+
VALUE RubyVor_point_hash(VALUE);
|
27
|
+
|
28
|
+
#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
|
+
|
data/ext/voronoi.c
ADDED
@@ -0,0 +1,271 @@
|
|
1
|
+
|
2
|
+
/*** VORONOI.C ***/
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <vdefs.h>
|
6
|
+
#include <stdio.h>
|
7
|
+
|
8
|
+
VoronoiState rubyvorState;
|
9
|
+
|
10
|
+
/* Static method definitions: C -> Ruby storage methods. */
|
11
|
+
static void storeTriangulationTriplet(const int, const int, const int);
|
12
|
+
static void storeLine(const float, const float, const float);
|
13
|
+
static void storeEndpoint(const int, const int, const int);
|
14
|
+
static void storeVertex(const float, const float);
|
15
|
+
static void storeSite(const float, const float);
|
16
|
+
|
17
|
+
/*** implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
|
18
|
+
: deltax, deltay (can all be estimates).
|
19
|
+
: Performance suffers if they are wrong; better to make nsites,
|
20
|
+
: deltax, and deltay too big than too small. (?)
|
21
|
+
***/
|
22
|
+
|
23
|
+
void initialize_state(int debug)
|
24
|
+
{
|
25
|
+
/* Set up our initial state */
|
26
|
+
rubyvorState.debug = debug;
|
27
|
+
rubyvorState.plot = 0;
|
28
|
+
rubyvorState.nsites = 0;
|
29
|
+
rubyvorState.siteidx = 0;
|
30
|
+
|
31
|
+
rubyvorState.storeT = storeTriangulationTriplet;
|
32
|
+
rubyvorState.storeL = storeLine;
|
33
|
+
rubyvorState.storeE = storeEndpoint;
|
34
|
+
rubyvorState.storeV = storeVertex;
|
35
|
+
rubyvorState.storeS = storeSite;
|
36
|
+
|
37
|
+
/* Initialize the Site Freelist */
|
38
|
+
freeinit(&(rubyvorState.sfl), sizeof(Site)) ;
|
39
|
+
|
40
|
+
/* Initialize the geometry module */
|
41
|
+
geominit() ;
|
42
|
+
|
43
|
+
/* TODO: remove C plot references */
|
44
|
+
if (rubyvorState.plot)
|
45
|
+
plotinit();
|
46
|
+
}
|
47
|
+
|
48
|
+
void
|
49
|
+
voronoi(Site *(*nextsite)(void))
|
50
|
+
{
|
51
|
+
Site * newsite, * bot, * top, * temp, * p, * v ;
|
52
|
+
Point newintstar ;
|
53
|
+
int pm , c;
|
54
|
+
Halfedge * lbnd, * rbnd, * llbnd, * rrbnd, * bisector ;
|
55
|
+
Edge * e ;
|
56
|
+
|
57
|
+
newintstar.x = newintstar.y = c = 0;
|
58
|
+
|
59
|
+
PQinitialize() ;
|
60
|
+
rubyvorState.bottomsite = (*nextsite)() ;
|
61
|
+
out_site(rubyvorState.bottomsite) ;
|
62
|
+
ELinitialize() ;
|
63
|
+
newsite = (*nextsite)() ;
|
64
|
+
|
65
|
+
while (1)
|
66
|
+
{
|
67
|
+
if(!PQempty())
|
68
|
+
newintstar = PQ_min() ;
|
69
|
+
|
70
|
+
if (newsite != (Site *)NULL && (PQempty()
|
71
|
+
|| newsite -> coord.y < newintstar.y
|
72
|
+
|| (newsite->coord.y == newintstar.y
|
73
|
+
&& newsite->coord.x < newintstar.x)))
|
74
|
+
{
|
75
|
+
/* new site is smallest */
|
76
|
+
{
|
77
|
+
out_site(newsite) ;
|
78
|
+
}
|
79
|
+
lbnd = ELleftbnd(&(newsite->coord)) ;
|
80
|
+
rbnd = ELright(lbnd) ;
|
81
|
+
bot = rightreg(lbnd) ;
|
82
|
+
e = bisect(bot, newsite) ;
|
83
|
+
bisector = HEcreate(e, le) ;
|
84
|
+
ELinsert(lbnd, bisector) ;
|
85
|
+
p = intersect(lbnd, bisector) ;
|
86
|
+
if (p != (Site *)NULL)
|
87
|
+
{
|
88
|
+
PQdelete(lbnd) ;
|
89
|
+
PQinsert(lbnd, p, dist(p,newsite)) ;
|
90
|
+
}
|
91
|
+
lbnd = bisector ;
|
92
|
+
bisector = HEcreate(e, re) ;
|
93
|
+
ELinsert(lbnd, bisector) ;
|
94
|
+
p = intersect(bisector, rbnd) ;
|
95
|
+
if (p != (Site *)NULL)
|
96
|
+
{
|
97
|
+
PQinsert(bisector, p, dist(p,newsite)) ;
|
98
|
+
}
|
99
|
+
newsite = (*nextsite)() ;
|
100
|
+
}
|
101
|
+
else if (!PQempty()) /* intersection is smallest */
|
102
|
+
{
|
103
|
+
lbnd = PQextractmin() ;
|
104
|
+
llbnd = ELleft(lbnd) ;
|
105
|
+
rbnd = ELright(lbnd) ;
|
106
|
+
rrbnd = ELright(rbnd) ;
|
107
|
+
bot = leftreg(lbnd) ;
|
108
|
+
top = rightreg(rbnd) ;
|
109
|
+
out_triple(bot, top, rightreg(lbnd)) ;
|
110
|
+
v = lbnd->vertex ;
|
111
|
+
makevertex(v) ;
|
112
|
+
endpoint(lbnd->ELedge, lbnd->ELpm, v);
|
113
|
+
endpoint(rbnd->ELedge, rbnd->ELpm, v) ;
|
114
|
+
ELdelete(lbnd) ;
|
115
|
+
PQdelete(rbnd) ;
|
116
|
+
ELdelete(rbnd) ;
|
117
|
+
pm = le ;
|
118
|
+
if (bot->coord.y > top->coord.y)
|
119
|
+
{
|
120
|
+
temp = bot ;
|
121
|
+
bot = top ;
|
122
|
+
top = temp ;
|
123
|
+
pm = re ;
|
124
|
+
}
|
125
|
+
e = bisect(bot, top) ;
|
126
|
+
bisector = HEcreate(e, pm) ;
|
127
|
+
ELinsert(llbnd, bisector) ;
|
128
|
+
endpoint(e, re-pm, v) ;
|
129
|
+
deref(v) ;
|
130
|
+
p = intersect(llbnd, bisector) ;
|
131
|
+
if (p != (Site *) NULL)
|
132
|
+
{
|
133
|
+
PQdelete(llbnd) ;
|
134
|
+
PQinsert(llbnd, p, dist(p,bot)) ;
|
135
|
+
}
|
136
|
+
p = intersect(bisector, rrbnd) ;
|
137
|
+
if (p != (Site *) NULL)
|
138
|
+
{
|
139
|
+
PQinsert(bisector, p, dist(p,bot)) ;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
else
|
143
|
+
{
|
144
|
+
break ;
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
for( lbnd = ELright(getELleftend()) ;
|
149
|
+
lbnd != getELrightend() ;
|
150
|
+
lbnd = ELright(lbnd))
|
151
|
+
{
|
152
|
+
e = lbnd->ELedge ;
|
153
|
+
out_ep(e) ;
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
/*
|
161
|
+
* Static storage methods
|
162
|
+
*/
|
163
|
+
|
164
|
+
/*** stores a triplet of point indices that comprise a Delaunay triangle ***/
|
165
|
+
static void
|
166
|
+
storeTriangulationTriplet(const int a, const int b, const int c)
|
167
|
+
{
|
168
|
+
VALUE trArray, triplet;
|
169
|
+
|
170
|
+
/* Create a new triplet from the three incoming points */
|
171
|
+
triplet = rb_ary_new2(3);
|
172
|
+
|
173
|
+
rb_ary_push(triplet, INT2FIX(a));
|
174
|
+
rb_ary_push(triplet, INT2FIX(b));
|
175
|
+
rb_ary_push(triplet, INT2FIX(c));
|
176
|
+
|
177
|
+
/* Get the existing raw triangulation */
|
178
|
+
trArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("delaunay_triangulation_raw"), 0);
|
179
|
+
|
180
|
+
/* Add the new triplet to it */
|
181
|
+
rb_ary_push(trArray, triplet);
|
182
|
+
}
|
183
|
+
|
184
|
+
|
185
|
+
/*** stores a line defined by ax + by = c ***/
|
186
|
+
static void
|
187
|
+
storeLine(const float a, const float b, const float c)
|
188
|
+
{
|
189
|
+
VALUE lArray, line;
|
190
|
+
|
191
|
+
/* Create a new line from the three values */
|
192
|
+
line = rb_ary_new2(4);
|
193
|
+
rb_ary_push(line, ID2SYM(rb_intern("l")));
|
194
|
+
rb_ary_push(line, rb_float_new(a));
|
195
|
+
rb_ary_push(line, rb_float_new(b));
|
196
|
+
rb_ary_push(line, rb_float_new(c));
|
197
|
+
|
198
|
+
/* Get the existing raw voronoi diagram */
|
199
|
+
lArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
|
200
|
+
|
201
|
+
/* Add the new line to it */
|
202
|
+
rb_ary_push(lArray, line);
|
203
|
+
}
|
204
|
+
|
205
|
+
|
206
|
+
/***
|
207
|
+
* Stores a Voronoi segment which is a subsegment of line number l;
|
208
|
+
* with endpoints numbered v1 and v2. If v1 or v2 is -1, the line
|
209
|
+
* extends to infinity.
|
210
|
+
***/
|
211
|
+
static void
|
212
|
+
storeEndpoint(const int l, const int v1, const int v2)
|
213
|
+
{
|
214
|
+
VALUE eArray, endpoint;
|
215
|
+
|
216
|
+
/* Create a new endpoint from the three values */
|
217
|
+
endpoint = rb_ary_new2(4);
|
218
|
+
rb_ary_push(endpoint, ID2SYM(rb_intern("e")));
|
219
|
+
rb_ary_push(endpoint, INT2FIX(l));
|
220
|
+
rb_ary_push(endpoint, INT2FIX(v1));
|
221
|
+
rb_ary_push(endpoint, INT2FIX(v2));
|
222
|
+
|
223
|
+
/* Get the existing raw voronoi diagram */
|
224
|
+
eArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
|
225
|
+
|
226
|
+
/* Add the new endpoint to it */
|
227
|
+
rb_ary_push(eArray, endpoint);
|
228
|
+
}
|
229
|
+
|
230
|
+
|
231
|
+
/*** stores a vertex at (a,b) ***/
|
232
|
+
static void
|
233
|
+
storeVertex(const float a, const float b)
|
234
|
+
{
|
235
|
+
VALUE vArray, vertex;
|
236
|
+
|
237
|
+
/* Create a new vertex from the coordinates */
|
238
|
+
vertex = rb_ary_new2(3);
|
239
|
+
rb_ary_push(vertex, ID2SYM(rb_intern("v")));
|
240
|
+
rb_ary_push(vertex, rb_float_new(a));
|
241
|
+
rb_ary_push(vertex, rb_float_new(b));
|
242
|
+
|
243
|
+
/* Get the existing raw voronoi diagram */
|
244
|
+
vArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
|
245
|
+
|
246
|
+
/* Add the new vertex to it */
|
247
|
+
rb_ary_push(vArray, vertex);
|
248
|
+
}
|
249
|
+
|
250
|
+
|
251
|
+
/***
|
252
|
+
* stores an input site at (x,y)
|
253
|
+
* TODO: redundant?
|
254
|
+
***/
|
255
|
+
static void
|
256
|
+
storeSite(const float x, const float y)
|
257
|
+
{
|
258
|
+
VALUE sArray, site;
|
259
|
+
|
260
|
+
/* Create a new site from the coordinates */
|
261
|
+
site = rb_ary_new2(3);
|
262
|
+
rb_ary_push(site, ID2SYM(rb_intern("s")));
|
263
|
+
rb_ary_push(site, rb_float_new(x));
|
264
|
+
rb_ary_push(site, rb_float_new(y));
|
265
|
+
|
266
|
+
/* Get the existing raw voronoi diagram */
|
267
|
+
sArray = rb_funcall(*(VALUE *)rubyvorState.comp, rb_intern("voronoi_diagram_raw"), 0);
|
268
|
+
|
269
|
+
/* Add the new site to it */
|
270
|
+
rb_ary_push(sArray, site);
|
271
|
+
}
|