#include "TraversabilityGrid.hpp"
#include <boost/bind.hpp>
#include <tools/RadialLookUpTable.hpp>
#include <tools/BoxLookUpTable.hpp>
#include <Eigen/Geometry>

using namespace envire;
using namespace Eigen;

ENVIRONMENT_ITEM_DEF( TraversabilityGrid )
const std::string TraversabilityGrid::TRAVERSABILITY = "traversability";
const std::string TraversabilityGrid::PROBABILITY = "probability";
const std::vector<std::string> TraversabilityGrid::bands = { TraversabilityGrid::TRAVERSABILITY, TraversabilityGrid::PROBABILITY };

class StatisticHelper
{
    static RadialLookUpTable *lut;
    static BoxLookUpTable *boxLut;
    const base::Pose2D &pose;
    Eigen::Rotation2D<double> inverseOrientation;
    const TraversabilityGrid &grid;
    const TraversabilityGrid::ArrayType &gridData;
    TraversabilityStatistic *innerStats;
    TraversabilityStatistic *outerStats;
    double scaleX;
    double scaleY;
    size_t xCenter;
    size_t yCenter;
public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    StatisticHelper(const base::Pose2D &pose, const TraversabilityGrid &grid, double sizeX, double sizeY, double borderWidth) : pose(pose),
    inverseOrientation(Eigen::Rotation2D<double>(pose.orientation).inverse()), grid(grid), gridData(grid.getGridData(TraversabilityGrid::TRAVERSABILITY))
    , scaleX(grid.getScaleX()), scaleY(grid.getScaleY())
    {
        if(!lut)
            lut = new RadialLookUpTable();
        lut->recompute(grid.getScaleX(), std::max(sizeX, sizeY));

        if(!boxLut)
            boxLut = new BoxLookUpTable();
        //note the scale should be higher than the grid scale because
        //of the roation. Else we get aliasing problems.
        boxLut->recompute(scaleX / 10.0, sizeX, sizeY, borderWidth * 2);

        grid.toGrid(pose.position.x(), pose.position.y(), xCenter, yCenter);
    }

    void addInnerVal(size_t x, size_t y)
    {
        innerStats->addMeasurement(gridData[y][x], lut->getDistance(x-xCenter, y-yCenter));
    }

    void addOuterVal(size_t x, size_t y)
    {
        Vector2d pos_map;
        grid.fromGrid(x, y, pos_map.x(), pos_map.y());
        Vector2d posAligned = inverseOrientation * (pos_map - pose.position);

        outerStats->addMeasurement(gridData[y][x], boxLut->getDistanceToBox(posAligned.x(), posAligned.y()));
    }

    void setInnerStatistic(TraversabilityStatistic *innerStat)
    {
        innerStats = innerStat;
    }
    void setOuterStatistic(TraversabilityStatistic *outerStat)
    {
        outerStats = outerStat;
    }
};

RadialLookUpTable *StatisticHelper::lut;
BoxLookUpTable *StatisticHelper::boxLut;

void addVal(size_t x, size_t y, std::vector<uint8_t> &stats, const TraversabilityGrid::ArrayType &gridData)
{
    stats[gridData[y][x]]++;
}

void TraversabilityGrid::computeStatistic(const base::Pose2D &pose, double sizeX, double sizeY, TraversabilityStatistic &innerStatistic) const
{
    StatisticHelper helper(pose, *this, sizeX, sizeY, 0);
    helper.setInnerStatistic(&innerStatistic);
    forEachInRectangle(pose, sizeX, sizeY, boost::bind( &StatisticHelper::addInnerVal, &helper,  _1, _2));
}

void TraversabilityGrid::computeStatistic(const base::Pose2D &pose, double sizeX, double sizeY, double borderWidth, TraversabilityStatistic &innerStatistic, TraversabilityStatistic &outerStatistic) const
{
    StatisticHelper helper(pose, *this, sizeX, sizeY, borderWidth);
    helper.setInnerStatistic(&innerStatistic);
    helper.setOuterStatistic(&outerStatistic);
    forEachInRectangles(pose, sizeX, sizeY, boost::bind( &StatisticHelper::addInnerVal, &helper,  _1, _2),
                        sizeX + borderWidth, sizeY + borderWidth, boost::bind( &StatisticHelper::addOuterVal, &helper,  _1, _2));
}

const TraversabilityClass& TraversabilityGrid::getWorstTraversabilityClassInRectangle(const base::Pose2D& pose, double sizeX, double sizeY) const
{
    double curDrivability = std::numeric_limits< double >::max();
    int curClass = -1;

    TraversabilityStatistic innerStatistic;
    computeStatistic(pose, sizeX, sizeY, innerStatistic);

    for(uint8_t i = 0; i <= innerStatistic.getHighestTraversabilityClass(); i++)
    {
        size_t count;
        double dist;
        innerStatistic.getStatisticForClass(i, dist, count);
        if(count)
        {
            const TraversabilityClass &klass(getTraversabilityClass(i));
            if(curDrivability > klass.getDrivability())
            {
                curClass = i;
                curDrivability = klass.getDrivability();
                //can't get worse than not traversable
                if(!klass.isTraversable())
                    return klass;
            }
        }
    }

    if(curClass < 0)
    {
        std::cout << "Pose " << pose.position.transpose() << " sizeY " << sizeY << " sizeX " << sizeX << " Total Count " << innerStatistic.getTotalCount() << std::endl;
        for(uint8_t i = 0; i <= innerStatistic.getHighestTraversabilityClass(); i++)
        {
            size_t count;
            double dist;
            innerStatistic.getStatisticForClass(i, dist, count);
            const TraversabilityClass &klass(getTraversabilityClass(i));
            std::cout << "Class " << i << " drivability " << klass.getDrivability() << " count " << count << std::endl;
        }
        throw std::runtime_error("TraversabilityGrid::Error, terrain class could not be identified");
    }

    return getTraversabilityClass(curClass);
}

