bribera-rubyvor 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest.txt CHANGED
@@ -10,12 +10,12 @@ ext/heap.c
10
10
  ext/memory.c
11
11
  ext/output.c
12
12
  ext/rb_cComputation.c
13
+ ext/rb_cPoint.c
13
14
  ext/rb_cPriorityQueue.c
14
15
  ext/ruby_vor.c
15
16
  ext/ruby_vor.h
16
17
  ext/vdefs.h
17
18
  ext/voronoi.c
18
- ext/voronoi_interface.c
19
19
  lib/ruby_vor.rb
20
20
  lib/ruby_vor/computation.rb
21
21
  lib/ruby_vor/point.rb
data/Rakefile CHANGED
@@ -7,8 +7,7 @@ require './lib/ruby_vor/version.rb'
7
7
  EXT = "ext/voronoi_interface.#{Hoe::DLEXT}"
8
8
 
9
9
  Hoe.new('rubyvor', RubyVor::VERSION) do |p|
10
- p.developer('Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com')
11
-
10
+ p.developer('Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com')
12
11
  p.url = 'http://github.com/bribera/rubyvor'
13
12
 
14
13
  # C extension goodness
data/ext/output.c CHANGED
@@ -1,24 +1,17 @@
1
1
 
2
2
  /*** OUTPUT.C ***/
3
3
 
4
-
4
+ #include <vdefs.h>
5
5
  #include <stdio.h>
6
-
7
- #include "vdefs.h"
6
+ #include <unistd.h>
8
7
 
9
8
  VoronoiState rubyvorState;
10
9
 
11
10
  static float pxmin, pxmax, pymin, pymax, cradius;
12
11
 
13
12
  void openpl(void) {}
14
-
15
- #pragma argsused
16
13
  void line(float ax, float ay, float bx, float by) {}
17
-
18
- #pragma argsused
19
14
  void circle(float ax, float ay, float radius) {}
20
-
21
- #pragma argsused
22
15
  void range(float pxmin, float pxmax, float pymin, float pymax) {}
23
16
 
24
17
  void
@@ -8,18 +8,16 @@ static Site * nextone(void);
8
8
  static int scomp(const void *, const void *);
9
9
 
10
10
  //
11
- // Class methods for RubyVor::VDDT::Computation
11
+ // See ruby_vor.c for RDOC
12
12
  //
13
13
 
14
14
 
15
- /*
16
- * Compute the voronoi diagram and delaunay triangulation from a set of points.
17
- *
18
- * This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
19
- * It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
20
- */
15
+ //
16
+ // Class methods for RubyVor::VDDT::Computation
17
+ //
18
+
21
19
  VALUE
