/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 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 Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef SOFATETGEN_MeshTetrahedrizationEngine_H
#define SOFATETGEN_MeshTetrahedrizationEngine_H


#include "SofaTetGen/config.h"

#include "tetgen/tetgen.h"

#include <sofa/helper/rmath.h>
#include <sofa/helper/OptionsGroup.h>
#include <sofa/core/DataEngine.h>

#include <sofa/core/topology/BaseMeshTopology.h>

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <iostream>
#include <fstream>


//#define MeshTetrahedrizationEngine_VERBOSE              true
//#define MeshTetrahedrizationEngine_DISPLAY_CONSTAINTS   false
//#define d_display_result.getValue()       false


#define SOFATETGEN_MeshTetrahedrizationEngine_TERMINAL_DISPLAY    false

#if SOFATETGEN_MeshTetrahedrizationEngine_TERMINAL_DISPLAY
  #define OUT   std::cout
  #define ENDL  std::endl
#else
  #define OUT   sout
  #define ENDL  sendl
#endif

namespace sofa
{
namespace component
{
namespace engine
{

/**
    This Engine computes a tetrahedrization on an input triangular mesh
*/
template <typename DataTypes>
class SOFA_SofaTetGen_API MeshTetrahedrizationEngine : public core::DataEngine
{

public:
    typedef core::DataEngine Inherited;
    SOFA_CLASS(SOFA_TEMPLATE(MeshTetrahedrizationEngine, DataTypes) , Inherited);

    typedef typename DataTypes::Real Real;
    typedef typename DataTypes::Coord Coord;
    typedef typename DataTypes::VecCoord VecCoord;

    // TODO use typedefs from topology
    typedef uint Idx;
//    typedef typename sofa::helper::fixed_array<Idx, 3> Triangle;
    typedef typename core::topology::BaseMeshTopology::Triangle Triangle;
    typedef typename sofa::helper::vector<Triangle> TriangleList;
//    typedef typename sofa::helper::fixed_array<Idx, 4> Tetra;
    typedef typename core::topology::BaseMeshTopology::Tetra Tetra;
    typedef typename sofa::helper::vector<Tetra> TetraList;


    Data<VecCoord> d_inputPosition;
    Data<TriangleList> d_inputTriangles;
    Data<VecCoord> d_inputConstrainedPoint;

    Data<VecCoord> d_outputPosition;
    Data<TetraList> d_outputTetra;

    virtual std::string getTemplateName() const    { return templateName(this); }
    static std::string templateName(const MeshTetrahedrizationEngine<DataTypes>* = NULL) { return DataTypes::Name(); }

    Data<bool> d_verbose;
    Data<bool> d_display_constaints;
    Data<bool> d_display_result;

      // Switches of TetGen.
      Data<bool> d_tg_plc;                                                         // '-p', 0.
      Data<bool> d_tg_psc;                                                         // '-s', 0.
      Data<bool> d_tg_refine;                                                      // '-r', 0.
      Data<bool> d_tg_quality;                                                     // '-q', 0.
      Data<bool> d_tg_nobisect;                                                    // '-Y', 0.
      Data<bool> d_tg_coarsen;                                                     // '-R', 0.
      Data<bool> d_tg_weighted;                                                    // '-w', 0.
      Data<bool> d_tg_brio_hilbert;                                                // '-b', 1.
      Data<bool> d_tg_incrflip;                                                    // '-l', 0.
      Data<bool> d_tg_flipinsert;                                                  // '-L', 0.
      Data<bool> d_tg_metric;                                                      // '-m', 0.
      Data<bool> d_tg_varvolume;                                                   // '-a', 0.
      Data<bool> d_tg_fixedvolume;                                                 // '-a', 0.
      Data<bool> d_tg_regionattrib;                                                // '-A', 0.
      Data<bool> d_tg_conforming;                                                  // '-D', 0.
      Data<bool> d_tg_insertaddpoints;                                             // '-i', 0.
      Data<bool> d_tg_diagnose;                                                    // '-d', 0.
      Data<bool> d_tg_convex;                                                      // '-c', 0.
      Data<bool> d_tg_nomergefacet;                                                // '-M', 0.
      Data<bool> d_tg_nomergevertex;                                               // '-M', 0.
      Data<bool> d_tg_noexact;                                                     // '-X', 0.
      Data<bool> d_tg_nostaticfilter;                                              // '-X', 0.
      Data<bool> d_tg_zeroindex;                                                   // '-z', 0.
      Data<bool> d_tg_facesout;                                                    // '-f', 0.
      Data<bool> d_tg_edgesout;                                                    // '-e', 0.
      Data<bool> d_tg_neighout;                                                    // '-n', 0.
      Data<bool> d_tg_voroout;                                                     // '-v', 0.
      Data<bool> d_tg_meditview;                                                   // '-g', 0.
      Data<bool> d_tg_vtkview;                                                     // '-k', 0.
      Data<bool> d_tg_nobound;                                                     // '-B', 0.
      Data<bool> d_tg_nonodewritten;                                               // '-N', 0.
      Data<bool> d_tg_noelewritten;                                                // '-E', 0.
      Data<bool> d_tg_nofacewritten;                                               // '-F', 0.
      Data<bool> d_tg_noiterationnum;                                              // '-I', 0.
      Data<bool> d_tg_nojettison;                                                  // '-J', 0.
      Data<bool> d_tg_reversetetori;                                               // '-R', 0.
      Data<bool> d_tg_docheck;                                                     // '-C', 0.
      Data<bool> d_tg_quiet;                                                       // '-Q', 0.
      Data<bool> d_tg_verbose;                                                     // '-V', 0.