void TraversabilityGrid::probabilityCallback(size_t x, size_t y, double& worst) const
{
    double curProbabilty = getProbability(x, y);
    if(worst > curProbabilty)
        worst = curProbabilty;
}

double TraversabilityGrid::getWorstProbabilityInRectangle(const base::Pose2D& pose, double sizeX, double sizeY) const
{
    double ret = 1.0;
    forEachInRectangle(pose, sizeX, sizeY, boost::bind(&TraversabilityGrid::probabilityCallback, this, _1, _2, boost::ref(ret)));
    return ret;
}

void TraversabilityGrid::setTraversabilityAndProbability(uint8_t klass, double probability, size_t x, size_t y)
{
    setProbability(probability, x, y);
    setTraversability(klass, x, y);
}

void TraversabilityGrid::setTraversability(uint8_t klass, size_t x, size_t y)
{
    setTraversabilityArray();
    (*traversabilityArray)[y][x] = klass;
}

const TraversabilityClass& TraversabilityGrid::getTraversability(size_t x, size_t y) const
{
    setTraversabilityArray();
    return traversabilityClasses[(*traversabilityArray)[y][x]];
}

bool TraversabilityGrid::registerNewTraversabilityClass(uint8_t& retId, const TraversabilityClass& klass)
{
    if(traversabilityClasses.size() >= std::numeric_limits< uint8_t >::max())
        return false;

    retId = traversabilityClasses.size() + 1;
    setTraversabilityClass(retId, klass);
    return true;
}

void TraversabilityGrid::setTraversabilityClass(uint8_t num, const TraversabilityClass& klass)
{
    if(traversabilityClasses.size() <= num)
        traversabilityClasses.resize(num + 1);

    traversabilityClasses[num] = klass;
}

const TraversabilityClass& TraversabilityGrid::getTraversabilityClass(uint8_t klass) const
{
    if(traversabilityClasses.size() <= klass)
    {
        throw std::runtime_error("TraversabilityGrid::Tried to access non existing TraversabilityClass " + boost::lexical_cast< std::string>((int) klass));
    }

    return traversabilityClasses[klass];
}

void TraversabilityGrid::setProbabilityArray()
{
    if(!probabilityArray)
    {
        probabilityArray = &(getData<ArrayType>(PROBABILITY));
        //hm, why is the resize done here ?
        probabilityArray->resize(boost::extents[getCellSizeY()][getCellSizeX()]);
    }
}

void TraversabilityGrid::setTraversabilityArray()
{
    if(!traversabilityArray)
    {
        traversabilityArray = &(getData<ArrayType>(TRAVERSABILITY));
		traversabilityArray->resize(boost::extents[getCellSizeY()][getCellSizeX()]);
    }
}

void TraversabilityGrid::setProbabilityArray() const
{
    TraversabilityGrid *nonConst = const_cast<TraversabilityGrid *>(this);
    nonConst->setProbabilityArray();
}

void TraversabilityGrid::setTraversabilityArray() const
{
    TraversabilityGrid *nonConst = const_cast<TraversabilityGrid *>(this);
    nonConst->setTraversabilityArray();
}

void TraversabilityGrid::setProbability(double probability, size_t x, size_t y)
{
    setProbabilityArray();

    const uint8_t probVal = std::min<uint32_t>(std::numeric_limits< uint8_t >::max(), probability * std::numeric_limits< uint8_t >::max());

    (*probabilityArray)[y][x] = probVal;
}

double TraversabilityGrid::getProbability(size_t x, size_t y) const
{
    const_cast<TraversabilityGrid *>(this)->setProbabilityArray();

    return ((double) (*probabilityArray)[y][x]) / std::numeric_limits< uint8_t >::max();
}

void TraversabilityGrid::serialize(Serialization& so)
{
    so.write<size_t>(std::string("drivabilityClassCount"), traversabilityClasses.size());
    for(size_t i = 0; i < traversabilityClasses.size(); i++)
    {
        so.write(std::string("drivability") + boost::lexical_cast< std::string>((int) i), traversabilityClasses[i].getDrivability());
    }
    envire::Grid< uint8_t >::serialize(so);
}

void TraversabilityGrid::unserialize(Serialization& so)
{
    envire::Grid< uint8_t >::unserialize(so);
    size_t traversabilityClassCount = 0;
    so.read<size_t>(std::string("drivabilityClassCount"), traversabilityClassCount);
    for(size_t i = 0; i < traversabilityClassCount; i++)
    {
        double drivability;
        if(so.read(std::string("drivability") + boost::lexical_cast< std::string>((int) i), drivability))
            setTraversabilityClass(i, TraversabilityClass(drivability));
    }
}

TraversabilityGrid& TraversabilityGrid::operator=(const TraversabilityGrid& other)
{
    const Grid<uint8_t> *obaseGrid = dynamic_cast<const Grid<uint8_t> *>(&other);
    Grid<uint8_t> *baseGrid = dynamic_cast<Grid<uint8_t> *>(this);
    assert(baseGrid);
    assert(obaseGrid);
    *baseGrid = *obaseGrid;

    traversabilityClasses = other.traversabilityClasses;

    traversabilityArray = NULL;
    probabilityArray = NULL;
    return *this;
}


#include "drake/geometry/render/vtk_util.h"

#include <cmath>
#include <limits>

#include <Eigen/Dense>
#include <gtest/gtest.h>
#include <vtkCellData.h>
#include <vtkNew.h>
#include <vtkPlaneSource.h>
#include <vtkSmartPointer.h>