22
- from_points(VALUE self, VALUE pointsArray)
20
+ RubyVor_from_points(VALUE self, VALUE pointsArray)
23
21
  {
24
22
  //VALUE returnValue;
25
23
  VALUE * inPtr, newComp;
@@ -121,16 +119,17 @@ from_points(VALUE self, VALUE pointsArray)
121
119
 
122
120
 
123
121
  //
124
- // Instance methods (none)
122
+ // Instance methods
125
123
  //
126
124
 
125
+ /*
127
126
  VALUE
128
- minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
127
+ RubyVor_minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
129
128
  {
130
129
  VALUE dist_proc, nodes, nnGraph, points, queue, tmpHash, tmpArray, adjList, latestAddition;
131
130
  long i, j;
132
131
 
133
- /* 0 mandatory, 1 optional */
132
+ // 0 mandatory, 1 optional
134
133
  rb_scan_args(argc, argv, "01", &dist_proc);
135
134
 
136
135
  if (NIL_P(dist_proc)) {
@@ -144,7 +143,7 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
144
143
  points = rb_iv_get(self, "@points");
145
144
  nodes = rb_ary_new2(RARRAY(points)->len);
146
145
  queue = rb_eval_string("RubyVor::PriorityQueue.new(lambda{|a,b| a[:min_distance] < b[:min_distance]})");
147
- nnGraph = nn_graph(self);
146
+ nnGraph = RubyVor_nn_graph(self);
148
147
 
149
148
  for (i=0; i < RARRAY(points)->len; i++) {
150
149
  tmpHash = rb_hash_new();
@@ -155,7 +154,7 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
155
154
  rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_distance")), (i == 0) ? INT2FIX(0) : rb_const_get(rb_cFloat, rb_intern("MAX")));
156
155
  // :parent => nil,
157
156
  rb_hash_aset(tmpHash, ID2SYM(rb_intern("parent")), Qnil);
158
- // :adjacency_list => nn_graph[n].clone,
157
+ // :adjacency_list => RubyVor_nn_graph[n].clone,
159
158
  rb_hash_aset(tmpHash, ID2SYM(rb_intern("adjacency_list")), rb_funcall(RARRAY(nnGraph)->ptr[i], rb_intern("clone"), 0));
160
159
  // :min_adjacency_list => [],
161
160
  rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_adjacency_list")), rb_ary_new());
@@ -185,13 +184,14 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
185
184
 
186
185
  return tmpArray;
187
186
  }
187
+ */
188
188
 
189
189
  VALUE
190
- nn_graph(VALUE self)
190
+ RubyVor_nn_graph(VALUE self)
191
191
  {
192
192
  long i;
193
193
  VALUE dtRaw, graph, points, * dtPtr, * tripletPtr, * graphPtr;
194
- ID has_key;
194
+
195
195
  graph = rb_iv_get(self, "@nn_graph");
196
196
 
197
197
  if (RTEST(graph))
data/ext/rb_cPoint.c ADDED
@@ -0,0 +1,14 @@
1
+ #include <ruby.h>
2
+ #include <vdefs.h>
3
+ #include <ruby_vor.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
+ }
@@ -2,37 +2,47 @@
2
2
  #include <vdefs.h>
3
3
  #include <ruby_vor.h>
4
4
 
5
- VALUE
5
+ //
6
+ // Instance methods for RubyVor::VDDT::PriorityQueue
7
+ //
8
+
9
+
10
+ static VALUE
6
11
  compare(VALUE a, VALUE b)
7
12
  {
8
13
  double aD, bD;
9
14
  ID minDistance;
10
15
  minDistance = ID2SYM(rb_intern("min_distance"));
11
16
 
12
- if (rb_class_of(a) == rb_cQueueItem)
17
+ if (rb_class_of(a) == RubyVor_rb_cQueueItem)
13
18
  aD = NUM2DBL(rb_funcall(a, rb_intern("priority"), 0));
14
19
  else
15
- aD = NUM2DBL(a);
20
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(a), rb_class2name(RubyVor_rb_cQueueItem));
16
21
 
17
- if (rb_class_of(b) == rb_cQueueItem)
22
+ if (rb_class_of(b) == RubyVor_rb_cQueueItem)
18
23
  bD = NUM2DBL(rb_funcall(b, rb_intern("priority"), 0));
19
24
  else
20
- bD = NUM2DBL(b);
25
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(b), rb_class2name(RubyVor_rb_cQueueItem));
21
26
 
22
27
  return RTEST(aD < bD);
23
28
  }
24
29
 
25
30
  VALUE
26
- percolate_up(VALUE self, VALUE index)
31
+ RubyVor_percolate_up(VALUE self, VALUE index)
27
32
  {
28
33
  VALUE item, data;
29
- long i, j;
34
+ long i, j, size;
35
+
36
+ Check_Type(index, T_FIXNUM);
30
37
 
31
38
  data = rb_iv_get(self, "@data");
32
39
  Check_Type(data, T_ARRAY);
33
40
 
34
- i = FIX2INT(index);
41
+ size = FIX2INT(rb_iv_get(self, "@size"));
42
+ i = FIX2INT(index) + 1;
35
43
 
44
+ if (i < 1 || i > size)
45
+ rb_raise(rb_eIndexError, "index %i out of range", i-1);
36
46
 
37
47
  j = i / 2;
38
48
 
@@ -41,30 +51,34 @@ percolate_up(VALUE self, VALUE index)
41
51
  while(j > 0 && compare(item, RARRAY(data)->ptr[j - 1]))
42
52
  {
43
53
  rb_ary_store(data, i-1, RARRAY(data)->ptr[j - 1]);
44
- rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
54
+ rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
45
55
  i = j;
46
56
  j = j / 2;
47
57
  }
48
58
 
49
59
  rb_ary_store(data, i-1, item);
50
- rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
60
+ rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
51
61
 
52
62
  return Qnil;
53
63
  }