      // Parameters of TetGen.
      Data<int> d_tg_vertexperblock;                                           // '-x', 4092.
      Data<int> d_tg_tetrahedraperblock;                                       // '-x', 8188.
      Data<int> d_tg_shellfaceperblock;                                        // '-x', 2044.
      Data<int> d_tg_nobisect_param;                                              // '-Y', 2.
      Data<int> d_tg_addsteiner_algo;                                            // '-Y/', 1.
      Data<int> d_tg_coarsen_param;                                               // '-R', 0.
      Data<int> d_tg_weighted_param;                                              // '-w', 0.
      Data<int> d_tg_fliplinklevel;                                                    // -1.
      Data<int> d_tg_flipstarsize;                                                     // -1.
      Data<int> d_tg_fliplinklevelinc;                                                 //  1.
      Data<int> d_tg_reflevel;                                                    // '-D', 3.
      Data<int> d_tg_optlevel;                                                    // '-O', 2.
      Data<int> d_tg_optscheme;                                                   // '-O', 7.
      Data<int> d_tg_delmaxfliplevel;                                                   // 1.
      Data<int> d_tg_order;                                                       // '-o', 1.
      Data<int> d_tg_steinerleft;                                                 // '-S', 0.
      Data<int> d_tg_no_sort;                                                           // 0.
      Data<int> d_tg_hilbert_order;                                           // '-b///', 52.
      Data<int> d_tg_hilbert_limit;                                             // '-b//'  8.
      Data<int> d_tg_brio_threshold;                                              // '-b' 64.

      Data<Real> d_tg_brio_ratio;                                             // '-b/' 0.125.
      Data<Real> d_tg_facet_ang_tol;                                          // '-p', 179.9.
      Data<Real> d_tg_maxvolume;                                               // '-a', -1.0.
      Data<Real> d_tg_minratio;                                                 // '-q', 0.0.
      Data<Real> d_tg_mindihedral;                                              // '-q', 5.0.
      Data<Real> d_tg_optmaxdihedral;                                               // 165.0.
      Data<Real> d_tg_optminsmtdihed;                                               // 179.0.
      Data<Real> d_tg_optminslidihed;                                               // 179.0.
      Data<Real> d_tg_epsilon;                                               // '-T', 1.0e-8.
      Data<Real> d_tg_minedgelength;                                                  // 0.0.
      Data<Real> d_tg_coarsen_percent;                                         // -R1/#, 1.0.







