GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
__voronoi__.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2000-2018 Kai Habel
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 /*
24 20. Augiust 2000 - Kai Habel: first release
25 */
26 
27 /*
28 2003-12-14 Rafael Laboissiere <rafael@laboissiere.net>
29 Added optional second argument to pass options to the underlying
30 qhull command
31 */
32 
33 #if defined (HAVE_CONFIG_H)
34 # include "config.h"
35 #endif
36 
37 #include <cstdio>
38 
39 #include <limits>
40 #include <string>
41 
42 #include "Array.h"
43 #include "boolMatrix.h"
44 #include "dMatrix.h"
45 #include "dRowVector.h"
46 #include "oct-locbuf.h"
47 #include "unwind-prot.h"
48 
49 #include "Cell.h"
50 #include "defun-dld.h"
51 #include "error.h"
52 #include "errwarn.h"
53 #include "ov.h"
54 #include "ovl.h"
55 
56 #if defined (HAVE_QHULL)
57 
58 # include "oct-qhull.h"
59 
60 # if defined (NEED_QHULL_VERSION)
61 char qh_version[] = "__voronoi__.oct 2007-07-24";
62 # endif
63 
64 static void
65 close_fcn (FILE *f)
66 {
67  std::fclose (f);
68 }
69 
70 static void
72 {
73  qh_freeqhull (! qh_ALL);
74 
75  int curlong, totlong;
76  qh_memfreeshort (&curlong, &totlong);
77 
78  if (curlong || totlong)
79  warning ("__voronoi__: did not free %d bytes of long memory (%d pieces)",
80  totlong, curlong);
81 }
82 
83 static bool
85 {
86  if (sizeof (octave_idx_type) > sizeof (int))
87  {
88  int maxval = std::numeric_limits<int>::max ();
89 
90  if (dim > maxval || n > maxval)
91  error ("%s: dimension too large for Qhull", who);
92  }
93 
94  return true;
95 }
96 
97 #endif
98 
99 DEFUN_DLD (__voronoi__, args, ,
100  doc: /* -*- texinfo -*-
101 @deftypefn {} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts})
102 @deftypefnx {} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts}, @var{options})
103 @deftypefnx {} {@var{C}, @var{F}, @var{Inf_Pts} =} __voronoi__ (@dots{})
104 Undocumented internal function.
105 @end deftypefn */)
106 {
107 #if defined (HAVE_QHULL)
108 
109  int nargin = args.length ();
110 
112  print_usage ();
113 
114  std::string caller = args(0).xstring_value ("__voronoi__: CALLER must be a string");
115 
117 
118  Matrix points = args(1).matrix_value ();
119  const octave_idx_type dim = points.columns ();
120  const octave_idx_type num_points = points.rows ();
121 
122  if (! octave_qhull_dims_ok (dim, num_points, "__voronoi__"))
123  return ovl (0.0);
124 
125  points = points.transpose ();
126 
128 
129  if (dim <= 3)
130  options = " Qbb";
131  else
132  options = " Qbb Qx";
133 
134  if (nargin == 3)
135  {
136  octave_value opt_arg = args(2);
137 
138  if (opt_arg.is_string ())
139  options = ' ' + opt_arg.string_value ();
140  else if (opt_arg.isempty ())
141  ; // Use default options.
142  else if (opt_arg.iscellstr ())
143  {
144  options = "";
145 
146  Array<std::string> tmp = opt_arg.cellstr_value ();
147 
148  for (octave_idx_type i = 0; i < tmp.numel (); i++)
149  options += ' ' + tmp(i);
150  }
151  else
152  error ("%s: OPTIONS must be a string, cell array of strings, or empty",
153  caller.c_str ());
154  }
155 
156  boolT ismalloc = false;
157 
159 
160  // Replace the outfile pointer with stdout for debugging information.
161 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
162  FILE *outfile = std::fopen ("NUL", "w");
163 #else
164  FILE *outfile = std::fopen ("/dev/null", "w");
165 #endif
166  FILE *errfile = stderr;
167 
168  if (! outfile)
169  error ("__voronoi__: unable to create temporary file for output");
170 
171  frame.add_fcn (close_fcn, outfile);
172 
173  // qh_new_qhull command and points arguments are not const...
174 
175  std::string cmd = "qhull v" + options;
176 
177  OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1);
178 
179  strcpy (cmd_str, cmd.c_str ());
180 
181  int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (),
182  ismalloc, cmd_str, outfile, errfile);
183 
185 
186  if (exitcode)
187  error ("%s: qhull failed", caller.c_str ());
188 
189  // Calling findgood_all provides the number of Voronoi vertices
190  // (sets qh num_good).
191 
192  qh_findgood_all (qh facet_list);
193 
194  octave_idx_type num_voronoi_regions
195  = qh num_vertices - qh_setsize (qh del_vertices);
196 
197  octave_idx_type num_voronoi_vertices = qh num_good;
198 
199  // Find the voronoi centers for all facets.
200 
201  qh_setvoronoi_all ();
202 
203  facetT *facet;
204  vertexT *vertex;
206 
207  // Find the number of Voronoi vertices for each Voronoi cell and
208  // store them in NI so we can use them later to set the dimensions
209  // of the RowVector objects used to collect them.
210 
211  FORALLfacets
212  {
213  facet->seen = false;
214  }
215 
216  OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions);
217  for (octave_idx_type i = 0; i < num_voronoi_regions; i++)
218  ni[i] = 0;
219 
220  k = 0;
221 
222  FORALLvertices
223  {
224  if (qh hull_dim == 3)
225  qh_order_vertexneighbors (vertex);
226 
227  bool infinity_seen = false;
228 
229  facetT *neighbor, **neighborp;
230 
231  FOREACHneighbor_ (vertex)
232  {
233  if (neighbor->upperdelaunay)
234  {
235  if (! infinity_seen)
236  {
237  infinity_seen = true;
238  ni[k]++;
239  }
240  }
241  else
242  {
243  neighbor->seen = true;
244  ni[k]++;
245  }
246  }
247 
248  k++;
249  }
250 
251  // If Qhull finds fewer regions than points, we will pad the end
252  // of the at_inf and C arrays so that they always contain at least
253  // as many elements as the given points array.
254 
255  // FIXME: is it possible (or does it make sense) for
256  // num_voronoi_regions to ever be larger than num_points?
257 
258  octave_idx_type nr = (num_points > num_voronoi_regions
259  ? num_points : num_voronoi_regions);
260 
261  boolMatrix at_inf (nr, 1, false);
262 
263  // The list of Voronoi vertices. The first element is always
264  // Inf.
265  Matrix F (num_voronoi_vertices+1, dim);
266 
267  for (octave_idx_type d = 0; d < dim; d++)
269 
270  // The cell array of vectors of indices into F that represent the
271  // vertices of the Voronoi regions (cells).
272 
273  Cell C (nr, 1);
274 
275  // Now loop through the list of vertices again and store the
276  // coordinates of the Voronoi vertices and the lists of indices
277  // for the cells.
278 
279  FORALLfacets
280  {
281  facet->seen = false;
282  }
283 
284  octave_idx_type i = 0;
285  k = 0;
286 
287  FORALLvertices
288  {
289  if (qh hull_dim == 3)
290  qh_order_vertexneighbors (vertex);
291 
292  bool infinity_seen = false;
293 
294  octave_idx_type idx = qh_pointid (vertex->point);
295 
296  octave_idx_type num_vertices = ni[k++];
297 
298  // Qhull seems to sometimes produces regions with a single
299  // vertex. Is that a bug? How can a region have just one
300  // vertex? Let's skip it.
301 
302  if (num_vertices == 1)
303  continue;
304 
305  RowVector facet_list (num_vertices);
306 
307  octave_idx_type m = 0;
308 
309  facetT *neighbor, **neighborp;
310 
311  FOREACHneighbor_(vertex)
312  {
313  if (neighbor->upperdelaunay)
314  {
315  if (! infinity_seen)
316  {
317  infinity_seen = true;
318  facet_list(m++) = 1;
319  at_inf(idx) = true;
320  }
321  }
322  else
323  {
324  if (! neighbor->seen)
325  {
326  i++;
327  for (octave_idx_type d = 0; d < dim; d++)
328  F(i,d) = neighbor->center[d];
329 
330  neighbor->seen = true;
331  neighbor->visitid = i;
332  }
333 
334  facet_list(m++) = neighbor->visitid + 1;
335  }
336  }
337 
338  C(idx) = facet_list;
339  }
340 
341  retval = ovl (F, C, at_inf);
342 
343  return retval;
344 
345 #else
346 
347  octave_unused_parameter (args);
348 
349  std::string caller
350  = (args.length () > 0
351  ? args(0).xstring_value ("__voronoi__: CALLER must be a string")
352  : "__voronoi__");
353 
354  err_disabled_feature (caller, "Qhull");
355 
356 #endif
357 }
358 
359 /*
360 ## No test needed for internal helper function.
361 %!assert (1)
362 */
octave_idx_type rows(void) const
Definition: Array.h:404
Definition: Cell.h:37
#define C(a, b)
Definition: Faddeeva.cc:246
std::string string_value(bool force=false) const
Definition: ov.h:955
bool isempty(void) const
Definition: ov.h:529
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE * f
static bool octave_qhull_dims_ok(octave_idx_type dim, octave_idx_type n, const char *who)
Definition: __voronoi__.cc:84
for large enough k
Definition: lu.cc:617
const T * fortran_vec(void) const
Definition: Array.h:584
void add_fcn(void(*fcn)(void))
void error(const char *fmt,...)
Definition: error.cc:578
octave_idx_type columns(void) const
Definition: Array.h:413
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
bool iscellstr(void) const
Definition: ov.h:543
Matrix transpose(void) const
Definition: dMatrix.h:132
OCTAVE_EXPORT octave_value_list or both For fclose
Definition: file-io.cc:676
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
void warning(const char *fmt,...)
Definition: error.cc:801
octave::unwind_protect frame
Definition: graphics.cc:12190
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
#define Inf
Definition: Faddeeva.cc:247
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).isinteger())
static void close_fcn(FILE *f)
Definition: __voronoi__.cc:65
OCTAVE_EXPORT octave_value_list only variables visible in the local scope are displayed The following are valid options
Definition: variables.cc:1862
static void free_qhull_memory()
Definition: __voronoi__.cc:71
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
args.length() nargin
Definition: file-io.cc:589
for i
Definition: data.cc:5264
bool is_string(void) const
Definition: ov.h:577
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition: defun-dld.h:58
Array< std::string > cellstr_value(void) const
Definition: ov.h:967
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:756