54
64
 
55
65
 
56
66
  VALUE
57
- percolate_down(VALUE self, VALUE index)
67
+ RubyVor_percolate_down(VALUE self, VALUE index)
58
68
  {
59
69
  VALUE item, data;
60
70
  long i, j, k, size;
61
71
 
72
+ Check_Type(index, T_FIXNUM);
73
+
62
74
  data = rb_iv_get(self, "@data");
63
75
  Check_Type(data, T_ARRAY);
64
76
 
65
77
  size = FIX2INT(rb_iv_get(self, "@size"));
66
- i = FIX2INT(index);
78
+ i = FIX2INT(index) + 1;
67
79
 
80
+ if (i < 1 || i > size)
81
+ rb_raise(rb_eIndexError, "index %i out of range", i-1);
68
82
 
69
83
  j = size / 2;
70
84
 
@@ -81,26 +95,26 @@ percolate_down(VALUE self, VALUE index)
81
95
  else
82
96
  {
83
97
  rb_ary_store(data, i-1, RARRAY(data)->ptr[k - 1]);
84
- rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
98
+ rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
85
99
  i = k;
86
100
  }
87
101
  }
88
102
 
89
103
  rb_ary_store(data, i-1, item);
90
- rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
104
+ rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
91
105
 
92
106
  return Qnil;
93
107
  }
94
108
 
95
109
 
96
110
  VALUE
97
- heapify(VALUE self)
111
+ RubyVor_heapify(VALUE self)
98
112
  {
99
113
  long i, size;
100
114
  size = FIX2INT(rb_iv_get(self, "@size"));
101
115
 
102
116
  for(i = size / 2; i >= 1; i--)
103
- percolate_down(self, INT2FIX(i));
117
+ RubyVor_percolate_down(self, INT2FIX(i-1));
104
118
 
105
119
  return Qnil;
106
120
  }
data/ext/ruby_vor.c CHANGED
@@ -2,6 +2,9 @@
2
2
  #include <vdefs.h>
3
3
  #include <ruby_vor.h>
4
4
 
5
+ //
6
+ // Extension initialization
7
+ //
5
8
  void
6
9
  Init_ruby_vor(void)