    virtual void init()
    {
        addInput(&d_inputPosition);
        addInput(&d_inputTriangles);
        addInput(&d_inputConstrainedPoint);

        addInput(&d_verbose);
        addInput(&d_display_constaints);
        addInput(&d_display_result);

        addInput(&d_tg_plc                );
        addInput(&d_tg_psc                );
        addInput(&d_tg_refine             );
        addInput(&d_tg_quality            );
        addInput(&d_tg_nobisect           );
        addInput(&d_tg_coarsen            );
        addInput(&d_tg_weighted           );
        addInput(&d_tg_brio_hilbert       );
        addInput(&d_tg_incrflip           );
        addInput(&d_tg_flipinsert         );
        addInput(&d_tg_metric             );
        addInput(&d_tg_varvolume          );
        addInput(&d_tg_fixedvolume        );
        addInput(&d_tg_regionattrib       );
        addInput(&d_tg_conforming         );
        addInput(&d_tg_insertaddpoints    );
        addInput(&d_tg_diagnose           );
        addInput(&d_tg_convex             );
        addInput(&d_tg_nomergefacet       );
        addInput(&d_tg_nomergevertex      );
        addInput(&d_tg_noexact            );
        addInput(&d_tg_nostaticfilter     );
        addInput(&d_tg_zeroindex          );
        addInput(&d_tg_facesout           );
        addInput(&d_tg_edgesout           );
        addInput(&d_tg_neighout           );
        addInput(&d_tg_voroout            );
        addInput(&d_tg_meditview          );
        addInput(&d_tg_vtkview            );
        addInput(&d_tg_nobound            );
        addInput(&d_tg_nonodewritten      );
        addInput(&d_tg_noelewritten       );
        addInput(&d_tg_nofacewritten      );
        addInput(&d_tg_noiterationnum     );
        addInput(&d_tg_nojettison         );
        addInput(&d_tg_reversetetori      );
        addInput(&d_tg_docheck            );
        addInput(&d_tg_quiet              );
        addInput(&d_tg_verbose            );
        addInput(&d_tg_vertexperblock     );
        addInput(&d_tg_tetrahedraperblock );
        addInput(&d_tg_shellfaceperblock  );
        addInput(&d_tg_nobisect_param     );
        addInput(&d_tg_addsteiner_algo    );
        addInput(&d_tg_coarsen_param      );
        addInput(&d_tg_weighted_param     );
        addInput(&d_tg_fliplinklevel      );
        addInput(&d_tg_flipstarsize       );
        addInput(&d_tg_fliplinklevelinc   );
        addInput(&d_tg_reflevel           );
        addInput(&d_tg_optlevel           );
        addInput(&d_tg_optscheme          );
        addInput(&d_tg_delmaxfliplevel    );
        addInput(&d_tg_order              );
        addInput(&d_tg_steinerleft        );
        addInput(&d_tg_no_sort            );
        addInput(&d_tg_hilbert_order      );
        addInput(&d_tg_hilbert_limit      );
        addInput(&d_tg_brio_threshold     );
        addInput(&d_tg_brio_ratio         );
        addInput(&d_tg_facet_ang_tol      );
        addInput(&d_tg_maxvolume          );
        addInput(&d_tg_minratio           );
        addInput(&d_tg_mindihedral        );
        addInput(&d_tg_optmaxdihedral     );
        addInput(&d_tg_optminsmtdihed     );
        addInput(&d_tg_optminslidihed     );
        addInput(&d_tg_epsilon            );
        addInput(&d_tg_minedgelength      );
        addInput(&d_tg_coarsen_percent    );

        addOutput(&d_outputPosition);
        addOutput(&d_outputTetra);

        setDirtyValue();
        reinit();
    }

    virtual void reinit()
    {
        update();
    }

    void update()
    {
        if(d_verbose.getValue())
        {
            OUT << "Initiated mesh tetrahedrization." << ENDL;
        }


        helper::ReadAccessor< Data<VecCoord>> in_position_accessor(d_inputPosition);
        const VecCoord& in_position = in_position_accessor.ref();

        helper::ReadAccessor< Data<VecCoord>> in_constrained_point_accessor(d_inputConstrainedPoint);
        const VecCoord& in_constrained_point = in_constrained_point_accessor.ref();

        helper::ReadAccessor< Data<TriangleList>> in_triangles_accessor(d_inputTriangles);
        const TriangleList& in_triangles = in_triangles_accessor.ref();

        helper::WriteOnlyAccessor< Data<VecCoord>> out_position_accessor(d_outputPosition);
        VecCoord& out_position = out_position_accessor.wref();

        helper::WriteOnlyAccessor< Data<TetraList>> out_tetra_accessor(d_outputTetra);
        TetraList& out_tetra = out_tetra_accessor.wref();


        if(d_verbose.getValue())
        {
            OUT << "Working on an input mesh of " << in_position.size() << " and " << in_triangles.size() << " triangles." << ENDL;
        }

        tetgenio in;

        in.firstnumber = 0;
        in.numberofpoints = in_position.size();
        in.pointlist = new Real[in.numberofpoints * 3];

        for(uint i=0; i<in.numberofpoints; ++i)
        {
            for(uint j=0; j<3; ++j)
            {
                in.pointlist[i*3+j] = in_position[i][j];
            }
        }

        in.numberoffacets = in_triangles.size();
        in.facetlist = new tetgenio::facet[in.numberoffacets];
        in.facetmarkerlist = new int[in.numberoffacets];


        for(uint i=0; i<in.numberoffacets; ++i)
        {
            tetgenio::facet *f = &in.facetlist[i];
            f->numberofpolygons = 1;
            f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
            f->numberofholes = 0;
            f->holelist = nullptr;

            tetgenio::polygon *p = &f->polygonlist[0];
            p->numberofvertices = 3;
            p->vertexlist = new int[p->numberofvertices];
            p->vertexlist[0] = in_triangles[i][0];
            p->vertexlist[1] = in_triangles[i][1];
            p->vertexlist[2] = in_triangles[i][2];

            in.facetmarkerlist[i] = 0;
        }



        tetgenio interior_constraint;

        interior_constraint.firstnumber = 0;

        interior_constraint.numberofpoints = in_constrained_point.size();
        interior_constraint.pointlist = new Real[interior_constraint.numberofpoints * 3];

        for(uint i=0; i<interior_constraint.numberofpoints; ++i)
        {
            if(d_display_constaints.getValue())
            {
                OUT << "c#" << i << " :  ";
            }
            for(uint j=0; j<3; ++j)
            {
                interior_constraint.pointlist[i*3+j] = in_constrained_point[i][j];
                if(d_display_constaints.getValue())
                {
                    OUT << "  " << interior_constraint.pointlist[i*3+j];
                }
            }
            if(d_display_constaints.getValue())
            {
                OUT << ENDL;
            }
        }



        tetgenbehavior behavior;
        setBehavior(behavior);
        if(d_verbose.getValue())
        {
            OUT << "Using following parameters:" << ENDL;
            displayBehavior(behavior);
        }

        tetgenio out;

        tetrahedralize(&behavior, &in, &out, &interior_constraint);

        if(d_verbose.getValue())
        {
            OUT << "Created tetrahedral mesh with " << out.numberofpoints << " points and " << out.numberoftetrahedra << " tetrahedra." << ENDL;
        }


        out_position.resize(out.numberofpoints);

        for(uint i=0; i<out.numberofpoints; ++i)
        {
            if(d_display_result.getValue())
            {
                OUT << "v#" << i << " :  ";
            }

            for(uint j=0; j<3; ++j)
            {
                out_position[i][j] = out.pointlist[i*3+j];
                if(d_display_result.getValue())
                {
                    OUT << "  " << out_position[i][j];
                }
            }
            if(d_display_result.getValue())
            {
                OUT << ENDL;
            }
        }

        assert(out.numberofcorners == 4);

        out_tetra.resize(out.numberoftetrahedra);

        for (uint i=0; i<out.numberoftetrahedra; ++i)
        {
            for (uint j=0; j<4; ++j)
            {
                out_tetra[i][j] = out.tetrahedronlist[i * 4 + j];
            }
        }

        cleanDirty();
    }

