Mercurial > octave-nkf
comparison src/DLD-FUNCTIONS/__voronoi__.cc @ 13871:adf60d6dc1dd
more compatibility fixes for __voronoi__
* __voronoi__.cc (F__voronoi__): Use v option for qhull, not Fv.
Improve argument handling. Call qh_findgood_all to obtain number of
Voronoi vertices directly. Correctly size output values. Use
qh_pointid to place cell indices in the same order as the given points.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Wed, 16 Nov 2011 16:17:13 -0500 |
parents | 6d7e133a4bed |
children | 440d7914cf01 |
comparison
equal
deleted
inserted
replaced
13868:87f78c11d725 | 13871:adf60d6dc1dd |
---|---|
74 { | 74 { |
75 print_usage (); | 75 print_usage (); |
76 return retval; | 76 return retval; |
77 } | 77 } |
78 | 78 |
79 std::string options = ""; | 79 std::string cmd = "qhull v"; |
80 | 80 |
81 if (nargin == 2) | 81 if (nargin == 2 && ! args(1).is_empty ()) |
82 { | 82 { |
83 if (args(1).is_string ()) | 83 if (args(1).is_string ()) |
84 options = args(1).string_value (); | 84 cmd += " " + args(1).string_value (); |
85 else if (args(1).is_empty ()) | |
86 ; // Use default options | |
87 else if (args(1).is_cellstr ()) | 85 else if (args(1).is_cellstr ()) |
88 { | 86 { |
89 options = ""; | |
90 Array<std::string> tmp = args(1).cellstr_value (); | 87 Array<std::string> tmp = args(1).cellstr_value (); |
91 | 88 |
92 for (octave_idx_type i = 0; i < tmp.numel (); i++) | 89 for (octave_idx_type i = 0; i < tmp.numel (); i++) |
93 options += tmp(i) + " "; | 90 cmd += " " + tmp(i); |
94 } | 91 } |
95 else | 92 else |
96 { | 93 { |
97 error ("__voronoi__: OPTIONS argument must be a string, cell array of strings, or empty"); | 94 error ("__voronoi__: OPTIONS argument must be a string, cell array of strings, or empty"); |
98 return retval; | 95 return retval; |
99 } | 96 } |
100 } | 97 } |
101 | 98 |
102 Matrix p (args(0).matrix_value ()); | 99 Matrix points (args(0).matrix_value ()); |
103 const octave_idx_type dim = p.columns (); | 100 const octave_idx_type dim = points.columns (); |
104 const octave_idx_type np = p.rows (); | 101 const octave_idx_type num_points = points.rows (); |
105 | 102 |
106 p = p.transpose (); | 103 points = points.transpose (); |
107 double *pt_array = p.fortran_vec (); | |
108 | 104 |
109 boolT ismalloc = false; | 105 boolT ismalloc = false; |
110 | 106 |
111 // Replace the 0 pointer with stdout for debugging information | 107 // Replace the 0 pointer with stdout for debugging information |
112 FILE *outfile = 0; | 108 FILE *outfile = 0; |
113 FILE *errfile = stderr; | 109 FILE *errfile = stderr; |
114 | 110 |
115 // Qhull flags argument is not const char* | 111 // Qhull flags and points arguments are not const... |
116 OCTAVE_LOCAL_BUFFER (char, flags, 12 + options.length ()); | 112 |
117 | 113 OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); |
118 sprintf (flags, "qhull v Fv %s", options.c_str ()); | 114 |
119 | 115 strcpy (cmd_str, cmd.c_str ()); |
120 int exitcode = qh_new_qhull (dim, np, pt_array, | 116 |
121 ismalloc, flags, outfile, errfile); | 117 int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), |
118 ismalloc, cmd_str, outfile, errfile); | |
122 if (! exitcode) | 119 if (! exitcode) |
123 { | 120 { |
121 // Calling findgood_all provides the number of Voronoi vertices | |
122 // (sets qh num_good). | |
123 | |
124 qh_findgood_all (qh facet_list); | |
125 | |
126 octave_idx_type num_voronoi_regions | |
127 = qh num_vertices - qh_setsize (qh del_vertices); | |
128 | |
129 octave_idx_type num_voronoi_vertices = qh num_good; | |
130 | |
131 // Find the voronoi centers for all facets. | |
132 | |
133 qh_setvoronoi_all (); | |
134 | |
124 facetT *facet; | 135 facetT *facet; |
125 vertexT *vertex; | 136 vertexT *vertex; |
126 | 137 octave_idx_type k; |
127 octave_idx_type i = 0, n = 1, k = 0, m = 0, j = 0, r = 0; | 138 |
128 | 139 // Find the number of Voronoi vertices for each Voronoi cell and |
129 // Count number of vertices for size of NI. FIXME -- does Qhull | 140 // store them in NI so we can use them later to set the dimensions |
130 // have a way to query this value directly? | 141 // of the RowVector objects used to collect them. |
131 octave_idx_type nv = 0; | 142 |
132 FORALLvertices | 143 FORALLfacets |
133 { | 144 { |
134 nv++; | 145 facet->seen = false; |
135 } | 146 } |
136 | 147 |
137 OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, nv); | 148 OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions); |
138 | 149 for (octave_idx_type i = 0; i < num_voronoi_regions; i++) |
139 for (i = 0; i < nv; i++) | |
140 ni[i] = 0; | 150 ni[i] = 0; |
141 | 151 |
142 qh_setvoronoi_all (); | 152 k = 0; |
143 | |
144 bool infinity_seen = false; | |
145 facetT *neighbor, **neighborp; | |
146 coordT *voronoi_vertex; | |
147 | |
148 FORALLfacets | |
149 { | |
150 facet->seen = false; | |
151 } | |
152 | 153 |
153 FORALLvertices | 154 FORALLvertices |
154 { | 155 { |
155 if (qh hull_dim == 3) | 156 if (qh hull_dim == 3) |
156 qh_order_vertexneighbors (vertex); | 157 qh_order_vertexneighbors (vertex); |
157 | 158 |
158 infinity_seen = false; | 159 bool infinity_seen = false; |
160 | |
161 facetT *neighbor, **neighborp; | |
159 | 162 |
160 FOREACHneighbor_ (vertex) | 163 FOREACHneighbor_ (vertex) |
161 { | 164 { |
162 if (! neighbor->upperdelaunay) | 165 if (neighbor->upperdelaunay) |
163 { | 166 { |
164 if (! neighbor->seen) | 167 if (! infinity_seen) |
165 { | 168 { |
166 n++; | 169 infinity_seen = true; |
167 neighbor->seen = true; | 170 ni[k]++; |
168 } | 171 } |
169 ni[k]++; | |
170 } | 172 } |
171 else if (! infinity_seen) | 173 else |
172 { | 174 { |
173 infinity_seen = true; | 175 neighbor->seen = true; |
174 ni[k]++; | 176 ni[k]++; |
175 } | 177 } |
176 } | 178 } |
177 | 179 |
178 k++; | 180 k++; |
179 } | 181 } |
180 | 182 |
181 Matrix v (n, dim); | 183 // If Qhull finds fewer regions than points, we will pad the end |
184 // of the at_inf and C arrays so that they always contain at least | |
185 // as many elements as the given points array. | |
186 | |
187 // FIXME -- is it possible (or does it make sense) for | |
188 // num_voronoi_regions to ever be larger than num_points? | |
189 | |
190 octave_idx_type nr = (num_points > num_voronoi_regions | |
191 ? num_points : num_voronoi_regions); | |
192 | |
193 boolMatrix at_inf (nr, 1, false); | |
194 | |
195 // The list of Voronoi vertices. The first element is always | |
196 // Inf. | |
197 Matrix F (num_voronoi_vertices+1, dim); | |
198 | |
182 for (octave_idx_type d = 0; d < dim; d++) | 199 for (octave_idx_type d = 0; d < dim; d++) |
183 v(0,d) = octave_Inf; | 200 F(0,d) = octave_Inf; |
184 | 201 |
185 boolMatrix AtInf (nv, 1, false); | 202 // The cell array of vectors of indices into F that represent the |
186 std::list<RowVector> F; | 203 // vertices of the Voronoi regions (cells). |
204 | |
205 Cell C (nr, 1); | |
206 | |
207 // Now loop through the list of vertices again and store the | |
208 // coordinates of the Voronoi vertices and the lists of indices | |
209 // for the cells. | |
210 | |
211 FORALLfacets | |
212 { | |
213 facet->seen = false; | |
214 } | |
215 | |
216 octave_idx_type i = 0; | |
187 k = 0; | 217 k = 0; |
188 i = 0; | |
189 | |
190 FORALLfacets | |
191 { | |
192 facet->seen = false; | |
193 } | |
194 | 218 |
195 FORALLvertices | 219 FORALLvertices |
196 { | 220 { |
197 if (qh hull_dim == 3) | 221 if (qh hull_dim == 3) |
198 qh_order_vertexneighbors (vertex); | 222 qh_order_vertexneighbors (vertex); |
199 | 223 |
200 infinity_seen = false; | 224 bool infinity_seen = false; |
201 | 225 |
202 octave_idx_type n_vertices = ni[k++]; | 226 octave_idx_type idx = qh_pointid (vertex->point); |
203 | 227 |
204 // Qhull seems to sometimes produce "facets" with a single | 228 octave_idx_type num_vertices = ni[k++]; |
205 // vertex. Is that a bug? How can a facet have just one | 229 |
230 // Qhull seems to sometimes produces regions with a single | |
231 // vertex. Is that a bug? How can a region have just one | |
206 // vertex? Let's skip it. | 232 // vertex? Let's skip it. |
207 | 233 |
208 if (n_vertices == 1) | 234 if (num_vertices == 1) |
209 continue; | 235 continue; |
210 | 236 |
211 RowVector facet_list (n_vertices); | 237 RowVector facet_list (num_vertices); |
212 m = 0; | 238 |
239 octave_idx_type m = 0; | |
240 | |
241 facetT *neighbor, **neighborp; | |
213 | 242 |
214 FOREACHneighbor_(vertex) | 243 FOREACHneighbor_(vertex) |
215 { | 244 { |
216 if (neighbor->upperdelaunay) | 245 if (neighbor->upperdelaunay) |
217 { | 246 { |
218 if (! infinity_seen) | 247 if (! infinity_seen) |
219 { | 248 { |
220 infinity_seen = true; | 249 infinity_seen = true; |
221 facet_list(m++) = 1; | 250 facet_list(m++) = 1; |
222 AtInf(j) = true; | 251 at_inf(idx) = true; |
223 } | 252 } |
224 } | 253 } |
225 else | 254 else |
226 { | 255 { |
227 if (! neighbor->seen) | 256 if (! neighbor->seen) |
228 { | 257 { |
229 voronoi_vertex = neighbor->center; | |
230 i++; | 258 i++; |
231 for (octave_idx_type d = 0; d < dim; d++) | 259 for (octave_idx_type d = 0; d < dim; d++) |
232 { | 260 F(i,d) = neighbor->center[d]; |
233 v(i,d) = *(voronoi_vertex++); | 261 |
234 } | |
235 neighbor->seen = true; | 262 neighbor->seen = true; |
236 neighbor->visitid = i; | 263 neighbor->visitid = i; |
237 } | 264 } |
265 | |
238 facet_list(m++) = neighbor->visitid + 1; | 266 facet_list(m++) = neighbor->visitid + 1; |
239 } | 267 } |
240 } | 268 } |
241 F.push_back (facet_list); | 269 |
242 j++; | 270 C(idx) = facet_list; |
243 } | 271 } |
244 | 272 |
245 // For compatibility with Matlab, pad the cell array of vertex | 273 retval(2) = at_inf; |
246 // lists with empty matrices if there are fewer facets than | |
247 // points. | |
248 octave_idx_type f_len = F.size (); | |
249 Cell C(np > f_len ? np : f_len, 1); | |
250 | |
251 i = 0; | |
252 for (std::list<RowVector>::const_iterator it = F.begin (); | |
253 it != F.end (); it++) | |
254 C.elem (i++) = *it; | |
255 | |
256 F.clear (); | |
257 | |
258 AtInf.resize (f_len, 1); | |
259 retval(2) = AtInf; | |
260 retval(1) = C; | 274 retval(1) = C; |
261 retval(0) = v; | 275 retval(0) = F; |
262 } | 276 } |
263 else | 277 else |
264 error ("__voronoi__: qhull failed"); | 278 error ("__voronoi__: qhull failed"); |
265 | 279 |
266 // free memory from Qhull | 280 // Free memory from Qhull |
267 qh_freeqhull (! qh_ALL); | 281 qh_freeqhull (! qh_ALL); |
268 | 282 |
269 int curlong, totlong; | 283 int curlong, totlong; |
270 qh_memfreeshort (&curlong, &totlong); | 284 qh_memfreeshort (&curlong, &totlong); |
271 | 285 |