7
10
  {
@@ -12,30 +15,82 @@ Init_ruby_vor(void)
12
15
  /*
13
16
  * Main RubyVor namespace.
14
17
  */
15
- rb_mRubyVor = rb_define_module("RubyVor");
18
+ RubyVor_rb_mRubyVor = rb_define_module("RubyVor");
16
19
 
17
20
 
18
21
  /*
19
22
  * Voronoi Digram and Delaunay Triangulation namespace.
20
23
  */
21
- rb_mVDDT = rb_define_module_under(rb_mRubyVor, "VDDT");
24
+ RubyVor_rb_mVDDT = rb_define_module_under(RubyVor_rb_mRubyVor, "VDDT");
22
25
 
23
26
 
24
27
  /*
25
28
  * Class representing a VD/DT computation based on a set of 2-dimensional points
26
29
  */
27
- rb_cComputation = rb_define_class_under(rb_mVDDT, "Computation", rb_cObject);
28
- rb_define_singleton_method(rb_cComputation, "from_points", from_points, 1);
29
- rb_define_method(rb_cComputation, "nn_graph", nn_graph, 0);
30
- //rb_define_method(rb_cComputation, "minimum_spanning_tree", minimum_spanning_tree, -1);
30
+ RubyVor_rb_cComputation = rb_define_class_under(RubyVor_rb_mVDDT, "Computation", rb_cObject);
31
+ rb_define_singleton_method(RubyVor_rb_cComputation, "from_points", RubyVor_from_points, 1);
32
+ rb_define_method(RubyVor_rb_cComputation, "nn_graph", RubyVor_nn_graph, 0);
33
+ // rb_define_method(RubyVor_rb_cComputation, "minimum_spanning_tree", RubyVor_minimum_spanning_tree, -1);
31
34
 
32
35
 
33
36
  /*
34
37
  * A priority queue with a customizable heap-order property.
35
38
  */
36
- rb_cPriorityQueue = rb_define_class_under(rb_mRubyVor, "PriorityQueue", rb_cObject);
37
- rb_cQueueItem = rb_define_class_under(rb_cPriorityQueue, "QueueItem", rb_cObject);
38
- rb_define_method(rb_cPriorityQueue, "percolate_up", percolate_up, 1);
39
- rb_define_method(rb_cPriorityQueue, "percolate_down", percolate_down, 1);
40
- rb_define_method(rb_cPriorityQueue, "heapify", heapify, 0);
39
+ RubyVor_rb_cPriorityQueue = rb_define_class_under(RubyVor_rb_mRubyVor, "PriorityQueue", rb_cObject);
40
+ RubyVor_rb_cQueueItem = rb_define_class_under(RubyVor_rb_cPriorityQueue, "QueueItem", rb_cObject);
41
+ rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_up", RubyVor_percolate_up, 1);
42
+ rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_down", RubyVor_percolate_down, 1);
43
+ rb_define_method(RubyVor_rb_cPriorityQueue, "heapify", RubyVor_heapify, 0);
44
+
45
+
46
+ /*
47
+ * A simple Point class
48
+ */
49
+ RubyVor_rb_cPoint = rb_define_class_under(RubyVor_rb_mRubyVor, "Point", rb_cObject);
50
+ rb_define_method(RubyVor_rb_cPoint, "distance_from", RubyVor_distance_from, 1);
41
51
  }
52
+
53
+
54
+
55
+
56
+ //
57
+ // Method declarations duplicated here for RDOC
58
+ //
59
+
60
+ /*
61
+ * Compute the voronoi diagram and delaunay triangulation from a set of points.
62
+ *
63
+ * This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
64
+ * It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
65
+ */
66
+ VALUE RubyVor_from_points(VALUE, VALUE);
67
+
68
+ /*
69
+ * Compute the nearest-neighbor graph using the existing Delaunay triangulation.
70
+ */
71
+ VALUE RubyVor_nn_graph(VALUE);
72
+
73
+ /*
74
+ * Compute the MST for the nearest-nearest graph using a Priority Queue and Prim's algorithm.
75
+ */
76
+ // VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
77
+
78
+ /*
79
+ * Move from the given index up, restoring the heap-order property.
80
+ */
81
+ VALUE RubyVor_percolate_up(VALUE, VALUE);
82
+
83
+ /*
84
+ * Move from the index down, restoring the heap-order property.
85
+ */
86
+ VALUE RubyVor_percolate_down(VALUE, VALUE);
87
+
88
+ /*
89
+ * Restore the heap-order property for a randomly ordered array of entries.
90
+ */
91
+ VALUE RubyVor_heapify(VALUE);
92
+
93
+ /*
94
+ * Compute the Euclidean distance between two points.
95
+ */
96
+ VALUE RubyVor_distance_from(VALUE, VALUE);
data/ext/ruby_vor.h CHANGED
@@ -4,20 +4,24 @@
4
4
  extern VoronoiState rubyvorState;
5
5
 
6
6
  /* Base modules */
7
- VALUE rb_mRubyVor;
8
- VALUE rb_mVDDT;
7
+ VALUE RubyVor_rb_mRubyVor;
8
+ VALUE RubyVor_rb_mVDDT;
9
9
 
10
10
  /* Computation */