namespace drake {
namespace geometry {
namespace render {
namespace vtk_util {
namespace {

const double kTolerance = 1e-15;
const double kSize = 10.;
const double kHalfSize = kSize * 0.5;
const int kNumPoints = 4;

struct Point {
  double x;
  double y;
  double z;
};

const Point kExpectedPointSet[kNumPoints] = {
  Point{ kHalfSize, -kHalfSize, 0.},
  Point{ kHalfSize,  kHalfSize, 0.},
  Point{-kHalfSize, -kHalfSize, 0.},
  Point{-kHalfSize,  kHalfSize, 0.}
};

GTEST_TEST(PointsCorrespondenceTest, PlaneCreationTest) {
  vtkSmartPointer<vtkPlaneSource> dut =
      CreateSquarePlane(kSize);

  EXPECT_EQ(kNumPoints, dut->GetOutput()->GetPoints()->GetNumberOfPoints());
  for (int i = 0; i < kNumPoints; ++i) {
    double dut_point[3];
    dut->GetOutput()->GetPoints()->GetPoint(i, dut_point);

    EXPECT_NEAR(kExpectedPointSet[i].x, dut_point[0], kTolerance);
    EXPECT_NEAR(kExpectedPointSet[i].y, dut_point[1], kTolerance);
    EXPECT_NEAR(kExpectedPointSet[i].z, dut_point[2], kTolerance);
  }
}

// Verifies whether the conversion is correct.
GTEST_TEST(ConvertToVtkTransformTest, ConversionTest) {
  const Eigen::Isometry3d expected(
      (Eigen::Translation3d(1., 2., 3.) *
       Eigen::AngleAxisd(1., Eigen::Vector3d(1. / std::sqrt(3.),
                                             1. / std::sqrt(3.),
                                             1. / std::sqrt(3.)))));

  auto dut = ConvertToVtkTransform(expected);

  for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 4; ++j) {
      EXPECT_NEAR(expected.matrix()(i, j),
                  dut->GetMatrix()->GetElement(i, j),
                  kTolerance);
    }
  }
}

GTEST_TEST(MakeVtkPointerArrayTest, ValidTest) {
  vtkNew<vtkCellData> data0;
  vtkNew<vtkCellData> data1;
  vtkNew<vtkCellData> data2;

  const auto dut1 = MakeVtkPointerArray(data0);
  EXPECT_EQ(dut1.size(), 1);
  EXPECT_EQ(dut1[0], data0.GetPointer());

  const auto dut2 = MakeVtkPointerArray(data0, data1);
  EXPECT_EQ(dut2.size(), 2);
  EXPECT_EQ(dut2[0], data0.GetPointer());
  EXPECT_EQ(dut2[1], data1.GetPointer());

  const auto dut3 = MakeVtkPointerArray(data0, data1, data2);
  EXPECT_EQ(dut3.size(), 3);
  EXPECT_EQ(dut3[0], data0.GetPointer());
  EXPECT_EQ(dut3[1], data1.GetPointer());
  EXPECT_EQ(dut3[2], data2.GetPointer());
}

}  // namespace
}  // namespace vtk_util
}  // namespace render
}  // namespace geometry
}  // namespace drake


/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "LiveRange.h"

#include <boost/pending/disjoint_sets.hpp>
#include <boost/property_map/property_map.hpp>

#include "ControlFlow.h"
#include "IRCode.h"
#include "ScopedCFG.h"
#include "Show.h"

namespace {

using namespace live_range;

/*
 * Type aliases for disjoint_sets
 */
using Rank = std::unordered_map<Def, size_t>;
using Parent = std::unordered_map<Def, Def>;
using RankPMap = boost::associative_property_map<Rank>;
using ParentPMap = boost::associative_property_map<Parent>;
using DefSets = boost::disjoint_sets<RankPMap, ParentPMap>;

/*
 * Allocates a unique symbolic register for every disjoint set of defs.
 */
class SymRegMapper {
 public:
  explicit SymRegMapper(bool width_aware) : m_width_aware(width_aware) {}

  reg_t make(Def def) {
    if (m_def_to_reg.find(def) == m_def_to_reg.end()) {
      if (m_width_aware) {
        m_def_to_reg[def] = m_next_symreg;
        m_next_symreg += def->dest_is_wide() ? 2 : 1;
      } else {
        m_def_to_reg[def] = m_next_symreg++;
      }
    }
    return m_def_to_reg.at(def);
  }

  reg_t at(Def def) { return m_def_to_reg.at(def); }

  reg_t regs_size() const { return m_next_symreg; }

 private:
  bool m_width_aware;
  reg_t m_next_symreg{0};
  std::unordered_map<Def, reg_t> m_def_to_reg;
};

/*
 * Put all defs with a use in common into the same set.
 */
void unify_defs(const UseDefChains& chains, DefSets* def_sets) {
  for (const auto& chain : chains) {
    auto& defs = chain.second;
    auto it = defs.begin();
    Def first = *it;
    auto end = defs.end();
    for (++it; it != end; ++it) {
      def_sets->union_set(first, *it);
    }
  }
}

template <typename Iter, typename Fn>
void replay_analysis_with_callback(const cfg::ControlFlowGraph& cfg,
                                   const Iter& iter,
                                   Fn f) {
  for (cfg::Block* block : cfg.blocks()) {
    auto defs_in = iter.get_entry_state_at(block);
    for (const auto& mie : InstructionIterable(block)) {
      auto insn = mie.insn;
      for (src_index_t i = 0; i < insn->srcs_size(); ++i) {
        Use use{insn, i};
        auto src = insn->src(i);
        const auto& defs = defs_in.get(src);
        always_assert_log(!defs.is_top() && defs.size() > 0,
                          "Found use without def when processing [0x%p]%s",
                          &mie, SHOW(insn));
        f(use, defs);
      }
      iter.analyze_instruction(insn, &defs_in);
    }
  }
}

template <typename Iter>
UseDefChains get_use_def_chains_impl(const cfg::ControlFlowGraph& cfg,
                                     const Iter& iter) {
  UseDefChains chains;
  replay_analysis_with_callback(
      cfg, iter, [&chains](const Use& use, const reaching_defs::Domain& defs) {
        chains[use] = defs.elements();
      });
  return chains;
}

template <typename Iter>
DefUseChains get_def_use_chains_impl(const cfg::ControlFlowGraph& cfg,
                                     const Iter& iter) {
  DefUseChains chains;
  replay_analysis_with_callback(
      cfg, iter, [&chains](const Use& use, const reaching_defs::Domain& defs) {
        for (auto def : defs.elements()) {
          chains[def].emplace(use);
        }
      });
  return chains;
}

} // namespace

