|
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 |
}
|