11
- VALUE rb_cComputation;
12
- VALUE from_points(VALUE, VALUE);
13
- VALUE nn_graph(VALUE);
14
- VALUE minimum_spanning_tree(int, VALUE*, VALUE);
11
+ VALUE RubyVor_rb_cComputation;
12
+ VALUE RubyVor_from_points(VALUE, VALUE);
13
+ VALUE RubyVor_nn_graph(VALUE);
14
+ // VALUE minimum_spanning_tree(int, VALUE*, VALUE);
15
15
 
16
16
  /* PriorityQueue */
17
- VALUE rb_cPriorityQueue;
18
- VALUE rb_cQueueItem;
19
- VALUE percolate_up(VALUE, VALUE);
20
- VALUE percolate_down(VALUE, VALUE);
21
- VALUE heapify(VALUE);
17
+ VALUE RubyVor_rb_cPriorityQueue;
18
+ VALUE RubyVor_rb_cQueueItem;
19
+ VALUE RubyVor_percolate_up(VALUE, VALUE);
20
+ VALUE RubyVor_percolate_down(VALUE, VALUE);
21
+ VALUE RubyVor_heapify(VALUE);
22
+
23
+ /* Point */
24
+ VALUE RubyVor_rb_cPoint;
25
+ VALUE RubyVor_distance_from(VALUE, VALUE);
22
26
 
23
27
  #endif
@@ -20,15 +20,14 @@ module RubyVor
20
20
 
21
21
  clusters = []
22
22
  nodes = (0..points.length-1).to_a
23
- visited = []
24
-
23
+ visited = [false] * points.length
24
+ graph = []
25
25
  v = 0
26
- graph = nn_graph.map do |neighbors|
27
- neighbors = neighbors.reject do |neighbor|
28
- dist_proc[points[v], points[neighbor]] > max_distance
26
+
27
+ nn_graph.each_with_index do |neighbors,v|
28
+ graph[v] = neighbors.select do |neighbor|
29
+ dist_proc[points[v], points[neighbor]] < max_distance
29
30
  end
30
- v += 1
31
- neighbors
32
31
  end
33
32
 
34
33
  until nodes.empty?
@@ -63,37 +62,49 @@ module RubyVor
63
62
  nodes = []
64
63
  q = RubyVor::PriorityQueue.new
65
64
  (0..points.length-1).to_a.map do |n|
66
- q.push({
67
- :node => n,
68
- :parent => nil,
69
- :adjacency_list => nn_graph[n].clone,
70
- :min_adjacency_list => [],
71
- :in_q => true
72
- }, (n == 0) ? 0.0 : Float::MAX)
73
- end
74
-
75
- q.data.each do |n|
76
- n.data[:adjacency_list].map!{|v| q.data[v]}
77
- nodes.push(n)
65
+ q.push([
66
+ n, # :node == 0
67
+ nil, # :parent == 1
68
+ nn_graph[n].clone, # :adjacency_list == 2
69
+ [], # :min_adjacency_list == 3
70
+ true # :in_q == 4
71
+ ],
72
+ # Set min_distance of first node to 0, all others (effectively) to Infinity.
73
+ (n == 0) ? 0.0 : Float::MAX)
78
74
  end
79
75
 
80
- while latest_addition = q.pop
81
- latest_addition.data[:in_q] = false
76
+ # Adjacency list accces
77
+ nodes = q.data.clone
78
+
79
+ # We have now prepped to run through Prim's algorithm.
80
+ while latest_addition = q.pop
81
+ # check :in_q
82
+ latest_addition.data[4] = false
82
83
 
83
- if latest_addition.data[:parent]
84
- latest_addition.data[:parent].data[:min_adjacency_list].push(latest_addition)
85
- latest_addition.data[:min_adjacency_list].push(latest_addition.data[:parent])
84
+ # check :parent
85
+ if latest_addition.data[1]
86
+ # push this node into :adjacency_list of :parent
87
+ latest_addition.data[1].data[3].push(latest_addition)
88
+ # push :parent into :adjacency_list of this node
89
+ latest_addition.data[3].push(latest_addition.data[1])
86
90
  end
87
91
 