namespace live_range {

bool Use::operator==(const Use& that) const {
  return insn == that.insn && src_index == that.src_index;
}

Chains::Chains(const cfg::ControlFlowGraph& cfg) : m_cfg(cfg), m_fp_iter(cfg) {
  m_fp_iter.run(reaching_defs::Environment());
}

UseDefChains Chains::get_use_def_chains() const {
  return get_use_def_chains_impl(m_cfg, m_fp_iter);
}

DefUseChains Chains::get_def_use_chains() const {
  return get_def_use_chains_impl(m_cfg, m_fp_iter);
}

MoveAwareChains::MoveAwareChains(const cfg::ControlFlowGraph& cfg)
    : m_cfg(cfg), m_fp_iter(cfg) {
  m_fp_iter.run(reaching_defs::Environment());
}

UseDefChains MoveAwareChains::get_use_def_chains() const {
  return get_use_def_chains_impl(m_cfg, m_fp_iter);
}

DefUseChains MoveAwareChains::get_def_use_chains() const {
  return get_def_use_chains_impl(m_cfg, m_fp_iter);
}

void renumber_registers(IRCode* code, bool width_aware) {
  cfg::ScopedCFG cfg(code);

  auto ud_chains = Chains(*cfg).get_use_def_chains();

  Rank rank;
  Parent parent;
  DefSets def_sets((RankPMap(rank)), (ParentPMap(parent)));
  for (const auto& mie : cfg::InstructionIterable(*cfg)) {
    if (mie.insn->has_dest()) {
      def_sets.make_set(mie.insn);
    }
  }
  unify_defs(ud_chains, &def_sets);
  SymRegMapper sym_reg_mapper(width_aware);
  for (auto& mie : cfg::InstructionIterable(*cfg)) {
    auto insn = mie.insn;
    if (insn->has_dest()) {
      auto sym_reg = sym_reg_mapper.make(def_sets.find_set(insn));
      insn->set_dest(sym_reg);
    }
  }
  for (auto& mie : cfg::InstructionIterable(*cfg)) {
    auto insn = mie.insn;
    for (src_index_t i = 0; i < insn->srcs_size(); ++i) {
      auto& defs = ud_chains.at(Use{insn, i});
      insn->set_src(i, sym_reg_mapper.at(def_sets.find_set(*defs.begin())));
    }
  }
  cfg->set_registers_size(sym_reg_mapper.regs_size());
}

} // namespace live_range


/*
 * This file is part of the DUDS project. It is subject to the BSD-style
 * license terms in the LICENSE file found in the top-level directory of this
 * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
 * No part of DUDS, including this file, may be copied, modified, propagated,
 * or distributed except according to the terms contained in the LICENSE file.
 *
 * Copyright (C) 2017  Jeff Jackowski
 */
#ifndef EXTENDEDUNIT_HPP
#define EXTENDEDUNIT_HPP

#include <duds/general/Errors.hpp>
#include <duds/data/Unit.hpp>
#include <boost/serialization/split_member.hpp>

