Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "trop_borders.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg_wrap.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcg/tcg_point.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_cyclic.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_containers_reader.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define INCLUDE_HPP
Toshihiro Shimizu 890ddd
#include "tcg/tcg_triangulate.h"
Toshihiro Shimizu 890ddd
#undef INCLUDE_HPP
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#define INCLUDE_HPP
Toshihiro Shimizu 890ddd
#include "../common/trop/raster_edge_evaluator.h"
Toshihiro Shimizu 890ddd
#undef INCLUDE_HPP
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "ext/meshbuilder.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct PolygonVertex {
Shinya Kitaoka 120a6e
  double m_pos[3];
Shinya Kitaoka 120a6e
  int m_idx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  PolygonVertex(const TPoint &p) : m_idx(-1) {
Shinya Kitaoka 120a6e
    m_pos[0] = p.x, m_pos[1] = p.y, m_pos[2] = 0.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    tcg  stuff
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace tcg {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Toshihiro Shimizu 890ddd
struct traits<ttexturemeshp> {</ttexturemeshp>
Shinya Kitaoka 120a6e
  typedef TTextureMeshP *pointer_type;
Shinya Kitaoka 120a6e
  typedef TTextureMeshP *&reference_type;
Shinya Kitaoka 120a6e
  typedef TTextureMesh pointed_type;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <>
Toshihiro Shimizu 890ddd
struct point_traits<polygonvertex> {</polygonvertex>
Shinya Kitaoka 120a6e
  typedef PolygonVertex point_type;
Shinya Kitaoka 120a6e
  typedef double value_type;
Shinya Kitaoka 120a6e
  typedef double float_type;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  inline static value_type x(const point_type &p) { return p.m_pos[0]; }
Shinya Kitaoka 120a6e
  inline static value_type y(const point_type &p) { return p.m_pos[1]; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace tcg
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    MeshBuilder Locals
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
//    Thresholding  stuff
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
void thresholdRaster(const TRasterPT<pix> &ras, TRasterGR8P &out,</pix>
Shinya Kitaoka 120a6e
                     const Pix &transp) {
Shinya Kitaoka 120a6e
  int lx = ras->getLx(), y, ly = ras->getLy();
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    Pix *pix, *line = ras->pixels(y), *lineEnd = line + lx;
Shinya Kitaoka 120a6e
    TPixelGR8 *gr, *grLine = out->pixels(y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr)
Shinya Kitaoka 120a6e
      gr->value = (pix->m && *pix != transp) ? 0 : 255;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix=""></typename>
Shinya Kitaoka 120a6e
void thresholdRasterGr(const TRasterPT<pix> &ras, TRasterGR8P &out,</pix>
Shinya Kitaoka 120a6e
                       const Pix &transp) {
Shinya Kitaoka 120a6e
  int lx = ras->getLx(), y, ly = ras->getLy();
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    Pix *pix, *line = ras->pixels(y), *lineEnd = line + lx;
Shinya Kitaoka 120a6e
    TPixelGR8 *gr, *grLine = out->pixels(y);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr)
Shinya Kitaoka 120a6e
      gr->value = (*pix != transp) ? 0 : 255;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void thresholdRasterCM32(const TRasterCM32P &ras, TRasterGR8P &out) {
Shinya Kitaoka 120a6e
  int lx = ras->getLx(), y, ly = ras->getLy();
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    TPixelCM32 *pix, *line = ras->pixels(y), *lineEnd = line + lx;
Shinya Kitaoka 120a6e
    TPixelGR8 *gr, *grLine = out->pixels(y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr)
Shinya Kitaoka 120a6e
      gr->value = (pix->isPurePaint() && !pix->getPaint()) ? 255 : 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRasterGR8P thresholdRaster(const TRasterP &ras,
Shinya Kitaoka 120a6e
                            const MeshBuilderOptions &opts) {
Shinya Kitaoka 120a6e
  TRasterGR8P binaryRas(ras->getLx(), ras->getLy());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterCM32P rasCM(ras);
Shinya Kitaoka 120a6e
  if (rasCM)
Shinya Kitaoka 120a6e
    thresholdRasterCM32(rasCM, binaryRas);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    switch (ras->getPixelSize()) {
Shinya Kitaoka 120a6e
    case 1: {
Shinya Kitaoka 120a6e
      TRasterGR8P rasGR8(ras);
Shinya Kitaoka 120a6e
      thresholdRasterGr(rasGR8, binaryRas,
Shinya Kitaoka 120a6e
                        TPixelGR8::from(toPixel32(opts.m_transparentColor)));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case 2: {
Shinya Kitaoka 120a6e
      TRasterGR16P rasGR16(ras);
Shinya Kitaoka 120a6e
      thresholdRasterGr(rasGR16, binaryRas,
Shinya Kitaoka 120a6e
                        TPixelGR16::from(opts.m_transparentColor));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case 4: {
Shinya Kitaoka 120a6e
      TRaster32P ras32(ras);
Shinya Kitaoka 120a6e
      thresholdRaster(ras32, binaryRas, toPixel32(opts.m_transparentColor));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case 8: {
Shinya Kitaoka 120a6e
      TRaster64P ras64(ras);
Shinya Kitaoka 120a6e
      thresholdRaster(ras64, binaryRas, opts.m_transparentColor);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    default:
Shinya Kitaoka 120a6e
      assert(false);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build an enlarged ras to preserve borders. 5 pixels should be fine.
Shinya Kitaoka 120a6e
  TRasterGR8P result(ras->getLx(), ras->getLy());
Shinya Kitaoka 120a6e
  TRop::blur(result, binaryRas, opts.m_margin, 0, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  thresholdRasterGr(result, result, TPixelGR8::White);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
//    Borders Extraction  stuff
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace TRop::borders;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka 120a6e
inline void delete_(T t) {
Shinya Kitaoka 120a6e
  delete t;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename t=""></typename>
Shinya Kitaoka d1f6c4
struct Vector final : public std::vector<t> {</t>
Shinya Kitaoka 120a6e
  Vector() : std::vector<t>() {}</t>
Shinya Kitaoka 120a6e
  ~Vector() { std::for_each(this->begin(), this->end(), delete_<t>); }</t>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::vector<tpoint> RasterBorder;</tpoint>
Toshihiro Shimizu 890ddd
typedef std::vector<polygonvertex> Polygon;</polygonvertex>
Toshihiro Shimizu 890ddd
typedef Vector<polygon *=""> Family;</polygon>
Toshihiro Shimizu 890ddd
typedef Vector<family *=""> Tribe;</family>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct PolygonReader {
Shinya Kitaoka 120a6e
  Polygon *m_polygon;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef tcg::cyclic_iterator<rasterborder::iterator> cyclic_iter;</rasterborder::iterator>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  PolygonReader() : m_polygon(0) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void openContainer(const cyclic_iter &ct) {
Shinya Kitaoka 120a6e
    m_polygon = new Polygon;
Shinya Kitaoka 120a6e
    m_polygon->push_back(PolygonVertex(*ct));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void addElement(const cyclic_iter &ct) {
Shinya Kitaoka 120a6e
    m_polygon->push_back(PolygonVertex(*ct));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void closeContainer() {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class BordersReader final : public ImageMeshesReaderT<tpixelgr8> {</tpixelgr8>
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  Vector<rasterborder *=""> m_borders;</rasterborder>
Shinya Kitaoka 120a6e
  RasterBorder *m_current;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  BordersReader()
Shinya Kitaoka 120a6e
      : ImageMeshesReaderT<tpixelgr8>(PixelSelector<tpixelgr8>(false))</tpixelgr8></tpixelgr8>
Shinya Kitaoka 120a6e
      , m_current(0) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void openFace(ImageMesh *mesh, int faceIdx, const TPixelGR8 &color) override {
Shinya Kitaoka 120a6e
    ImageMeshesReader::openFace(mesh, faceIdx);  // defines imageIndex
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (mesh) {
Shinya Kitaoka 120a6e
      ImageMesh::face_type &fc = mesh->face(faceIdx);
Shinya Kitaoka 120a6e
      fc.imageIndex()          = (color.value) ? 0 : 1;  // redefines iI
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void openEdge(const raster_edge_iterator &it) override {
Shinya Kitaoka 120a6e
    m_current = new RasterBorder;
Shinya Kitaoka 120a6e
    m_current->push_back(it.pos());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void addVertex(const raster_edge_iterator &it) override {
Shinya Kitaoka 120a6e
    m_current->push_back(it.pos());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void closeEdge(ImageMesh *mesh, int edgeIdx) override {
Shinya Kitaoka 120a6e
    ImageMesh::edge_type &ed = mesh->edge(edgeIdx);
Shinya Kitaoka 120a6e
    ed.imageIndex()          = m_borders.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_borders.push_back(m_current);
Shinya Kitaoka 120a6e
    m_current = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ImageMeshesReader::closeEdge(mesh, edgeIdx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Polygon *reduceBorder(RasterBorder *border) {
Shinya Kitaoka 120a6e
  typedef RasterBorder::iterator iter;
Shinya Kitaoka 120a6e
  typedef tcg::cyclic_iterator<iter> cyclic_iter;</iter>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  iter b(border->begin()), e(border->end());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  cyclic_iter cBegin(b, b, e - 1, 0), cEnd(b + 1, b, e - 1, 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  RasterEdgeEvaluator<cyclic_iter> eval(cBegin - 1, cEnd + 1, 2.0,</cyclic_iter>
Shinya Kitaoka 120a6e
                                        (std::numeric_limits<double>::max)());</double>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  PolygonReader reader;
Shinya Kitaoka 120a6e
  tcg::sequence_ops::minimalPath(cBegin, cEnd, eval, reader);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return reader.m_polygon;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void reduceBorders(Tribe *tribe, const ImageMeshesReader &reader,
Shinya Kitaoka 120a6e
                   const Vector<rasterborder *=""> &borders, int meshIdx,</rasterborder>
Shinya Kitaoka 120a6e
                   const ImageMesh::face_type &fc) {
Shinya Kitaoka 120a6e
  // Traverse the image structure. Each time a black face is encountered, add
Shinya Kitaoka 120a6e
  // its associated family to the
Shinya Kitaoka 120a6e
  // resulting tribe.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const tcg::list<imagemeshp> &meshes = reader.meshes();</imagemeshp>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (meshIdx >= 0 && fc.imageIndex()) {
Shinya Kitaoka 120a6e
    // Build a family. Start by extracting the face's contour
Shinya Kitaoka 120a6e
    Family *family = new Family;
Shinya Kitaoka 120a6e
    tribe->push_back(family);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const ImageMeshP &mesh = meshes[meshIdx];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    Polygon *outerBorder = reduceBorder(borders[mesh->edge(0).imageIndex()]);
Shinya Kitaoka 120a6e
    family->push_back(outerBorder);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Then, extract the contours of every sub-mesh
Shinya Kitaoka 120a6e
    int m, mCount = fc.meshesCount();
Shinya Kitaoka 120a6e
    for (m = 0; m < mCount; ++m) {
Shinya Kitaoka 120a6e
      int mIdx                    = fc.mesh(m);
Shinya Kitaoka 120a6e
      const ImageMeshP &childMesh = meshes[mIdx];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      Polygon *innerBorder =
Shinya Kitaoka 120a6e
          reduceBorder(borders[childMesh->edge(0).imageIndex()]);
Shinya Kitaoka 120a6e
      family->push_back(innerBorder);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      reduceBorders(tribe, reader, borders, mIdx, childMesh->face(0));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Recursive on the face's sub-mesh faces
Shinya Kitaoka 120a6e
  int m, mCount = fc.meshesCount();
Shinya Kitaoka 120a6e
  for (m = 0; m < mCount; ++m) {
Shinya Kitaoka 120a6e
    int mIdx = fc.mesh(m);
Shinya Kitaoka 120a6e
    reduceBorders(tribe, reader, borders, mIdx, meshes[mIdx]->face(0));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Tribe *extractBorders(const TRasterGR8P &ras) {
Shinya Kitaoka 120a6e
  Tribe *result = new Tribe;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  BordersReader reader;
Shinya Kitaoka 120a6e
  TRop::borders::readMeshes(ras, reader);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  reduceBorders(result, reader, reader.m_borders, -1, reader.outerFace());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
//    Maximum Edge Length  stuff
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double buildMinimumEdgeLength(Tribe *tribe, int targetMaxVerticesCount) {
Shinya Kitaoka 120a6e
  // Calculate the tribe's total area
Shinya Kitaoka 120a6e
  double area = 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Tribe::iterator ft, fEnd(tribe->end());
Shinya Kitaoka 120a6e
  for (ft = tribe->begin(); ft != fEnd; ++ft) {
Shinya Kitaoka 120a6e
    Family *fam = *ft;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Add area corresponding to the external border
Shinya Kitaoka 120a6e
    area += fabs(
Shinya Kitaoka 120a6e
        tcg::polyline_ops::area(fam->front()->begin(), fam->front()->end()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Then, subtract all the internal ones
Shinya Kitaoka 120a6e
    Family::iterator pt, pEnd(fam->end());
Shinya Kitaoka 120a6e
    for (pt = ++fam->begin(); pt != pEnd; ++pt)
Shinya Kitaoka 120a6e
      area -= fabs(tcg::polyline_ops::area((*pt)->begin(), (*pt)->end()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Given the area, find the approximate edge length corresponding to the
Shinya Kitaoka 120a6e
  // required
Shinya Kitaoka 120a6e
  // vertices count
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // The idea is: given a polygon, its uniform triangular mesh - made of, say,
Shinya Kitaoka 120a6e
  // lots of equilateral
Shinya Kitaoka 120a6e
  // triangles, has vertices count proportional to ( polygon area / sq(mean mesh
Shinya Kitaoka 120a6e
  // edge length) ).
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Under this assumption, take an equilater triangle as our polygon, and
Shinya Kitaoka 120a6e
  // assume that its built
Shinya Kitaoka 120a6e
  // mesh is the regular mesh obtained by subdividing it multiple times,
Shinya Kitaoka 120a6e
  // Sierpinsky-like.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Since it can easily be sheared to a corresponding half-square, it can be
Shinya Kitaoka 120a6e
  // SEEN that in
Shinya Kitaoka 120a6e
  // this case its vertices count is EXACTLY  (l / e_length)^2 / 2,  l being the
Shinya Kitaoka 120a6e
  // large
Shinya Kitaoka 120a6e
  // triangle's edge. By extension, if A is the area of the triangle, then we
Shinya Kitaoka 120a6e
  // have:
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //    A = l^2 * sqrt(3/2) / 2;      => l = sqrt(2 * K * A),     K = 1.0 /
Shinya Kitaoka 120a6e
  //    sqrt(3/2);
Shinya Kitaoka 120a6e
  //    V = K * A / e_length^2;       => e_length = sqrt(KA / V);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // And we just extend this from 'triangle' to 'polygon'.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return sqrt(area / (sqrt(1.5) * targetMaxVerticesCount));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
//    Mesh Refinement  stuff
Toshihiro Shimizu 890ddd
//======================================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void refineMeshes(const TMeshImageP &mi, const MeshBuilderOptions &options) {
Shinya Kitaoka 120a6e
  std::vector<ttexturemeshp> &meshes = mi->meshes();</ttexturemeshp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Refine every mesh to achieve a target mesh density dependent on the image
Shinya Kitaoka 120a6e
  // size
Shinya Kitaoka 120a6e
  /*TRectD bbox(mi->getBBox());
Shinya Kitaoka 120a6e
double targetLength = sqrt(bbox.getLx() * bbox.getLy()) * relativeMeshDensity;*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double targetLength = options.m_targetEdgeLength;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m, mCount = meshes.size();
Shinya Kitaoka 120a6e
  for (m = 0; m < mCount; ++m) {
Shinya Kitaoka 120a6e
    const TTextureMeshP &mesh = meshes[m];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    tcg::TriMeshStuff::DefaultEvaluator<ttexturemesh> eval(</ttexturemesh>
Shinya Kitaoka 120a6e
        0.0, (std::numeric_limits<double>::max)());</double>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // First, perform edge swaps alone. This is useful since results from
Shinya Kitaoka 120a6e
    // gluTriangulate
Shinya Kitaoka 120a6e
    // tend to be unbalanced to vertical - this is a good correction.
Shinya Kitaoka 120a6e
    tcg::refineMesh(*mesh, eval);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Now, launch a full-scale, finishing simplification
Shinya Kitaoka 120a6e
    eval.m_collapseValue = targetLength * 0.6;
Shinya Kitaoka 120a6e
    eval.m_splitValue    = targetLength * 1.4;
Shinya Kitaoka 120a6e
    tcg::refineMesh(*mesh, eval,
Shinya Kitaoka 120a6e
                    20000);  // Max 10000 iterations - to avoid loops
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Since we stopped at a max number of iterations, separate collapses from
Shinya Kitaoka 120a6e
    // splits
Shinya Kitaoka 120a6e
    // and simplify until the procedure stops.
Shinya Kitaoka 120a6e
    eval.m_collapseValue = 0.0;
Shinya Kitaoka 120a6e
    eval.m_splitValue    = 1.4 * targetLength;
Shinya Kitaoka 120a6e
    tcg::refineMesh(*mesh, eval);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    eval.m_splitValue    = (std::numeric_limits<double>::max)();</double>
Shinya Kitaoka 120a6e
    eval.m_collapseValue = targetLength * 0.6;
Shinya Kitaoka 120a6e
    tcg::refineMesh(*mesh, eval);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Perform 1000 final iterations with uniform split and collapses
Shinya Kitaoka 120a6e
    eval.m_splitValue = targetLength * 1.4;
Shinya Kitaoka 120a6e
    tcg::refineMesh(*mesh, eval, 1000);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Finally, squeeze the mesh to ensure that VEF containers are tight
Shinya Kitaoka 120a6e
    mesh->squeeze();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Mesh Builder  function
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TMeshImageP buildMesh(const TRasterP &ras, const MeshBuilderOptions &options) {
Shinya Kitaoka 120a6e
  // Convert the input image to a binary raster
Shinya Kitaoka 120a6e
  TRasterGR8P binaryRas = thresholdRaster(ras, options);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Extract the image borders
Shinya Kitaoka 120a6e
  Tribe *tribe = extractBorders(binaryRas);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Calculate maximum edge length
Shinya Kitaoka 120a6e
  double minEdgeLength =
Shinya Kitaoka 120a6e
      buildMinimumEdgeLength(tribe, options.m_targetMaxVerticesCount);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MeshBuilderOptions opts(options);
Shinya Kitaoka 120a6e
  opts.m_targetEdgeLength = std::max(opts.m_targetEdgeLength, minEdgeLength);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform tessellation
Shinya Kitaoka 120a6e
  TMeshImageP meshImage(new TMeshImage);
Shinya Kitaoka 120a6e
  std::vector<ttexturemeshp> &meshes = meshImage->meshes();</ttexturemeshp>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  tcg::sequential_reader<std::vector<ttexturemeshp>> reader(&meshes);</std::vector<ttexturemeshp>
Shinya Kitaoka 120a6e
  tcg::gluTriangulate(tribe->begin(), tribe->end(), reader);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  delete tribe;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Perform meshes refinement
Shinya Kitaoka 120a6e
  refineMeshes(meshImage, opts);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return meshImage;
Toshihiro Shimizu 890ddd
}