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