namespace duds { namespace data {

// needed for celsius, liter

/**
 * redo: Use floats for scale and offset. Use 32-bits for 10 3-bit and 1 2-bit
 *       additional unit flags (put relative humidity there?), and a Unit.
 *       Should be 16 bytes, 128-bits. Include in GenericValue.
 */
class ExtendedUnit {
	Unit unit;
	union {
		/**
		 * A scaling and offset value packed into four bytes. The scalar works
		 * for most of the metric prefixes. The offset works for 273.15. All this
		 * fits in the space of a single float. The offset needs more precision
		 * than a half (from IEEE 754).
		 */
		std::uint32_t scaloff;
		struct {
			/**
			 * The mantissa, save for the impled leading bit.
			 */
			unsigned int mant  : 20;
			/**
			 * The exponent as a signed integer rather than unsigned with bias.
			 */
			int exp            : 7;
			/**
			 * The sign flag.
			 */
			int sign           : 1;
			/**
			 * A value used to represnt most SI prefixes. The prefixes
			 * represent a scalar value. To produce this prefix scalar,
			 * multiply @a scale by three, then rasie ten to the power of
			 * the product. Kilograms has a prefix built into the base unit
			 * resulting in inconsistency. This scalar modifies kilo in
			 * kilograms. Thus, if @a unit is Kilogram, then a @a scale of -1
			 * produces the unit gram.
			 */
			int scale : 4;
		};
	};
	// serialization support
	friend class boost::serialization::access;
	template <class A>
	void save(A &a, const unsigned int) const {
		a & BOOST_SERIALIZATION_NVP(unit);
		// prevent differences in bitfields across platforms from causing
		// different values for scaloff; assume for now that the archive will
		// handle endianness differences
		std::uint32_t packed = mant | (exp << 20) | (sign << 27) | (scale << 28);
		a & BOOST_SERIALIZATION_NVP(packed);
	}
	template <class A>
	void load(A &a, const unsigned int) {
		a & BOOST_SERIALIZATION_NVP(unit);
		std::uint32_t packed;
		a & BOOST_SERIALIZATION_NVP(packed);
		// prevent differences in bitfields across platforms from causing
		// different values for scaloff; assume for now that the archive will
		// handle endianness differences
		mant = packed & 0xFFFFF;
		exp = (packed >> 20) & 0x7F;
		sign = (packed >> 27) & 1;
		scale = packed >> 28;
	}
	BOOST_SERIALIZATION_SPLIT_MEMBER();
	/**
	 * An simple internal constructor that takes the values of it members.
	 * @todo  Maybe make this public along with some macro to set @a s? Doing
	 *        so would allow easy creation of constant ExtendedUnit objects,
	 *        like the Units in Units.hpp. May have to specify the offset it
	 *        pieces, though.
	 */
	constexpr ExtendedUnit(Unit u, std::uint32_t s) : unit(u), scaloff(s) { }
public:
	/**
	 * Makes an uninitialized ExtendedUnit.
	 */
	ExtendedUnit() = default;
	/**
	 * Makes a copy.
	 */
	ExtendedUnit(const ExtendedUnit &) = default;
	/**
	 * Makes an ExtendedUnit that is equivalent to the given base Unit.
	 * @param u  The base unit.
	 */
	constexpr ExtendedUnit(Unit u) : unit(u), scaloff(0) { }
	/**
	 * Constructs an ExtendedUnit with the given values.
	 * @tparam O  The offset type; must be either @a float or @a double. In most
	 *            cases, the compiler should deduce this type.
	 * @param  u  The initial Unit value.
	 * @param  o  The initial offset value.
	 * @param  s  The initial scalar value.
	 * @todo   Document the offset and scalar better.
	 * @throw  UnitRangeError  Either the scalar or offset value is beyond the
	 *                         bounds of the internal storage.
	 */
	template <typename O>
	ExtendedUnit(Unit u, O o, int s) : unit(u), scale(s) {
		if ((s > 7) || (s < -8)) {
			DUDS_THROW_EXCEPTION(UnitRangeError());
		}
		offset(o);
	}
	/**
	 * True if the unit represented by this object can also be represented by
	 * a Unit object.
	 */
	bool canConvertToUnit() const;
	/**
	 * Change the offset.
	 * @param o  The new offset. Is must not be subnormal, infinite, or NaN.
	 * @throw  UnitRangeError  The offset value is beyond the bounds of the
	 *                         internal storage.
	 */
	void offset(float o);
	/**
	 * Query the offset as a float.
	 */
	float offsetf() const;
	/**
	 * Change the offset.
	 * @param o  The new offset. Is must not be subnormal, infinite, or NaN.
	 * @throw  UnitRangeError  The offset value is beyond the bounds of the
	 *                         internal storage.
	 */
	void offset(double o);
	/**
	 * Query the offset as a double.
	 */
	double offset() const;
	/**
	 * Returns the base unit as a Unit object.
	 */
	const Unit &base() const {
		return unit;
	}
	/**
	 * Returns the exponent for the ampere (current) dimension.
	 */
	int ampere() const {
		return unit.ampere();
	}
	/**
	 * Returns the exponent for the candela (luminous intensity) dimension.
	 */
	int candela() const {
		return unit.candela();
	}
	/**
	 * Returns the exponent for the kelvin (thermodynamic temperature) dimension.
	 */
	int kelvin() const {
		return unit.kelvin();
	}
	/**
	 * Returns the exponent for the kilogram (mass) dimension.
	 */
	int kilogram() const {
		return unit.kilogram();
	}
	/**
	 * Returns the exponent for the meter (distance) dimension.
	 */
	int meter() const {
		return unit.meter();
	}
	/**
	 * Returns the exponent for the mole (amount of substance) dimension.
	 */
	int mole() const {
		return unit.mole();
	}
	/**
	 * Returns the exponent for the second (time) dimension.
	 */
	int second() const {
		return unit.second();
	}
	/**
	 * Returns the exponent for radians (angle).
	 */
	int radian() const {
		return unit.radian();
	}
	/**
	 * Returns the exponent for steradians (solid angle).
	 */
	int steradian() const {
		return unit.steradian();
	}
	/**
	 * Returns the exponent for the ampere (current) dimension.
	 */
	int amp() const {
		return unit.ampere();
	}
	/**
	 * Returns the exponent for the meter (distance) dimension.
	 */
	int metre() const {
		return unit.meter();
	}
	/**
	 * Returns the exponent for the ampere (current) dimension.
	 */
	int A() const {
		return unit.ampere();
	}
	/**
	 * Returns the exponent for the candela (luminous intensity) dimension.
	 */
	int cd() const {
		return unit.candela();
	}
	/**
	 * Returns the exponent for the kelvin (thermodynamic temperature) dimension.
	 */
	int K() const {
		return unit.kelvin();
	}
	/**
	 * Returns the exponent for the kilogram (mass) dimension.
	 */
	int kg() const {
		return unit.kilogram();
	}
	/**
	 * Returns the exponent for the meter (distance) dimension.
	 */
	int m() const {
		return unit.meter();
	}
	/**
	 * Returns the exponent for the mole (amount of substance) dimension.
	 */
	int mol() const {
		return unit.mole();
	}
	/**
	 * Returns the exponent for the second (time) dimension.
	 */
	int s() const {
		return unit.second();
	}
	/**
	 * Returns the exponent for radians (angle).
	 */
	int rad() const {
		return unit.radian();
	}
	/**
	 * Returns the exponent for steradians (solid angle).
	 */
	int sr() const {
		return unit.steradian();
	}
	/**
	 * Sets the exponent for the ampere (current) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void ampere(int e) {
		unit.ampere(e);
	}
	/**
	 * Sets the exponent for the candela (luminous intensity) dimension without
	 * range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void candela(int e) {
		unit.candela(e);
	}
	/**
	 * Sets the exponent for the kelvin (thermodynamic temperature) dimension
	 * without range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void kelvin(int e) {
		unit.kelvin(e);
	}
	/**
	 * Sets the exponent for the ampere (current)kilogram (mass) dimension without
	 * range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void kilogram(int e) {
		unit.kilogram(e);
	}
	/**
	 * Sets the exponent for the meter (distance) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void meter(int e) {
		unit.meter(e);
	}
	/**
	 * Sets the exponent for the mole (amount of substance) dimension without
	 * range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void mole(int e) {
		unit.mole(e);
	}
	/**
	 * Sets the exponent for the second (time) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void second(int e) {
		unit.second(e);
	}
	/**
	 * Sets the exponent for radians (angle) without range checking.
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 */
	void radian(int e) {
		unit.radian(e);
	}
	/**
	 * Sets the exponent for steradians (solid angle) without range checking.
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 */
	void steradian(int e) {
		unit.steradian(e);
	}
	/**
	 * Sets the exponent for the ampere (current) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void amp(int e) {
		unit.ampere(e);
	}
	/**
	 * Sets the exponent for the meter (distance) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void metre(int e) {
		unit.meter(e);
	}
	/**
	 * Sets the exponent for the ampere (current) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void A(int e) {
		unit.ampere(e);
	}
	/**
	 * Sets the exponent for the candela (luminous intensity) dimension without
	 * range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void cd(int e) {
		unit.candela(e);
	}
	/**
	 * Sets the exponent for the kelvin (thermodynamic temperature) dimension
	 * without range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void K(int e) {
		unit.kelvin(e);
	}
	/**
	 * Sets the exponent for the kilogram (mass) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void kg(int e) {
		unit.kilogram(e);
	}
	/**
	 * Sets the exponent for the meter (distance) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void m(int e) {
		unit.meter(e);
	}
	/**
	 * Sets the exponent for the mole (amount of substance) dimension without
	 * range checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void mol(int e) {
		unit.mole(e);
	}
	/**
	 * Sets the exponent for the second (time) dimension without range
	 * checking.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 */
	void s(int e) {
		second(e);
	}
	/**
	 * Sets the exponent for radians (angle) without range checking.
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 */
	void rad(int e) {
		unit.radian(e);
	}
	/**
	 * Sets the exponent for steradians (solid angle) without range checking.
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 */
	void sr(int e) {
		unit.steradian(e);
	}
	/**
	 * Sets the exponent for the ampere (current) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setAmpere(int e) {
		unit.setAmpere(e);
	}
	/**
	 * Sets the exponent for the candela (luminous intensity) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setCandela(int e) {
		unit.setCandela(e);
	}
	/**
	 * Sets the exponent for the kelvin (thermodynamic temperature) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setKelvin(int e) {
		unit.setKelvin(e);
	}
	/**
	 * Sets the exponent for the kilogram (mass) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setKilogram(int e) {
		unit.setKilogram(e);
	}
	/**
	 * Sets the exponent for the meter (distance) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setMeter(int e) {
		unit.setMeter(e);
	}
	/**
	 * Sets the exponent for the mole (amount of substance) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setMole(int e) {
		unit.setMole(e);
	}
	/**
	 * Sets the exponent for the second (time) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setSecond(int e) {
		unit.setSecond(e);
	}
	/**
	 * Sets the exponent for radians (angle).
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setRadian(int e) {
		unit.setRadian(e);
	}
	/**
	 * Sets the exponent for steradians (solid angle).
	 * @param e  The exponent in a range between -2 to 1, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setSteradian(int e) {
		unit.setSteradian(e);
	}
	/**
	 * Sets the exponent for the ampere (current) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setAmp(int e) {
		unit.setAmpere(e);
	}
	/**
	 * Sets the exponent for the meter (distance) dimension.
	 * @param e  The exponent in a range between -8 to 7, inclusive.
	 * @throw UnitRangeError  The exponent @a e is out of range.
	 */
	void setMetre(int e) {
		unit.setMeter(e);
	}
	/**
	 * Returns true if the object represents no units. This is normal for some
	 * values, such as ratios.
	 */
	bool unitless() const {
		return unit.unitless();
	}
	/**
	 * Combines two units into a new unit.
	 * @throw UnitRangeError  A resulting exponent is out of range.
	 */
	const ExtendedUnit operator * (const Unit &U) const;
	/**
	 * Combines two units into a new unit.
	 * @throw UnitRangeError  A resulting exponent is out of range.
	 */
	const ExtendedUnit operator / (const Unit &U) const;
	/**
	 * Combines two units into a new unit.
	 * @throw UnitRangeError  A resulting exponent is out of range. All
	 *                           work is done on a temporary so that if an
	 *                           exception is thrown only the temporary is
	 *                           modified.
	 */
	ExtendedUnit &operator *= (const Unit &U);
	/**
	 * Combines two units into a new unit.
	 * @throw UnitRangeError  A resulting exponent is out of range. All
	 *                           work is done on a temporary so that if an
	 *                           exception is thrown only the temporary is
	 *                           modified.
	 */
	ExtendedUnit &operator /= (const Unit &U);
	/**
	 * Makes this extended unit equivalent to the given Unit object.
	 */
	ExtendedUnit &operator = (const Unit &U);
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator < (const ExtendedUnit &U) const {
		return ((unit == U.unit) && (scaloff < U.scaloff)) || (unit < U.unit);
	}
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator > (const ExtendedUnit &U) const {
		return ((unit == U.unit) && (scaloff > U.scaloff)) || (unit > U.unit);
	}
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator <= (const ExtendedUnit &U) const {
		return ((unit == U.unit) && (scaloff <= U.scaloff)) || (unit <= U.unit);
	}
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator >= (const ExtendedUnit &U) const {
		return ((unit == U.unit) && (scaloff >= U.scaloff)) || (unit >= U.unit);
	}
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator == (const ExtendedUnit &U) const {
		return (unit == U.unit) && (scaloff == U.scaloff);
	}
	/**
	 * Unit objects are compared using the @a u member.
	 */
	bool operator != (const ExtendedUnit &U) const {
		return (unit != U.unit) || (scaloff != U.scaloff);
	}
};

/**
 * An idea that is not yet implemented; <b>DO NOT USE</b>.
 */
template <class Q = double>
struct ExtendedQuantity {
	Q value;
	ExtendedUnit unit;
private:
	// serialization support
	friend class boost::serialization::access;
	template <class A>
	void serialize(A &a, const unsigned int) {
		a & BOOST_SERIALIZATION_NVP(value);
		a & BOOST_SERIALIZATION_NVP(unit);
	}
};

} }

