GNU Octave  8.1.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-2023 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 # include "oct-qhull.h"
61 # if defined (NEED_QHULL_R_VERSION)
62 char qh_version[] = "__voronoi__.oct 2007-07-24";
63 # endif
64 #endif
65 
67 
68 #if defined (HAVE_QHULL)
69 
70 static void
72 {
73  qh_freeqhull (qh, ! qh_ALL);
74 
75  int curlong, totlong;
76  qh_memfreeshort (qh, &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 
111  if (nargin < 2 || nargin > 3)
112  print_usage ();
113 
114  std::string caller = args(0).xstring_value ("__voronoi__: CALLER must be a string");
115 
116  octave_value_list retval;
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 
127  std::string options;
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 
158  // Set the outfile pointer to stdout for status information.
159  FILE *outfile = nullptr;
160  FILE *errfile = stderr;
161 
162  qhT context = { };
163  qhT *qh = &context;
164 
165  std::string cmd = "qhull v" + options;
166 
167  int exitcode = qh_new_qhull (qh, dim, num_points, points.fortran_vec (),
168  ismalloc, &cmd[0], outfile, errfile);
169 
170  unwind_action free_memory ([qh] () { free_qhull_memory (qh); });
171 
172  if (exitcode)
173  error ("%s: qhull failed", caller.c_str ());
174 
175  // Calling findgood_all provides the number of Voronoi vertices
176  // (sets qh->num_good).
177 
178  qh_findgood_all (qh, qh->facet_list);
179 
180  octave_idx_type num_voronoi_regions
181  = qh->num_vertices - qh_setsize (qh, qh->del_vertices);
182 
183  octave_idx_type num_voronoi_vertices = qh->num_good;
184 
185  // Find the voronoi centers for all facets.
186 
187  qh_setvoronoi_all (qh);
188 
189  facetT *facet;
190  vertexT *vertex;
191  octave_idx_type k;
192 
193  // Find the number of Voronoi vertices for each Voronoi cell and
194  // store them in NI so we can use them later to set the dimensions
195  // of the RowVector objects used to collect them.
196 
197  FORALLfacets
198  {
199  facet->seen = false;
200  }
201 
202  OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions);
203  for (octave_idx_type i = 0; i < num_voronoi_regions; i++)
204  ni[i] = 0;
205 
206  k = 0;
207 
208  FORALLvertices
209  {
210  if (qh->hull_dim == 3)
211  qh_order_vertexneighbors (qh, vertex);
212 
213  bool infinity_seen = false;
214 
215  facetT *neighbor, * *neighborp;
216 
217  FOREACHneighbor_ (vertex)
218  {
219  if (neighbor->upperdelaunay)
220  {
221  if (! infinity_seen)
222  {
223  infinity_seen = true;
224  ni[k]++;
225  }
226  }
227  else
228  {
229  neighbor->seen = true;
230  ni[k]++;
231  }
232  }
233 
234  k++;
235  }
236 
237  // If Qhull finds fewer regions than points, we will pad the end
238  // of the at_inf and C arrays so that they always contain at least
239  // as many elements as the given points array.
240 
241  // FIXME: is it possible (or does it make sense) for
242  // num_voronoi_regions to ever be larger than num_points?
243 
244  octave_idx_type nr = (num_points > num_voronoi_regions
245  ? num_points : num_voronoi_regions);
246 
247  boolMatrix at_inf (nr, 1, false);
248 
249  // The list of Voronoi vertices. The first element is always
250  // Inf.
251  Matrix F (num_voronoi_vertices+1, dim);
252 
253  for (octave_idx_type d = 0; d < dim; d++)
254  F(0, d) = numeric_limits<double>::Inf ();
255 
256  // The cell array of vectors of indices into F that represent the
257  // vertices of the Voronoi regions (cells).
258 
259  Cell C (nr, 1);
260 
261  // Now loop through the list of vertices again and store the
262  // coordinates of the Voronoi vertices and the lists of indices
263  // for the cells.
264 
265  FORALLfacets
266  {
267  facet->seen = false;
268  }
269 
270  octave_idx_type i = 0;
271  k = 0;
272 
273  FORALLvertices
274  {
275  if (qh->hull_dim == 3)
276  qh_order_vertexneighbors (qh, vertex);
277 
278  bool infinity_seen = false;
279 
280  octave_idx_type idx = qh_pointid (qh, vertex->point);
281 
282  octave_idx_type num_vertices = ni[k++];
283 
284  // Qhull seems to sometimes produces regions with a single
285  // vertex. Is that a bug? How can a region have just one
286  // vertex? Let's skip it.
287 
288  if (num_vertices == 1)
289  continue;
290 
291  RowVector facet_list (num_vertices);
292 
293  octave_idx_type m = 0;
294 
295  facetT *neighbor, * *neighborp;
296 
297  FOREACHneighbor_(vertex)
298  {
299  if (neighbor->upperdelaunay)
300  {
301  if (! infinity_seen)
302  {
303  infinity_seen = true;
304  facet_list(m++) = 1;
305  at_inf(idx) = true;
306  }
307  }
308  else
309  {
310  if (! neighbor->seen)
311  {
312  i++;
313  for (octave_idx_type d = 0; d < dim; d++)
314  F(i, d) = neighbor->center[d];
315 
316  neighbor->seen = true;
317  neighbor->visitid = i;
318  }
319 
320  facet_list(m++) = neighbor->visitid + 1;
321  }
322  }
323 
324  C(idx) = facet_list;
325  }
326 
327  retval = ovl (F, C, at_inf);
328 
329  return retval;
330 
331 #else
332 
333  octave_unused_parameter (args);
334 
335  std::string caller
336  = (args.length () > 0
337  ? args(0).xstring_value ("__voronoi__: CALLER must be a string")
338  : "__voronoi__");
339 
340  err_disabled_feature (caller, "Qhull");
341 
342 #endif
343 }
344 
345 /*
346 ## No test needed for internal helper function.
347 %!assert (1)
348 */
349 
OCTAVE_END_NAMESPACE(octave)
#define Inf
Definition: Faddeeva.cc:260
#define C(a, b)
Definition: Faddeeva.cc:259
static bool octave_qhull_dims_ok(octave_idx_type dim, octave_idx_type n, const char *who)
Definition: __voronoi__.cc:84
static void free_qhull_memory(qhT *qh)
Definition: __voronoi__.cc:71
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type columns(void) const
Definition: Array.h:471
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:414
OCTARRAY_OVERRIDABLE_FUNC_API octave_idx_type rows(void) const
Definition: Array.h:459
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array-base.cc:1766
Definition: Cell.h:43
Definition: dMatrix.h:42
Matrix transpose(void) const
Definition: dMatrix.h:140
bool iscellstr(void) const
Definition: ov.h:652
bool is_string(void) const
Definition: ov.h:682
std::string string_value(bool force=false) const
Definition: ov.h:1019
bool isempty(void) const
Definition: ov.h:646
Array< std::string > cellstr_value(void) const
Definition: ov.h:1027
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#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-int.h:72
void warning(const char *fmt,...)
Definition: error.cc:1054
void error(const char *fmt,...)
Definition: error.cc:979
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
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211