/* Copyright (C) 2000  Kai Habel
**
** This program 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 2 of the License, or
** (at your option) any later version.
**
** This program 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 this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
*/

/*
16. July 2000 - Kai Habel: first release

25. September 2002 - Changes by Rafael Laboissiere <rafael@laboissiere.net>

 * Added Qbb option to normalize the input and avoid crashes in Octave.
 * delaunayn accepts now a second (optional) argument that must be a string
   containing extra options to the qhull command.
 * Fixed doc string.  The dimension of the result matrix is [m, dim+1], and
   not [n, dim-1].
*/

#include "config.h"

extern "C" {
  #include "qhull/qhull_a.h"
}

#include <iostream>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <octave/oct.h>

#ifdef NEED_QHULL_VERSION
char qh_version[] = "delaunayn.oct 2003-12-14";
#endif
FILE *outfile = stdout;
FILE *errfile = stderr;
char flags[250];
const char *options;

DEFUN_DLD (delaunayn, args, ,
        "-*- texinfo -*-\n\
@deftypefn {Loadable Function} {@var{T}=} delaunayn (@var{P}[, @var{opt}])\n\
Form the Delaunay triangulation for a set of points.\n\
The Delaunay trianugulation is a tessellation of the convex hull of the\n\
points such that no n-sphere defined by the n-triangles contains\n\
any other points from the set.\n\n\
The input matrix of size [n, dim] contains n points of dimension dim.\n\
The return matrix @var{T} has the size [m, dim+1]. It contains for\n\
each row a set of indices to the points, which describes a simplex of\n\
dimension dim.  The 3d simplex is a tetrahedron.\n\n\
If a second optional argument is given, it must be a string containing\n\
extra options for the underlying qhull command.  In particular, \"Qt\"\n\
may be useful for joggling the input to cope with non-simplicial cases.\n\
(See the Qhull documentation for the available options.) @end deftypefn")

{
  octave_value_list retval;
  retval(0) = 0.0;

  int nargin = args.length();
  if (nargin < 1 || nargin > 2) {
    print_usage ("delaunayn(p,[opt])");
    return retval;
  }

  if (nargin == 2) {
    if ( ! args (1).is_string () ) {
      error ("delaunayn: second argument must be a string");
      return retval;
    }
    options = args (1).string_value().c_str();
  }
  else
    options = "";

  Matrix p(args(0).matrix_value());

  const int dim = p.columns();
  const int n = p.rows();

  if (n > dim) {

    p = p.transpose();
    double *pt_array = p.fortran_vec();
    boolT ismalloc = False;

    sprintf(flags,"qhull d Qbb T0 %s",options);
    if (!qh_new_qhull (dim, n, pt_array, ismalloc, flags, NULL, errfile)) {

      /*If you want some debugging information replace the NULL
      pointer with outfile.
      */

      facetT *facet;
      vertexT *vertex, **vertexp;
      int nf=0,i=0;

      FORALLfacets {
        if (!facet->upperdelaunay) nf++;
      }

      Matrix simpl(nf,dim+1);
      FORALLfacets {
        if (!facet->upperdelaunay) {
          int j=0;
          FOREACHvertex_ (facet->vertices) {
            simpl(i,j++)=1 + qh_pointid(vertex->point);
          }
          i++;
        }
      }
      retval(0) = simpl;
    }
    qh_freeqhull(!qh_ALL);
      //free long memory

    int curlong, totlong;
    qh_memfreeshort (&curlong, &totlong);
      //free short memory and memory allocator

    if (curlong || totlong) {
	warning("delaunay: did not free %d bytes of long memory (%d pieces)",
	        totlong, curlong);
    }
  } else if (n == dim + 1) {
    // one should check if nx points span a simplex
    // I will look at this later.
    RowVector vec(n);
    for (int i=0;i<n;i++) {
      vec(i)=i+1.0;
    }
    retval(0) = vec;
  }
  return retval;
}


syntax highlighted by Code2HTML, v. 0.9.1