#endif        //  #ifndef EXTENDEDUNIT_HPP


//#define GraphicalModelDecomposition AStarInference_GraphicalModelDecomposition

#include <boost/python.hpp>
#include <string>
#include "inf_def_visitor.hxx"

#include <opengm/inference/astar.hxx>
#include <param/astar_param.hxx>

using namespace boost::python;

template<class GM,class ACC>
void export_astar(){
   using namespace boost::python;
   import_array();
   append_subnamespace("solver");

   // setup
   InfSetup setup;
   setup.cite       = "Kappes, J. H. :\"Inference on Highly-Connected Discrete Graphical Models with Applications to Visual Object Recognition \","
   "Ph.D. Thesis 2011.\n\n"
   "Bergtholdt, M. & Kappes, J. H. & Schnoerr, C.:\"`Learning of Graphical Models and Efficient Inference for Object Class Recognition"
   " <http://hci.iwr.uni-heidelberg.de/Staff/jkappes/publications/dagm2006.pdf>`_\","
   "  DAGM 2006\n\n"
   "Bergtholdt, M. & Kappes, J. H. & Schmidt, S. & Schnoerr, C.: \"`A Study of Parts-Based Object Class Detection Using Complete Graphs"
   " <https://www.inf.tu-dresden.de/content/institutes/ki/is/HS_SS09_Papers/A_Study_of_Parts_Based_Object_Class_Detection_Using_Complete_Graphs.pdf>`_\","
   "  DAGM 2006";
   setup.notes     =
   "The AStar-Algo transform the problem into a shortest path problem in an exponentially large graph.\n\n"
   "Due to the problem structure, this graph can be represented implicitly!\n\n"
   "To find the shortest path we perform a best first search and use a admissable tree-based heuristic\n\n"
   "to underestimate the cost to a goal node.\n\n"
   "This lower bound allows us to reduce the search to an manageable \n\n"
   "subspace of the exponentially large search-space. ";
   setup.algType     = "searching";
   setup.guarantees  = "global optimal";
   setup.limitations = "graphical model must be small";
   setup.examples   = ">>> parameter = opengm.InfParam(heuristic='fast')\n"
                      ">>> inference = opengm.inference.AStar(gm=gm,accumulator='minimizer',parameter=parameter)\n"
                      "\n\n";
                      ;
   // export parameter
   typedef opengm::AStar<GM, ACC>  PyAStar;
   exportInfParam<PyAStar>("_AStar");
   // export inference
   class_< PyAStar>("_AStar",init<const GM & >())
   .def(InfSuite<PyAStar>(std::string("AStar"),setup))
   ;
}

