GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
__delaunayn__.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  16. July 2000 - Kai Habel: first release
28 
29  25. September 2002 - Changes by Rafael Laboissiere <rafael@laboissiere.net>
30 
31  * Added Qbb option to normalize the input and avoid crashes in Octave.
32  * delaunayn accepts now a second (optional) argument that must be a string
33  containing extra options to the qhull command.
34  * Fixed doc string. The dimension of the result matrix is [m, dim+1], and
35  not [n, dim-1].
36 
37  6. June 2006: Changes by Alexander Barth <abarth@marine.usf.edu>
38 
39  * triangulate non-simplicial facets
40  * allow options to be specified as cell array of strings
41  * change the default options (for compatibility with matlab)
42 */
43 
44 #if defined (HAVE_CONFIG_H)
45 # include "config.h"
46 #endif
47 
48 #include <cstdio>
49 
50 #include <limits>
51 #include <string>
52 
53 #include "Array.h"
54 #include "dMatrix.h"
55 #include "dRowVector.h"
56 #include "oct-locbuf.h"
57 #include "unwind-prot.h"
58 
59 #include "defun-dld.h"
60 #include "error.h"
61 #include "errwarn.h"
62 #include "ovl.h"
63 
64 #if defined (HAVE_QHULL)
65 
66 # include "oct-qhull.h"
67 
68 # if defined (NEED_QHULL_VERSION)
69 char qh_version[] = "__delaunayn__.oct 2007-08-21";
70 # endif
71 
72 static void
73 close_fcn (FILE *f)
74 {
75  std::fclose (f);
76 }
77 
78 static void
80 {
81  qh_freeqhull (! qh_ALL);
82 
83  int curlong, totlong;
84  qh_memfreeshort (&curlong, &totlong);
85 
86  if (curlong || totlong)
87  warning ("__delaunayn__: did not free %d bytes of long memory (%d pieces)",
88  totlong, curlong);
89 }
90 
91 static bool
93 {
94  if (sizeof (octave_idx_type) > sizeof (int))
95  {
96  int maxval = std::numeric_limits<int>::max ();
97 
98  if (dim > maxval || n > maxval)
99  error ("%s: dimension too large for Qhull", who);
100  }
101 
102  return true;
103 }
104 
105 #endif
106 
107 DEFUN_DLD (__delaunayn__, args, ,
108  doc: /* -*- texinfo -*-
109 @deftypefn {} {@var{T} =} __delaunayn__ (@var{pts})
110 @deftypefnx {} {@var{T} =} __delaunayn__ (@var{pts}, @var{options})
111 Undocumented internal function.
112 @end deftypefn */)
113 
114 {
115 #if defined (HAVE_QHULL)
116 
117  int nargin = args.length ();
118 
119  if (nargin < 1 || nargin > 2)
120  print_usage ();
121 
123 
124  retval(0) = 0.0;
125 
126  Matrix p (args(0).matrix_value ());
127  const octave_idx_type dim = p.columns ();
128  const octave_idx_type n = p.rows ();
129 
130  if (! octave_qhull_dims_ok (dim, n, "__delaynayn__"))
131  return retval;
132 
133  // Default options
134  std::string options;
135  if (dim <= 3)
136  options = "Qt Qbb Qc";
137  else
138  options = "Qt Qbb Qc Qx";
139 
140  if (nargin == 2)
141  {
142  if (args(1).is_string ())
143  options = args(1).string_value ();
144  else if (args(1).isempty ())
145  ; // Use default options
146  else if (args(1).iscellstr ())
147  {
148  options = "";
149  Array<std::string> tmp = args(1).cellstr_value ();
150 
151  for (octave_idx_type i = 0; i < tmp.numel (); i++)
152  options += tmp(i) + ' ';
153  }
154  else
155  error ("__delaunayn__: OPTIONS argument must be a string, cell array of strings, or empty");
156  }
157 
158  if (n > dim + 1)
159  {
160  p = p.transpose ();
161  double *pt_array = p.fortran_vec ();
162  boolT ismalloc = false;
163 
164  // Qhull flags argument is not const char*
165  OCTAVE_LOCAL_BUFFER (char, flags, 9 + options.length ());
166 
167  sprintf (flags, "qhull d %s", options.c_str ());
168 
170 
171  // Replace the outfile pointer with stdout for debugging information.
172 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM)
173  FILE *outfile = std::fopen ("NUL", "w");
174 #else
175  FILE *outfile = std::fopen ("/dev/null", "w");
176 #endif
177  FILE *errfile = stderr;
178 
179  if (! outfile)
180  error ("__delaunayn__: unable to create temporary file for output");
181 
182  frame.add_fcn (close_fcn, outfile);
183 
184  int exitcode = qh_new_qhull (dim, n, pt_array,
185  ismalloc, flags, outfile, errfile);
186 
187  frame.add_fcn (free_qhull_memory);
188 
189  if (exitcode)
190  error ("__delaunayn__: qhull failed");
191 
192  // triangulate non-simplicial facets
193  qh_triangulate ();
194 
195  facetT *facet;
196  vertexT *vertex, **vertexp;
197  octave_idx_type nf = 0;
198  octave_idx_type i = 0;
199 
200  FORALLfacets
201  {
202  if (! facet->upperdelaunay)
203  nf++;
204 
205  // Double check. Non-simplicial facets will cause segfault below
206  if (! facet->simplicial)
207  error ("__delaunayn__: Qhull returned non-simplicial facets -- try delaunayn with different options");
208  }
209 
210  Matrix simpl (nf, dim+1);
211 
212  FORALLfacets
213  {
214  if (! facet->upperdelaunay)
215  {
216  octave_idx_type j = 0;
217 
218  FOREACHvertex_ (facet->vertices)
219  {
220  simpl(i, j++) = 1 + qh_pointid(vertex->point);
221  }
222  i++;
223  }
224  }
225 
226  retval(0) = simpl;
227  }
228  else if (n == dim + 1)
229  {
230  // FIXME: One should check if nx points span a simplex.
231  // I will look at this later.
232  RowVector vec (n);
233  for (octave_idx_type i = 0; i < n; i++)
234  vec(i) = i + 1.0;
235 
236  retval(0) = vec;
237  }
238 
239  return retval;
240 
241 #else
242 
243  octave_unused_parameter (args);
244 
245  err_disabled_feature ("__delaunayn__", "Qhull");
246 
247 #endif
248 }
249 
250 /*
251 ## No test needed for internal helper function.
252 %!assert (1)
253 */
static void close_fcn(FILE *f)
static bool octave_qhull_dims_ok(octave_idx_type dim, octave_idx_type n, const char *who)
static void free_qhull_memory()
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: dMatrix.h:42
Matrix transpose(void) const
Definition: dMatrix.h:135
void add_fcn(void(*fcn)(Params...), Args &&... args)
#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 * f
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