    void setBehavior(tetgenbehavior& behavior)
    {
        behavior.plc                = d_tg_plc.getValue();
        behavior.psc                = d_tg_psc.getValue();
        behavior.refine             = d_tg_refine.getValue();
        behavior.quality            = d_tg_quality.getValue();
        behavior.nobisect           = d_tg_nobisect.getValue();
        behavior.coarsen            = d_tg_coarsen.getValue();
        behavior.weighted           = d_tg_weighted.getValue();
        behavior.brio_hilbert       = d_tg_brio_hilbert.getValue();
        behavior.incrflip           = d_tg_incrflip.getValue();
        behavior.flipinsert         = d_tg_flipinsert.getValue();
        behavior.metric             = d_tg_metric.getValue();
        behavior.varvolume          = d_tg_varvolume.getValue();
        behavior.fixedvolume        = d_tg_fixedvolume.getValue();
        behavior.regionattrib       = d_tg_regionattrib.getValue();
        behavior.conforming         = d_tg_conforming.getValue();
        behavior.insertaddpoints    = d_tg_insertaddpoints.getValue();
        behavior.diagnose           = d_tg_diagnose.getValue();
        behavior.convex             = d_tg_convex.getValue();
        behavior.nomergefacet       = d_tg_nomergefacet.getValue();
        behavior.nomergevertex      = d_tg_nomergevertex.getValue();
        behavior.noexact            = d_tg_noexact.getValue();
        behavior.nostaticfilter     = d_tg_nostaticfilter.getValue();
        behavior.zeroindex          = d_tg_zeroindex.getValue();
        behavior.facesout           = d_tg_facesout.getValue();
        behavior.edgesout           = d_tg_edgesout.getValue();
        behavior.neighout           = d_tg_neighout.getValue();
        behavior.voroout            = d_tg_voroout.getValue();
        behavior.meditview          = d_tg_meditview.getValue();
        behavior.vtkview            = d_tg_vtkview.getValue();
        behavior.nobound            = d_tg_nobound.getValue();
        behavior.nonodewritten      = d_tg_nonodewritten.getValue();
        behavior.noelewritten       = d_tg_noelewritten.getValue();
        behavior.nofacewritten      = d_tg_nofacewritten.getValue();
        behavior.noiterationnum     = d_tg_noiterationnum.getValue();
        behavior.nojettison         = d_tg_nojettison.getValue();
        behavior.reversetetori      = d_tg_reversetetori.getValue();
        behavior.docheck            = d_tg_docheck.getValue();
        behavior.quiet              = d_tg_quiet.getValue();
        behavior.verbose            = d_tg_verbose.getValue();
        behavior.vertexperblock     = d_tg_vertexperblock.getValue();
        behavior.tetrahedraperblock = d_tg_tetrahedraperblock.getValue();
        behavior.shellfaceperblock  = d_tg_shellfaceperblock.getValue();
        behavior.nobisect_param     = d_tg_nobisect_param.getValue();
        behavior.addsteiner_algo    = d_tg_addsteiner_algo.getValue();
        behavior.coarsen_param      = d_tg_coarsen_param.getValue();
        behavior.weighted_param     = d_tg_weighted_param.getValue();
        behavior.fliplinklevel      = d_tg_fliplinklevel.getValue();
        behavior.flipstarsize       = d_tg_flipstarsize.getValue();
        behavior.fliplinklevelinc   = d_tg_fliplinklevelinc.getValue();
        behavior.reflevel           = d_tg_reflevel.getValue();
        behavior.optlevel           = d_tg_optlevel.getValue();
        behavior.optscheme          = d_tg_optscheme.getValue();
        behavior.delmaxfliplevel    = d_tg_delmaxfliplevel.getValue();
        behavior.order              = d_tg_order.getValue();
        behavior.steinerleft        = d_tg_steinerleft.getValue();
        behavior.no_sort            = d_tg_no_sort.getValue();
        behavior.hilbert_order      = d_tg_hilbert_order.getValue();
        behavior.hilbert_limit      = d_tg_hilbert_limit.getValue();
        behavior.brio_threshold     = d_tg_brio_threshold.getValue();
        behavior.brio_ratio         = d_tg_brio_ratio.getValue();
        behavior.facet_ang_tol      = d_tg_facet_ang_tol.getValue();
        behavior.maxvolume          = d_tg_maxvolume.getValue();
        behavior.minratio           = d_tg_minratio.getValue();
        behavior.mindihedral        = d_tg_mindihedral.getValue();
        behavior.optmaxdihedral     = d_tg_optmaxdihedral.getValue();
        behavior.optminsmtdihed     = d_tg_optminsmtdihed.getValue();
        behavior.optminslidihed     = d_tg_optminslidihed.getValue();
        behavior.epsilon            = d_tg_epsilon.getValue();
        behavior.minedgelength      = d_tg_minedgelength.getValue();
        behavior.coarsen_percent    = d_tg_coarsen_percent.getValue();
    }


