3Copyright (C) 2000, 2007, 2008, 2009 Kai Habel
5This file is part of Octave.
7Octave is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by the
9Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
12Octave is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17You should have received a copy of the GNU General Public License
18along with Octave; see the file COPYING. If not, see
19<http://www.gnu.org/licenses/>.
2429. July 2000 - Kai Habel: first release
252002-04-22 Paul Kienzle
26* Use warning(...) function rather than writing to cerr
28* add support for consistent winding in all dimensions; output is
29* guaranteed to be simplicial.
45#if defined(HAVE__SNPRINTF) && !defined(HAVE_SNPRINTF)
46#define snprintf _snprintf
50#include <qhull/qhull_a.h>
53#ifdef NEED_QHULL_VERSION
54char qh_version[] = "convhulln.oct 2007-07-24";
58DEFUN_DLD (convhulln, args, nargout,
60@deftypefn {Loadable Function} {@var{h} =} convhulln (@var{p})\n\
61@deftypefnx {Loadable Function} {@var{h} =} convhulln (@var{p}, @var{opt})\n\
62@deftypefnx {Loadable Function} {[@var{h}, @var{v}] =} convhulln (@dots{})\n\
63Return an index vector to the points of the enclosing convex hull.\n\
64The input matrix of size [n, dim] contains n points of dimension dim.\n\n\
65If a second optional argument is given, it must be a string or cell array\n\
66of strings containing options for the underlying qhull command. (See\n\
67the Qhull documentation for the available options.) The default options\n\
69If the second output @var{V} is requested the volume of the convex hull is\n\
71@seealso{convhull, delaunayn}\n\
74 octave_value_list retval;
79 int nargin = args.length ();
80 if (nargin < 1 || nargin > 2)
88 if (args (1).is_string ())
89 options = args(1).string_value ();
90 else if (args(1).is_cell ())
92 Cell c = args(1).cell_value ();
94 for (octave_idx_type i = 0; i < c.numel (); i++)
96 if (! c.elem(i).is_string ())
98 error ("convhulln: second argument must be a string or cell array of strings");
102 options = options + c.elem(i).string_value() + " ";
107 error ("convhulln: second argument must be a string or cell array of strings");
112 // turn on some consistency checks
113 options = "s Qci Tcv";
115 Matrix p (args(0).matrix_value ());
117 const octave_idx_type dim = p.columns ();
118 const octave_idx_type n = p.rows ();
121 double *pt_array = p.fortran_vec ();
123 boolT ismalloc = False;
125 OCTAVE_LOCAL_BUFFER (char, flags, 250);
127 // hmm, lots of options for qhull here
128 // QJ guarantees that the output will be triangles
129 snprintf (flags, 250, "qhull QJ %s", options.c_str ());
131 if (! qh_new_qhull (dim, n, pt_array, ismalloc, flags, 0, stderr))
133 // If you want some debugging information replace the NULL
134 // pointer with stdout
136 vertexT *vertex, **vertexp;
139 unsigned int nf = qh num_facets;
141 Matrix idx (nf, dim);
143 octave_idx_type j, i = 0;
147 if (! facet->simplicial)
148 // should never happen with QJ
149 error ("convhulln: non-simplicial facet");
153 vertices = qh_facet3vertex (facet);
154 FOREACHvertex_ (vertices)
155 idx(i, j++) = 1 + qh_pointid(vertex->point);
156 qh_settempfree (&vertices);
160 if (facet->toporient ^ qh_ORIENTclock)
162 FOREACHvertex_ (facet->vertices)
163 idx(i, j++) = 1 + qh_pointid(vertex->point);
167 FOREACHvertexreverse12_ (facet->vertices)
168 idx(i, j++) = 1 + qh_pointid(vertex->point);
172 // likewise but less fatal
173 warning ("facet %d only has %d vertices", i, j);
178 // calculate volume of convex hull
179 // taken from qhull src/geom2.c
189 if (facet->upperdelaunay && qh ATinfinity)
192 facet->f.area = area = qh_facetarea (facet);
193 facet->isarea = True;
197 if (facet->upperdelaunay == qh UPPERdelaunay)
203 qh_distplane (qh interior_point, facet, &dist);
204 qh totvol += -dist * area/ qh hull_dim;
208 retval(1) = octave_value (qh totvol);
211 retval(0) = octave_value (idx);
215 qh_freeqhull (! qh_ALL);
217 // free short memory and memory allocator
218 int curlong, totlong;
219 qh_memfreeshort (&curlong, &totlong);
221 if (curlong || totlong)
222 warning ("convhulln: did not free %d bytes of long memory (%d pieces)",
225 error ("convhulln: not available in this version of Octave");
233%! cube = [0 0 0;1 0 0;1 1 0;0 1 0;0 0 1;1 0 1;1 1 1;0 1 1];
234%! [h, v] = convhulln(cube,'Pp');
235%! assert (v, 1.0, 1e6*eps);
237%! tetrahedron = [1 1 1;-1 -1 1;-1 1 -1;1 -1 -1];
238%! [h, v] = convhulln(tetrahedron,'Pp');
239%! assert (v, 8/3, 1e6*eps);