88
- latest_addition.data[:adjacency_list].each do |adjacent|
89
-
90
- if adjacent.data[:in_q]
92
+ latest_addition.data[2].each do |adjacent|
93
+ # grab indexed node
94
+ adjacent = nodes[adjacent]
91
95
 
92
- adjacent_distance = dist_proc[ points[latest_addition.data[:node]], points[adjacent.data[:node]] ]
93
-
96
+ # check :in_q -- only look at new nodes
97
+ if adjacent.data[4]
98
+ # compare points by :node -- adjacent against current
99
+ adjacent_distance = dist_proc[ points[latest_addition.data[0]], points[adjacent.data[0]] ]
100
+
101
+ # if the new distance is better than our current priorty, exchange them
94
102
  if adjacent_distance < adjacent.priority
95
- adjacent.data[:parent] = latest_addition
103
+ # set new :parent
104
+ adjacent.data[1] = latest_addition
105
+ # update priority
96
106
  adjacent.priority = adjacent_distance
107
+ # percolate up into correct position
97
108
  q.percolate_up(adjacent.index)
98
109
  end
99
110
  end
@@ -103,15 +114,19 @@ module RubyVor
103
114
 
104
115
 
105
116
  nodes.map! do |n|
106
- n.data[:min_adjacency_list].map!{|v| v.data[:node]}
117
+ n.data[3].inject({}) do |h,v|
118
+ h[v.data[0]] = v.priority
119
+ h
120
+ end
107
121
  end
108
122
  end
109
123
 
110
124
  def cluster_by_size(sizes=[])
111
125
  # TODO
112
- # * Create a minimum_spanning_tree routine to:
113
- # 1. compute weights (should be done for us in C?)
114
- # 2. Use Prim's algorithm for computation
126
+ # * (DONE) Create a minimum_spanning_tree routine to:
127
+ # 1. (DONE) compute weights (should be done for us in C?)
128
+ # 2. (DONE) Use Prim's algorithm for computation
129
+ #
115
130
  # * Take MST, and
116
131
  # 1. For n in sizes (taken in descending order), delete the n most expensive edges from MST
117
132
  # * use a MaxHeap?
@@ -1,13 +1,8 @@
1
1
  module RubyVor
2
- # Basic 2-d point
3
2
  class Point
4
3
  attr_accessor :x, :y
5
4
  def initialize(x=0.0,y=0.0)
6
5
  @x = x; @y = y
7
6
  end
8
-
9
- def distance_from(p)
10
- ((self.x - p.x) ** 2 + (self.y - p.y) ** 2) ** 0.5
11
- end
12
7
  end
13
8
  end
@@ -3,10 +3,9 @@ module RubyVor
3
3
 
4
4
  attr_reader :data, :size
5
5
 
6
- def initialize(d=[])
7
- @data = d || []
8
- @size = d.length
9
-
6
+ def initialize()
7
+ @data = []
8
+ @size = 0
10
9
  heapify()
11
10
  end
12
11
 
@@ -20,20 +19,20 @@ module RubyVor
20
19
  r = @data[0]
21
20
 
22
21
  @data[0] = @data[@size-1]
23
- @data[0].index = 1
22
+ @data[0].index = 0
24
23
  @data.delete_at(@size-1)
25
24
 
26
25
  @size -= 1
27
26
 
28
- percolate_down(1) if @size > 0
27
+ percolate_down(0) if @size > 0
29
28
 
30
29
  return r
31
30
  end
32
31
 
33
- def push(data, priority=Float::MAX)
32
+ def push(data, priority=data)
34
33
  @size += 1
35
34
  @data[@size - 1] = QueueItem.new(priority, @size - 1, data)
36
- percolate_up(@size)
35
+ percolate_up(@size - 1)
37
36
  end
38
37
 
39
38
  # Implemented in C
@@ -1,3 +1,3 @@
1
1
  module RubyVor
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
data/rubyvor.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{rubyvor}
5
- s.version = "0.0.4"
5
+ s.version = "0.0.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Brendan Ribera"]
9
- s.date = %q{2008-12-10}
9
+ s.date = %q{2008-12-11}
10
10
  s.description = %q{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.}