    void displayBehavior(const tetgenbehavior& behavior)
    {
        OUT << "plc                : " << behavior.plc                << ENDL;
        OUT << "psc                : " << behavior.psc                << ENDL;
        OUT << "refine             : " << behavior.refine             << ENDL;
        OUT << "quality            : " << behavior.quality            << ENDL;
        OUT << "nobisect           : " << behavior.nobisect           << ENDL;
        OUT << "coarsen            : " << behavior.coarsen            << ENDL;
        OUT << "weighted           : " << behavior.weighted           << ENDL;
        OUT << "brio_hilbert       : " << behavior.brio_hilbert       << ENDL;
        OUT << "incrflip           : " << behavior.incrflip           << ENDL;
        OUT << "flipinsert         : " << behavior.flipinsert         << ENDL;
        OUT << "metric             : " << behavior.metric             << ENDL;
        OUT << "varvolume          : " << behavior.varvolume          << ENDL;
        OUT << "fixedvolume        : " << behavior.fixedvolume        << ENDL;
        OUT << "regionattrib       : " << behavior.regionattrib       << ENDL;
        OUT << "conforming         : " << behavior.conforming         << ENDL;
        OUT << "insertaddpoints    : " << behavior.insertaddpoints    << ENDL;
        OUT << "diagnose           : " << behavior.diagnose           << ENDL;
        OUT << "convex             : " << behavior.convex             << ENDL;
        OUT << "nomergefacet       : " << behavior.nomergefacet       << ENDL;
        OUT << "nomergevertex      : " << behavior.nomergevertex      << ENDL;
        OUT << "noexact            : " << behavior.noexact            << ENDL;
        OUT << "nostaticfilter     : " << behavior.nostaticfilter     << ENDL;
        OUT << "zeroindex          : " << behavior.zeroindex          << ENDL;
        OUT << "facesout           : " << behavior.facesout           << ENDL;
        OUT << "edgesout           : " << behavior.edgesout           << ENDL;
        OUT << "neighout           : " << behavior.neighout           << ENDL;
        OUT << "voroout            : " << behavior.voroout            << ENDL;
        OUT << "meditview          : " << behavior.meditview          << ENDL;
        OUT << "vtkview            : " << behavior.vtkview            << ENDL;
        OUT << "nobound            : " << behavior.nobound            << ENDL;
        OUT << "nonodewritten      : " << behavior.nonodewritten      << ENDL;
        OUT << "noelewritten       : " << behavior.noelewritten       << ENDL;
        OUT << "nofacewritten      : " << behavior.nofacewritten      << ENDL;
        OUT << "noiterationnum     : " << behavior.noiterationnum     << ENDL;
        OUT << "nojettison         : " << behavior.nojettison         << ENDL;
        OUT << "reversetetori      : " << behavior.reversetetori      << ENDL;
        OUT << "docheck            : " << behavior.docheck            << ENDL;
        OUT << "quiet              : " << behavior.quiet              << ENDL;
        OUT << "verbose            : " << behavior.verbose            << ENDL;
        OUT << "vertexperblock     : " << behavior.vertexperblock     << ENDL;
        OUT << "tetrahedraperblock : " << behavior.tetrahedraperblock << ENDL;
        OUT << "shellfaceperblock  : " << behavior.shellfaceperblock  << ENDL;
        OUT << "nobisect_param     : " << behavior.nobisect_param     << ENDL;
        OUT << "addsteiner_algo    : " << behavior.addsteiner_algo    << ENDL;
        OUT << "coarsen_param      : " << behavior.coarsen_param      << ENDL;
        OUT << "weighted_param     : " << behavior.weighted_param     << ENDL;
        OUT << "fliplinklevel      : " << behavior.fliplinklevel      << ENDL;
        OUT << "flipstarsize       : " << behavior.flipstarsize       << ENDL;
        OUT << "fliplinklevelinc   : " << behavior.fliplinklevelinc   << ENDL;
        OUT << "reflevel           : " << behavior.reflevel           << ENDL;
        OUT << "optlevel           : " << behavior.optlevel           << ENDL;
        OUT << "optscheme          : " << behavior.optscheme          << ENDL;
        OUT << "delmaxfliplevel    : " << behavior.delmaxfliplevel    << ENDL;
        OUT << "order              : " << behavior.order              << ENDL;
        OUT << "steinerleft        : " << behavior.steinerleft        << ENDL;
        OUT << "no_sort            : " << behavior.no_sort            << ENDL;
        OUT << "hilbert_order      : " << behavior.hilbert_order      << ENDL;
        OUT << "hilbert_limit      : " << behavior.hilbert_limit      << ENDL;
        OUT << "brio_threshold     : " << behavior.brio_threshold     << ENDL;
        OUT << "brio_ratio         : " << behavior.brio_ratio         << ENDL;
        OUT << "facet_ang_tol      : " << behavior.facet_ang_tol      << ENDL;
        OUT << "maxvolume          : " << behavior.maxvolume          << ENDL;
        OUT << "minratio           : " << behavior.minratio           << ENDL;
        OUT << "mindihedral        : " << behavior.mindihedral        << ENDL;
        OUT << "optmaxdihedral     : " << behavior.optmaxdihedral     << ENDL;
        OUT << "optminsmtdihed     : " << behavior.optminsmtdihed     << ENDL;
        OUT << "optminslidihed     : " << behavior.optminslidihed     << ENDL;
        OUT << "epsilon            : " << behavior.epsilon            << ENDL;
        OUT << "minedgelength      : " << behavior.minedgelength      << ENDL;
        OUT << "coarsen_percent    : " << behavior.coarsen_percent    << ENDL;
    }

protected:
    MeshTetrahedrizationEngine() : Inherited()
      , d_inputPosition (initData(&d_inputPosition , VecCoord()    , "in_position","Positions of the vertices of the input triangle mesh"))
      , d_inputTriangles(initData(&d_inputTriangles, TriangleList(), "in_triangle","List of indices (starting at 0) defining triangles"))
      , d_inputConstrainedPoint (initData(&d_inputConstrainedPoint , VecCoord()    , "in_constraints","Positions of the constrained interior vertices (to be inserted in the final tetrahedrization)"))
      , d_outputPosition(initData(&d_outputPosition, VecCoord()    , "out_position","Positions of the vertices of the output tetrahedral mesh"))
      , d_outputTetra   (initData(&d_outputTetra   , TetraList()   , "out_tetra","List of indices (starting at 0) defining tetras"))

