view src/DLD-FUNCTIONS/__voronoi__.cc @ 13862:6d7e133a4bed

compatibility fixes for __voronoi__ * __voronoi__.cc (F__voronoi__): Use Fv option for Qhull, not FV. Delete unused variable fidx. Count vertices to get size of NI array. Skip facets that contain only one point. Always return AtInf. Use a list of accumulate vertex lists. Pad the cell array of facet vertex lists with empty matrices if there are fewer facets than points.
author John W. Eaton <jwe@octave.org>
date Mon, 14 Nov 2011 04:14:04 -0500
parents 7ff0bdc3dc4c
children adf60d6dc1dd
line wrap: on
line source

/*

Copyright (C) 2000-2011 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"

#ifdef HAVE_QHULL
extern "C" {
#include <qhull/qhull_a.h>
}

#ifdef NEED_QHULL_VERSION
char qh_version[] = "__voronoi__.oct 2007-07-24";
#endif
#endif

DEFUN_DLD (__voronoi__, args, ,
        "-*- texinfo -*-\n\
@deftypefn  {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@var{pts})\n\
@deftypefnx {Loadable Function} {@var{C}, @var{F} =} __voronoi__ (@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;

#ifdef HAVE_QHULL

  retval(0) = 0.0;

  int nargin = args.length ();
  if (nargin < 1 || nargin > 2)
    {
      print_usage ();
      return retval;
    }

  std::string options = "";

  if (nargin == 2)
    {
      if (args(1).is_string ())
        options = args(1).string_value ();
      else if (args(1).is_empty ())
        ;  // Use default options
      else if (args(1).is_cellstr ())
        {
          options = "";
          Array<std::string> tmp = args(1).cellstr_value ();

          for (octave_idx_type i = 0; i < tmp.numel (); i++)
            options += tmp(i) + " ";
        }
      else
        {
          error ("__voronoi__: OPTIONS argument must be a string, cell array of strings, or empty");
          return retval;
        }
    }

  Matrix p (args(0).matrix_value ());
  const octave_idx_type dim = p.columns ();
  const octave_idx_type np = p.rows ();

  p = p.transpose ();
  double *pt_array = p.fortran_vec ();

  boolT ismalloc = false;

  // Replace the 0 pointer with stdout for debugging information
  FILE *outfile = 0;
  FILE *errfile = stderr;

  // Qhull flags argument is not const char*
  OCTAVE_LOCAL_BUFFER (char, flags, 12 + options.length ());

  sprintf (flags, "qhull v Fv %s", options.c_str ());

  int exitcode = qh_new_qhull (dim, np, pt_array, 
                               ismalloc, flags, outfile, errfile);
  if (! exitcode) 
    {
      facetT *facet;
      vertexT *vertex;

      octave_idx_type i = 0, n = 1, k = 0, m = 0, j = 0, r = 0;

      // Count number of vertices for size of NI.  FIXME -- does Qhull
      // have a way to query this value directly?
      octave_idx_type nv = 0;
      FORALLvertices
        {
          nv++;
        }

      OCTAVE_LOCAL_BUFFER (octave_idx_type, ni, nv);

      for (i = 0; i < nv; i++)
        ni[i] = 0;

      qh_setvoronoi_all ();

      bool infinity_seen = false;
      facetT *neighbor, **neighborp;
      coordT *voronoi_vertex;

      FORALLfacets
        {
          facet->seen = false;
        }

      FORALLvertices
        {
          if (qh hull_dim == 3)
            qh_order_vertexneighbors (vertex);
          
          infinity_seen = false;

          FOREACHneighbor_ (vertex)
            {
              if (! neighbor->upperdelaunay)
                {
                  if (! neighbor->seen)
                    {
                      n++;
                      neighbor->seen = true;
                    }
                  ni[k]++;
                }
              else if (! infinity_seen)
                {
                  infinity_seen = true;
                  ni[k]++;
                }
            }

          k++;
        }

      Matrix v (n, dim);
      for (octave_idx_type d = 0; d < dim; d++)
        v(0,d) = octave_Inf;

      boolMatrix AtInf (nv, 1, false);
      std::list<RowVector> F;
      k = 0;
      i = 0;

      FORALLfacets
        {
          facet->seen = false;
        }

      FORALLvertices
        {
          if (qh hull_dim == 3)
            qh_order_vertexneighbors (vertex);

          infinity_seen = false;

          octave_idx_type n_vertices = ni[k++];

          // Qhull seems to sometimes produce "facets" with a single
          // vertex.  Is that a bug?  How can a facet have just one
          // vertex?  Let's skip it.

          if (n_vertices == 1)
            continue;

          RowVector facet_list (n_vertices);
          m = 0;

          FOREACHneighbor_(vertex)
            {
              if (neighbor->upperdelaunay)
                {
                  if (! infinity_seen)
                    {
                      infinity_seen = true;
                      facet_list(m++) = 1;
                      AtInf(j) = true;
                    }
                }
              else
                {
                  if (! neighbor->seen)
                    {
                      voronoi_vertex = neighbor->center;
                      i++;
                      for (octave_idx_type d = 0; d < dim; d++)
                        {
                          v(i,d) = *(voronoi_vertex++);
                        }
                      neighbor->seen = true;
                      neighbor->visitid = i;
                    }
                  facet_list(m++) = neighbor->visitid + 1;
                }
            }
          F.push_back (facet_list);
          j++;
        }

      // For compatibility with Matlab, pad the cell array of vertex
      // lists with empty matrices if there are fewer facets than
      // points.
      octave_idx_type f_len = F.size ();
      Cell C(np > f_len ? np : f_len, 1);

      i = 0;
      for (std::list<RowVector>::const_iterator it = F.begin ();
           it != F.end (); it++)
        C.elem (i++) = *it;

      F.clear ();

      AtInf.resize (f_len, 1);
      retval(2) = AtInf;
      retval(1) = C;
      retval(0) = v;
    }
  else
    error ("__voronoi__: qhull failed");

  // free memory from Qhull
  qh_freeqhull (! qh_ALL);

  int curlong, totlong;
  qh_memfreeshort (&curlong, &totlong);

  if (curlong || totlong)
    warning ("__voronoi__: did not free %d bytes of long memory (%d pieces)",
             totlong, curlong);

#else
  error ("__voronoi__: not available in this version of Octave");
#endif

  return retval;
}

/*

## No test needed for internal helper function.
%!assert (1)

*/