11
11
  s.email = ["brendan.ribera+rubyvor@gmail.com"]
12
12
  s.extensions = ["ext/extconf.rb"]
13
13
  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
14
- s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/rb_cComputation.c", "ext/rb_cPriorityQueue.c", "ext/ruby_vor.c", "ext/ruby_vor.h", "ext/vdefs.h", "ext/voronoi.c", "ext/voronoi_interface.c", "lib/ruby_vor.rb", "lib/ruby_vor/computation.rb", "lib/ruby_vor/point.rb", "lib/ruby_vor/priority_queue.rb", "lib/ruby_vor/version.rb", "rubyvor.gemspec", "test/test_computation.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb"]
14
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/rb_cComputation.c", "ext/rb_cPoint.c", "ext/rb_cPriorityQueue.c", "ext/ruby_vor.c", "ext/ruby_vor.h", "ext/vdefs.h", "ext/voronoi.c", "lib/ruby_vor.rb", "lib/ruby_vor/computation.rb", "lib/ruby_vor/point.rb", "lib/ruby_vor/priority_queue.rb", "lib/ruby_vor/version.rb", "rubyvor.gemspec", "test/test_computation.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb"]
15
15
  s.has_rdoc = true
16
16
  s.homepage = %q{http://github.com/bribera/rubyvor}
17
17
  s.rdoc_options = ["--main", "README.txt"]
@@ -53,9 +53,11 @@ class TestComputation < MiniTest::Unit::TestCase
53
53
  [0,2],
54
54
  [1]
55
55
  ]
56
+ computed_mst = comp.minimum_spanning_tree
56
57
 
58
+ # Assert nodes are correct
57
59
  assert_equal expected_mst.map{|v| v.sort}.sort, \
58
- comp.minimum_spanning_tree.map{|v| v.sort}.sort
60
+ computed_mst.map{|v| v.keys.sort}.sort
59
61
  end
60
62
 
61
63
  def test_advanced_mst
@@ -119,8 +121,10 @@ class TestComputation < MiniTest::Unit::TestCase
119
121
  [22,24], # 23
120
122
  [23] # 24
121
123
  ]
124
+ computed_mst = comp.minimum_spanning_tree
125
+
122
126
  assert_equal expected_mst.map{|v| v.sort}.sort, \
123
- comp.minimum_spanning_tree.map{|v| v.sort}.sort
127
+ computed_mst.map{|v| v.keys.sort}.sort
124
128
  end
125
129
 
126
130
  def test_cluster_by_distance
@@ -146,6 +150,29 @@ class TestComputation < MiniTest::Unit::TestCase
146
150
 
147
151
  end
148
152
 
153
+ def test_bad_data
154
+ assert_raises TypeError do
155
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,:s)])
156
+ end
157
+
158
+ assert_raises TypeError do
159
+ comp = RubyVor::VDDT::Computation.from_points(RubyVor::Point.new(21,3))
160
+ end
161
+
162
+ assert_raises RuntimeError do
163
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), nil])
164
+ end
165
+
166
+ assert_raises RuntimeError do
167
+ comp = RubyVor::VDDT::Computation.from_points([])
168
+ end
169
+
170
+ comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,1.5)])
171
+ assert_raises ArgumentError do
172
+ cl = comp.cluster_by_distance(nil)
173
+ end
174
+ end
175
+
149
176
  #
150
177
  # A few helper methods
151
178
  #
@@ -9,7 +9,7 @@ class TestPriorityQueue < MiniTest::Unit::TestCase
9
9
  q = RubyVor::PriorityQueue.new
10
10
 
11
11
  items = [1,2,3,4,5,6,99,4,-20,101,5412,2,-1,-1,-1,33.0,0,55,7,12321,123.123,-123.123,0,0,0]
12
- items.each{|i| q.push(i,i)}
12
+ items.each{|i| q.push(i)}
13
13
 
14
14
  items.sort!
15
15
  idx = 0
@@ -31,26 +31,83 @@ class TestPriorityQueue < MiniTest::Unit::TestCase
31
31
  def test_heapify