template void export_astar<opengm::python::GmAdder, opengm::Minimizer>();
template void export_astar<opengm::python::GmAdder, opengm::Maximizer>();
template void export_astar<opengm::python::GmMultiplier, opengm::Minimizer>();
template void export_astar<opengm::python::GmMultiplier, opengm::Maximizer>();


// Boost.Geometry

// Copyright (c) 2021 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html

#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP

#include <vector>

#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/distance_result.hpp>

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{

template <typename Geometry, typename GeometryCollection, typename Strategies>
inline auto geometry_to_collection(Geometry const& geometry,
                                   GeometryCollection const& collection,
                                   Strategies const& strategies)
{
    using result_t = typename geometry::distance_result<Geometry, GeometryCollection, Strategies>::type;
    result_t result = 0;
    bool is_first = true;
    detail::visit_breadth_first([&](auto const& g)
    {
        result_t r = dispatch::distance
                        <
                            Geometry, util::remove_cref_t<decltype(g)>, Strategies
                        >::apply(geometry, g, strategies);
        if (is_first)
        {
            result = r;
            is_first = false;
        }
        else if (r < result)
        {
            result = r;
        }
        return result > result_t(0);
    }, collection);

    return result;
}

template <typename GeometryCollection1, typename GeometryCollection2, typename Strategies>
inline auto collection_to_collection(GeometryCollection1 const& collection1,
                                     GeometryCollection2 const& collection2,
                                     Strategies const& strategies)
{
    using result_t = typename geometry::distance_result<GeometryCollection1, GeometryCollection2, Strategies>::type;

    using point1_t = typename geometry::point_type<GeometryCollection1>::type;
    using box1_t = model::box<point1_t>;
    using point2_t = typename geometry::point_type<GeometryCollection2>::type;
    using box2_t = model::box<point2_t>;

    using rtree_value_t = std::pair<box1_t, typename boost::range_iterator<GeometryCollection1 const>::type>;
    using rtree_params_t = index::parameters<index::rstar<4>, Strategies>;
    using rtree_t = index::rtree<rtree_value_t, rtree_params_t>;

    rtree_params_t rtree_params(index::rstar<4>(), strategies);
    rtree_t rtree(rtree_params);

    // Build rtree of boxes and iterators of elements of GC1
    // TODO: replace this with visit_breadth_first_iterator to avoid creating an unnecessary container?
    {
        std::vector<rtree_value_t> values;
        visit_breadth_first_impl<true>::apply([&](auto & g1, auto it)
        {
            box1_t b1 = geometry::return_envelope<box1_t>(g1, strategies);
            geometry::detail::expand_by_epsilon(b1);
            values.emplace_back(b1, it);
            return true;
        }, collection1);
        rtree_t rt(values.begin(), values.end(), rtree_params);
        rtree = std::move(rt);
    }

    result_t const zero = 0;
    auto const rtree_qend = rtree.qend();

    result_t result = 0;
    bool is_first = true;
    visit_breadth_first([&](auto const& g2)
    {
        box2_t b2 = geometry::return_envelope<box2_t>(g2, strategies);
        geometry::detail::expand_by_epsilon(b2);

        for (auto it = rtree.qbegin(index::nearest(b2, rtree.size())) ; it != rtree_qend ; ++it)
        {
            // If the distance between boxes is greater than or equal to previously found
            // distance between geometries then stop processing the current b2 because no
            // closer b1 will be found
            if (! is_first)
            {
                result_t const bd = dispatch::distance
                    <
                        box1_t, box2_t, Strategies
                    >::apply(it->first, b2, strategies);
                if (bd >= result)
                {
                    break;
                }
            }

            // Boxes are closer than the previously found distance (or it's the first time),
            // calculate the new distance between geometries and check if it's closer (or assign it).
            traits::iter_visit<GeometryCollection1>::apply([&](auto const& g1)
            {
                result_t const d = dispatch::distance
                    <
                        util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>,
                        Strategies
                    >::apply(g1, g2, strategies);
                if (is_first)
                {
                    result = d;
                    is_first = false;
                }
                else if (d < result)
                {
                    result = d;
                }
            }, it->second);

            // The smallest possible distance found, end searching.
            if (! is_first && result <= zero)
            {
                return false;
            }
        }

        // Just in case
        return is_first || result > zero;
    }, collection2);

    return result;
}

}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename Geometry, typename GeometryCollection, typename Strategies, typename Tag1
>
struct distance
    <
        Geometry, GeometryCollection, Strategies,
        Tag1, geometry_collection_tag, void, false
    >
{
    static inline auto apply(Geometry const& geometry,
                             GeometryCollection const& collection,
                             Strategies const& strategies)
    {
        assert_dimension_equal<Geometry, GeometryCollection>();

        return detail::distance::geometry_to_collection(geometry, collection, strategies);
    }
};