      , d_verbose             (initData(&d_verbose            ,  true , "verbose"           , "verbose"           ))
      , d_display_constaints  (initData(&d_display_constaints ,  false, "display_constaints", "display_constaints"))
      , d_display_result      (initData(&d_display_result     ,  false, "display_result"    , "display_result"    ))

      , d_tg_plc                 (initData(&d_tg_plc                ,  true , "plc"               , "plc"               ))
      , d_tg_psc                 (initData(&d_tg_psc                ,  false, "psc"               , "psc"               ))
      , d_tg_refine              (initData(&d_tg_refine             ,  false, "refine"            , "refine"            ))
      , d_tg_quality             (initData(&d_tg_quality            ,  true , "quality"           , "quality"           ))
      , d_tg_nobisect            (initData(&d_tg_nobisect           ,  false, "nobisect"          , "nobisect"          ))
      , d_tg_coarsen             (initData(&d_tg_coarsen            ,  false, "coarsen"           , "coarsen"           ))
      , d_tg_weighted            (initData(&d_tg_weighted           ,  false, "weighted"          , "weighted"          ))
      , d_tg_brio_hilbert        (initData(&d_tg_brio_hilbert       ,  true , "brio_hilbert"      , "brio_hilbert"      ))
      , d_tg_incrflip            (initData(&d_tg_incrflip           ,  false, "incrflip"          , "incrflip"          ))
      , d_tg_flipinsert          (initData(&d_tg_flipinsert         ,  false, "flipinsert"        , "flipinsert"        ))
      , d_tg_metric              (initData(&d_tg_metric             ,  false, "metric"            , "metric"            ))
      , d_tg_varvolume           (initData(&d_tg_varvolume          ,  false, "varvolume"         , "varvolume"         ))
      , d_tg_fixedvolume         (initData(&d_tg_fixedvolume        ,  false, "fixedvolume"       , "fixedvolume"       ))
      , d_tg_regionattrib        (initData(&d_tg_regionattrib       ,  false, "regionattrib"      , "regionattrib"      ))
      , d_tg_conforming          (initData(&d_tg_conforming         ,  false, "conforming"        , "conforming"        ))
      , d_tg_insertaddpoints     (initData(&d_tg_insertaddpoints    ,  false, "insertaddpoints"   , "insertaddpoints"   ))
      , d_tg_diagnose            (initData(&d_tg_diagnose           ,  false, "diagnose"          , "diagnose"          ))
      , d_tg_convex              (initData(&d_tg_convex             ,  false, "convex"            , "convex"            ))
      , d_tg_nomergefacet        (initData(&d_tg_nomergefacet       ,  false, "nomergefacet"      , "nomergefacet"      ))
      , d_tg_nomergevertex       (initData(&d_tg_nomergevertex      ,  false, "nomergevertex"     , "nomergevertex"     ))
      , d_tg_noexact             (initData(&d_tg_noexact            ,  false, "noexact"           , "noexact"           ))
      , d_tg_nostaticfilter      (initData(&d_tg_nostaticfilter     ,  false, "nostaticfilter"    , "nostaticfilter"    ))
      , d_tg_zeroindex           (initData(&d_tg_zeroindex          ,  false, "zeroindex"         , "zeroindex"         ))
      , d_tg_facesout            (initData(&d_tg_facesout           ,  false, "facesout"          , "facesout"          ))
      , d_tg_edgesout            (initData(&d_tg_edgesout           ,  false, "edgesout"          , "edgesout"          ))
      , d_tg_neighout            (initData(&d_tg_neighout           ,  false, "neighout"          , "neighout"          ))
      , d_tg_voroout             (initData(&d_tg_voroout            ,  false, "voroout"           , "voroout"           ))
      , d_tg_meditview           (initData(&d_tg_meditview          ,  false, "meditview"         , "meditview"         ))
      , d_tg_vtkview             (initData(&d_tg_vtkview            ,  false, "vtkview"           , "vtkview"           ))
      , d_tg_nobound             (initData(&d_tg_nobound            ,  false, "nobound"           , "nobound"           ))
      , d_tg_nonodewritten       (initData(&d_tg_nonodewritten      ,  false, "nonodewritten"     , "nonodewritten"     ))
      , d_tg_noelewritten        (initData(&d_tg_noelewritten       ,  false, "noelewritten"      , "noelewritten"      ))
      , d_tg_nofacewritten       (initData(&d_tg_nofacewritten      ,  false, "nofacewritten"     , "nofacewritten"     ))
      , d_tg_noiterationnum      (initData(&d_tg_noiterationnum     ,  false, "noiterationnum"    , "noiterationnum"    ))
      , d_tg_nojettison          (initData(&d_tg_nojettison         ,  false, "nojettison"        , "nojettison"        ))
      , d_tg_reversetetori       (initData(&d_tg_reversetetori      ,  false, "reversetetori"     , "reversetetori"     ))
      , d_tg_docheck             (initData(&d_tg_docheck            ,  false, "docheck"           , "docheck"           ))
      , d_tg_quiet               (initData(&d_tg_quiet              ,  true , "quiet"             , "quiet"             ))
      , d_tg_verbose             (initData(&d_tg_verbose            ,  false, "tg_verbose"        , "verbose"           ))
      , d_tg_vertexperblock      (initData(&d_tg_vertexperblock     ,   4092, "vertexperblock"    , "vertexperblock"    ))
      , d_tg_tetrahedraperblock  (initData(&d_tg_tetrahedraperblock ,   8188, "tetrahedraperblock", "tetrahedraperblock"))
      , d_tg_shellfaceperblock   (initData(&d_tg_shellfaceperblock  ,   4092, "shellfaceperblock" , "shellfaceperblock" ))
      , d_tg_nobisect_param      (initData(&d_tg_nobisect_param     ,      2, "nobisect_param"    , "nobisect_param"    ))
      , d_tg_addsteiner_algo     (initData(&d_tg_addsteiner_algo    ,      1, "addsteiner_algo"   , "addsteiner_algo"   ))
      , d_tg_coarsen_param       (initData(&d_tg_coarsen_param      ,      0, "coarsen_param"     , "coarsen_param"     ))
      , d_tg_weighted_param      (initData(&d_tg_weighted_param     ,      0, "weighteparam"      , "weighteparam"      ))
      , d_tg_fliplinklevel       (initData(&d_tg_fliplinklevel      ,     -1, "fliplinklevel"     , "fliplinklevel"     ))
      , d_tg_flipstarsize        (initData(&d_tg_flipstarsize       ,     -1, "flipstarsize"      , "flipstarsize"      ))
      , d_tg_fliplinklevelinc    (initData(&d_tg_fliplinklevelinc   ,      1, "fliplinklevelinc"  , "fliplinklevelinc"  ))
      , d_tg_reflevel            (initData(&d_tg_reflevel           ,      3, "reflevel"          , "reflevel"          ))
      , d_tg_optlevel            (initData(&d_tg_optlevel           ,      2, "optlevel"          , "optlevel"          ))
      , d_tg_optscheme           (initData(&d_tg_optscheme          ,      7, "optscheme"         , "optscheme"         ))
      , d_tg_delmaxfliplevel     (initData(&d_tg_delmaxfliplevel    ,      1, "delmaxfliplevel"   , "delmaxfliplevel"   ))
      , d_tg_order               (initData(&d_tg_order              ,      1, "order"             , "order"             ))
      , d_tg_steinerleft         (initData(&d_tg_steinerleft        ,     -1, "steinerleft"       , "steinerleft"       ))
      , d_tg_no_sort             (initData(&d_tg_no_sort            ,      0, "no_sort"           , "no_sort"           ))
      , d_tg_hilbert_order       (initData(&d_tg_hilbert_order      ,     52, "hilbert_order"     , "hilbert_order"     ))
      , d_tg_hilbert_limit       (initData(&d_tg_hilbert_limit      ,      8, "hilbert_limit"     , "hilbert_limit"     ))
      , d_tg_brio_threshold      (initData(&d_tg_brio_threshold     ,     64, "brio_threshold"    , "brio_threshold"    ))
      , d_tg_brio_ratio          (initData(&d_tg_brio_ratio         ,  0.125, "brio_ratio"        , "brio_ratio"        ))
      , d_tg_facet_ang_tol       (initData(&d_tg_facet_ang_tol      ,  179.9, "facet_ang_tol"     , "facet_ang_tol"     ))
      , d_tg_maxvolume           (initData(&d_tg_maxvolume          ,   -1.0, "maxvolume"         , "maxvolume"         ))
      , d_tg_minratio            (initData(&d_tg_minratio           ,    0.0, "minratio"          , "minratio"          ))
      , d_tg_mindihedral         (initData(&d_tg_mindihedral        ,    0.0, "mindihedral"       , "mindihedral"       ))
      , d_tg_optmaxdihedral      (initData(&d_tg_optmaxdihedral     ,  165.0, "optmaxdihedral"    , "optmaxdihedral"    ))
      , d_tg_optminsmtdihed      (initData(&d_tg_optminsmtdihed     ,  179.0, "optminsmtdihed"    , "optminsmtdihed"    ))
      , d_tg_optminslidihed      (initData(&d_tg_optminslidihed     ,  179.0, "optminslidihed"    , "optminslidihed"    ))
      , d_tg_epsilon             (initData(&d_tg_epsilon            , 1.0e-8, "epsilon"           , "epsilon"           ))
      , d_tg_minedgelength       (initData(&d_tg_minedgelength      ,    0.0, "minedgelength"     , "minedgelength"     ))
      , d_tg_coarsen_percent     (initData(&d_tg_coarsen_percent    ,    1.0, "coarsen_percent"   , "coarsen_percent"   ))

    {
    }

    ~MeshTetrahedrizationEngine()
    {

    }

};




}
}
}


#endif