32
32
  q = RubyVor::PriorityQueue.new
33
33
 
34
- ([10] * 10).each{|x| q.push(x,x)}
34
+ # Create a randomized data set.
35
+ #
36
+ # Not ideal for unit tests, since they *should* be done
37
+ # on static data so that failure/success is deterministic...
38
+ # but works for me.
35
39
 
36
- q.data[3] = RubyVor::PriorityQueue::QueueItem.new(-34, 3, -34)
37
- q.data[4] = RubyVor::PriorityQueue::QueueItem.new(1, 4, 1)
38
- q.data[5] = RubyVor::PriorityQueue::QueueItem.new(100, 5, 100)
39
- q.data[7] = RubyVor::PriorityQueue::QueueItem.new(0.9, 7, 0.9)
40
- q.data.sort!{|a,b| rand(3)-1}
41
-
40
+ 100.times{ q.push(rand * 10000.0 - 5000.0)}
41
+
42
+ # Set things right.
42
43
  q.heapify()
43
44
 
44
- assert_equal(-34, q.pop.data)
45
- assert_equal 0.9, q.pop.data
46
- assert_equal 1, q.pop.data
47
- assert_equal 10, q.pop.data
48
- assert_equal 10, q.pop.data
49
- assert_equal 10, q.pop.data
50
- assert_equal 10, q.pop.data
51
- assert_equal 10, q.pop.data
52
- assert_equal 10, q.pop.data
53
- assert_equal 100, q.pop.data
45
+ old_n = -1.0 * Float::MAX
46
+ while n = q.pop
47
+ assert n.priority >= old_n
48
+ old_n = n.priority
49
+ end
54
50
  end
51
+
52
+ def test_bad_data
53
+ q = RubyVor::PriorityQueue.new
54
+ 10.times { q.push(rand * 100.0 - 50.0) }
55
55
 
56
+ #
57
+ # Heapify
58
+ #
59
+ old_data = q.data[1]
60
+ q.data[1] = 45
61
+ assert_raises TypeError do
62
+ q.heapify()
63
+ end
64
+ q.data[1] = old_data
65
+ assert_nothing_raised do
66
+ q.heapify()
67
+ end
68
+
69
+
70
+ #
71
+ # Percolation
72
+ #
73
+ [100, -100].each do |i|
74
+ assert_raises IndexError do
75
+ q.percolate_up(i)
76
+ end
77
+ assert_raises IndexError do
78
+ q.percolate_down(i)
79
+ end
80
+ end
81
+ [:x, Class, nil, false].each do |i|
82
+ assert_raises TypeError do
83
+ q.percolate_up(i)
84
+ end
85
+ assert_raises TypeError do
86
+ q.percolate_down(i)
87
+ end
88
+ end
89
+ [0,1,2,3].each do |i|
90
+ assert_nothing_raised do
91
+ q.percolate_up(i)
92
+ end
93
+ assert_nothing_raised do
94
+ q.percolate_down(i)
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ private
101
+
102
+ def assert_nothing_raised(&b)
103
+ begin
104
+ yield
105
+ rescue Exception => e
106
+ flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
107
+ return
108
+ end
109
+ pass()
110
+ end
56
111
  end
112
+
113
+ MiniTest::Unit.autorun
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bribera-rubyvor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brendan Ribera
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-10 00:00:00 -08:00
12
+ date: 2008-12-11 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -45,12 +45,12 @@ files:
45
45
  - ext/memory.c
46
46
  - ext/output.c
47
47
  - ext/rb_cComputation.c
48
+ - ext/rb_cPoint.c
48
49
  - ext/rb_cPriorityQueue.c
49
50
  - ext/ruby_vor.c
50
51
  - ext/ruby_vor.h
51
52
  - ext/vdefs.h
52
53
  - ext/voronoi.c
53
- - ext/voronoi_interface.c
54
54
  - lib/ruby_vor.rb
55
55
  - lib/ruby_vor/computation.rb
56
56
  - lib/ruby_vor/point.rb