template
<
    typename GeometryCollection, typename Geometry, typename Strategies, typename Tag2
>
struct distance
    <
        GeometryCollection, Geometry, Strategies,
        geometry_collection_tag, Tag2, void, false
    >
{
    static inline auto apply(GeometryCollection const& collection,
                             Geometry const& geometry,
                             Strategies const& strategies)
    {
        assert_dimension_equal<Geometry, GeometryCollection>();

        return detail::distance::geometry_to_collection(geometry, collection, strategies);
    }
};

template
<
    typename GeometryCollection1, typename GeometryCollection2, typename Strategies
>
struct distance
    <
        GeometryCollection1, GeometryCollection2, Strategies,
        geometry_collection_tag, geometry_collection_tag, void, false
    >
{
    static inline auto apply(GeometryCollection1 const& collection1,
                             GeometryCollection2 const& collection2,
                             Strategies const& strategies)
    {
        assert_dimension_equal<GeometryCollection1, GeometryCollection2>();

        // Build the rtree for the smaller GC (ignoring recursive GCs)
        return boost::size(collection1) <= boost::size(collection2)
             ? detail::distance::collection_to_collection(collection1, collection2, strategies)
             : detail::distance::collection_to_collection(collection2, collection1, strategies);
    }
};

} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP


/*!
*	@file	libpsalm.cpp
*	@brief	Exports a function for filling holes in meshes. Used by GigaMesh.
*	@author	Bastian Rieck <bastian.rieck@iwr.uni-heidelberg.de>
*/

#include <sstream>
#include <string>
#include <vector>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>

#include "libpsalm.h"
#include "mesh.h"

#include "SubdivisionAlgorithms/Liepa.h"
#include "TriangulationAlgorithms/MinimumWeightTriangulation.h"

/*!
*	Generates a filename by creating a UUID and attaching the extension
*	onto it. This function is used for debugging purposes in order to save
*	auxiliary results of the triangulation.
*
*	@param	extension File extension
*	@return UUID.extension as a filename
*/

std::string generate_filename(std::string extension = "ply")
{
	boost::uuids::uuid uuid = boost::uuids::random_generator()();

	std::stringstream converter;
	converter << uuid << "." << extension;

	return(converter.str());
}

/*!
*	Given a polygonal line described as a list of vertices, this function
*	triangulates the hole and subdivides it. Afterwards, the new data is
*	stored in some arrays given as parameters of the caller.
*
*	@param num_vertices	Number of vertices in polygonal line
*
*	@param vertex_IDs	List of vertex IDs, used to identify them. If
*				this parameter is NULL, the mesh class will
*				assign sequential vertex IDs, starting with 0.
*
*	@param coordinates	Array of vertex coordinates (size: 3*num_vertices)
*
*	@param scale_attributes	Array of scale attributes (size: num_vertices).
*				The scale attribute is the average length of all
*				edges incident on the vertex. This parameter is
*				used for the subdivision algorithm. If the pointer
*				is NULL, the scale attributes will not be initialized
*				but the algorithm will still work.
*
*	@param normals		Array of vertex normals (size: 3*num_vertices)
*
*	@param num_new_vertices	Number of new vertices created by the algorithm
*
*	@param new_coordinates	Array of vertex coordinates created by the
*				algorithm (size: 3*num_new_vertices)
*
*	@param num_new_faces	Number of new faces created by the algorithm
*
*	@param new_vertex_IDs	List of vertex IDs for the new faces (size:
*				3*num_new_faces). Negative IDs signify that the
*				vertex is _not_ new.
*
*	The nomenclature here might be confusing: new_vertex_IDs contains 3
*	vertex IDs that describe a new face created by the algorithm.
*
*	@returns true if the hole could be filled, otherwise false
*/

bool fill_hole(	int num_vertices, long* vertex_IDs, double* coordinates, double* scale_attributes, double* normals,
		int* num_new_vertices, double** new_coordinates, int* num_new_faces, long** new_vertex_IDs)
{
	bool result = true;
	if(	num_vertices == 0		||
		coordinates == NULL		||
		num_new_vertices == NULL	||
		new_coordinates == NULL		||
		num_new_faces == NULL		||
		new_vertex_IDs == NULL)
		return(false);

	psalm::mesh M;

	psalm::Liepa liepa_algorithm;
	psalm::MinimumWeightTriangulation triangulation_algorithm;

	result = M.load_raw_data(	num_vertices,
					vertex_IDs,
					coordinates,
					scale_attributes,
					normals);

	if(!result)
	{
		std::cerr << "libpsalm: Data processing failed for fill_hole() failed" << std::endl;
		return(false);
	}

	result = (result && triangulation_algorithm.apply_to(M));				// step 1: triangulate the hole
	result = (result && liepa_algorithm.apply_to(M));					// step 2: apply Liepa's subdivision scheme with
												// default parameters

	if(result)
	{
		M.save_raw_data(num_new_vertices,
				new_coordinates,
				num_new_faces,
				new_vertex_IDs);

		#ifdef DEBUG
			M.save(generate_filename());
		#endif
	}

	// signal an error for the calling function
	else
	{
		*num_new_vertices	= 0;
		*num_new_faces		= 0;
	}

	return(result);
}