Mercurial > octave-nkf
diff libinterp/dldfcn/__voronoi__.cc @ 15195:2fc554ffbc28
split libinterp from src
* libinterp: New directory. Move all files from src directory here
except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc,
mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh.
* libinterp/Makefile.am: New file, extracted from src/Makefile.am.
* src/Makefile.am: Delete everything except targets and definitions
needed to build and link main and utility programs.
* Makefile.am (SUBDIRS): Include libinterp in the list.
* autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not
src/dldfcn directory.
* configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not
src/octave.cc.
(DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src.
(AC_CONFIG_FILES): Include libinterp/Makefile in the list.
* find-docstring-files.sh: Look in libinterp, not src.
* gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in
libinterp, not src.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 18 Aug 2012 16:23:39 -0400 |
parents | src/dldfcn/__voronoi__.cc@000587f92082 |
children | dda043ccad7c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/dldfcn/__voronoi__.cc Sat Aug 18 16:23:39 2012 -0400 @@ -0,0 +1,334 @@ +/* + +Copyright (C) 2000-2012 Kai Habel + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +/* +20. Augiust 2000 - Kai Habel: first release +*/ + +/* +2003-12-14 Rafael Laboissiere <rafael@laboissiere.net> +Added optional second argument to pass options to the underlying +qhull command +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdio> + +#include <list> + +#include "lo-ieee.h" + +#include "Cell.h" +#include "defun-dld.h" +#include "error.h" +#include "oct-obj.h" +#include "unwind-prot.h" + +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) +char qh_version[] = "__voronoi__.oct 2007-07-24"; +# endif +#endif + +static void +close_fcn (FILE *f) +{ + gnulib::fclose (f); +} + +DEFUN_DLD (__voronoi__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts})\n\ +@deftypefnx {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{caller}, @var{pts}, @var{options})\n\ +@deftypefnx {Loadable Function} {@var{C}, @var{F}, @var{Inf_Pts} =} __voronoi__ (@dots{})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value_list retval; + + std::string caller = args(0).string_value (); + +#if defined (HAVE_QHULL) + + retval(0) = 0.0; + + int nargin = args.length (); + if (nargin < 2 || nargin > 3) + { + print_usage (); + return retval; + } + + Matrix points = args(1).matrix_value (); + const octave_idx_type dim = points.columns (); + const octave_idx_type num_points = points.rows (); + + points = points.transpose (); + + std::string options; + + if (dim <= 4) + options = " Qbb"; + else + options = " Qbb Qx"; + + if (nargin == 3) + { + octave_value opt_arg = args(2); + + if (opt_arg.is_string ()) + options = " " + opt_arg.string_value (); + else if (opt_arg.is_empty ()) + ; // Use default options. + else if (opt_arg.is_cellstr ()) + { + options = ""; + + Array<std::string> tmp = opt_arg.cellstr_value (); + + for (octave_idx_type i = 0; i < tmp.numel (); i++) + options += " " + tmp(i); + } + else + { + error ("%s: OPTIONS must be a string, cell array of strings, or empty", + caller.c_str ()); + return retval; + } + } + + boolT ismalloc = false; + + unwind_protect frame; + + // Replace the outfile pointer with stdout for debugging information. +#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM) + FILE *outfile = gnulib::fopen ("NUL", "w"); +#else + FILE *outfile = gnulib::fopen ("/dev/null", "w"); +#endif + FILE *errfile = stderr; + + if (outfile) + frame.add_fcn (close_fcn, outfile); + else + { + error ("__voronoi__: unable to create temporary file for output"); + return retval; + } + + // qh_new_qhull command and points arguments are not const... + + std::string cmd = "qhull v" + options; + + OCTAVE_LOCAL_BUFFER (char, cmd_str, cmd.length () + 1); + + strcpy (cmd_str, cmd.c_str ()); + + int exitcode = qh_new_qhull (dim, num_points, points.fortran_vec (), + ismalloc, cmd_str, outfile, errfile); + if (! exitcode) + { + // Calling findgood_all provides the number of Voronoi vertices + // (sets qh num_good). + + qh_findgood_all (qh facet_list); + + octave_idx_type num_voronoi_regions + = qh num_vertices - qh_setsize (qh del_vertices); + + octave_idx_type num_voronoi_vertices = qh num_good; + + // Find the voronoi centers for all facets. + + qh_setvoronoi_all (); + + facetT *facet; + vertexT *vertex; + octave_idx_type k; + + // Find the number of Voronoi vertices for each Voronoi cell and + // store them in NI so we can use them later to set the dimensions + // of the RowVector objects used to collect them. + + FORALLfacets + { + facet->seen = false; + } + + OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, num_voronoi_regions); + for (octave_idx_type i = 0; i < num_voronoi_regions; i++) + ni[i] = 0; + + k = 0; + + FORALLvertices + { + if (qh hull_dim == 3) + qh_order_vertexneighbors (vertex); + + bool infinity_seen = false; + + facetT *neighbor, **neighborp; + + FOREACHneighbor_ (vertex) + { + if (neighbor->upperdelaunay) + { + if (! infinity_seen) + { + infinity_seen = true; + ni[k]++; + } + } + else + { + neighbor->seen = true; + ni[k]++; + } + } + + k++; + } + + // If Qhull finds fewer regions than points, we will pad the end + // of the at_inf and C arrays so that they always contain at least + // as many elements as the given points array. + + // FIXME -- is it possible (or does it make sense) for + // num_voronoi_regions to ever be larger than num_points? + + octave_idx_type nr = (num_points > num_voronoi_regions + ? num_points : num_voronoi_regions); + + boolMatrix at_inf (nr, 1, false); + + // The list of Voronoi vertices. The first element is always + // Inf. + Matrix F (num_voronoi_vertices+1, dim); + + for (octave_idx_type d = 0; d < dim; d++) + F(0,d) = octave_Inf; + + // The cell array of vectors of indices into F that represent the + // vertices of the Voronoi regions (cells). + + Cell C (nr, 1); + + // Now loop through the list of vertices again and store the + // coordinates of the Voronoi vertices and the lists of indices + // for the cells. + + FORALLfacets + { + facet->seen = false; + } + + octave_idx_type i = 0; + k = 0; + + FORALLvertices + { + if (qh hull_dim == 3) + qh_order_vertexneighbors (vertex); + + bool infinity_seen = false; + + octave_idx_type idx = qh_pointid (vertex->point); + + octave_idx_type num_vertices = ni[k++]; + + // Qhull seems to sometimes produces regions with a single + // vertex. Is that a bug? How can a region have just one + // vertex? Let's skip it. + + if (num_vertices == 1) + continue; + + RowVector facet_list (num_vertices); + + octave_idx_type m = 0; + + facetT *neighbor, **neighborp; + + FOREACHneighbor_(vertex) + { + if (neighbor->upperdelaunay) + { + if (! infinity_seen) + { + infinity_seen = true; + facet_list(m++) = 1; + at_inf(idx) = true; + } + } + else + { + if (! neighbor->seen) + { + i++; + for (octave_idx_type d = 0; d < dim; d++) + F(i,d) = neighbor->center[d]; + + neighbor->seen = true; + neighbor->visitid = i; + } + + facet_list(m++) = neighbor->visitid + 1; + } + } + + C(idx) = facet_list; + } + + retval(2) = at_inf; + retval(1) = C; + retval(0) = F; + } + else + error ("%s: qhull failed", caller.c_str ()); + + // Free memory from Qhull + qh_freeqhull (! qh_ALL); + + int curlong, totlong; + qh_memfreeshort (&curlong, &totlong); + + if (curlong || totlong) + warning ("%s: qhull did not free %d bytes of long memory (%d pieces)", + caller.c_str (), totlong, curlong); + +#else + error ("%s: not available in this version of Octave", caller.c_str ()); +#endif + + return retval; +} + +/* +## No test needed for internal helper function. +%!assert (1) +*/