| |
| |
|
|
| #include "trop.h" |
| #include "trop_borders.h" |
| #include "tpixelutils.h" |
| |
| |
| #include "tcg_wrap.h" |
| |
| #include "tcg/tcg_point.h" |
| #include "tcg/tcg_cyclic.h" |
| #include "tcg/tcg_containers_reader.h" |
| |
| #define INCLUDE_HPP |
| #include "tcg/tcg_triangulate.h" |
| #undef INCLUDE_HPP |
| |
| |
| #define INCLUDE_HPP |
| #include "../common/trop/raster_edge_evaluator.h" |
| #undef INCLUDE_HPP |
| |
| #include "ext/meshbuilder.h" |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| struct PolygonVertex { |
| double m_pos[3]; |
| int m_idx; |
| |
| PolygonVertex(const TPoint &p) |
| : m_idx(-1) { m_pos[0] = p.x, m_pos[1] = p.y, m_pos[2] = 0.0; } |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| namespace tcg |
| { |
| |
| template <> |
| struct traits<TTextureMeshP> { |
| typedef TTextureMeshP *pointer_type; |
| typedef TTextureMeshP *&reference_type; |
| typedef TTextureMesh pointed_type; |
| }; |
| |
| |
| |
| template <> |
| struct point_traits<PolygonVertex> { |
| typedef PolygonVertex point_type; |
| typedef double value_type; |
| typedef double float_type; |
| |
| inline static value_type x(const point_type &p) { return p.m_pos[0]; } |
| inline static value_type y(const point_type &p) { return p.m_pos[1]; } |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| |
| |
| |
| |
| template <typename Pix> |
| void thresholdRaster(const TRasterPT<Pix> &ras, TRasterGR8P &out, const Pix &transp) |
| { |
| int lx = ras->getLx(), y, ly = ras->getLy(); |
| for (y = 0; y < ly; ++y) { |
| Pix *pix, *line = ras->pixels(y), *lineEnd = line + lx; |
| TPixelGR8 *gr, *grLine = out->pixels(y); |
| |
| for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr) |
| gr->value = (pix->m && *pix != transp) ? 0 : 255; |
| } |
| } |
| |
| |
| |
| template <typename Pix> |
| void thresholdRasterGr(const TRasterPT<Pix> &ras, TRasterGR8P &out, const Pix &transp) |
| { |
| int lx = ras->getLx(), y, ly = ras->getLy(); |
| for (y = 0; y < ly; ++y) { |
| Pix *pix, *line = ras->pixels(y), *lineEnd = line + lx; |
| TPixelGR8 *gr, *grLine = out->pixels(y); |
| |
| for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr) |
| gr->value = (*pix != transp) ? 0 : 255; |
| } |
| } |
| |
| |
| |
| void thresholdRasterCM32(const TRasterCM32P &ras, TRasterGR8P &out) |
| { |
| int lx = ras->getLx(), y, ly = ras->getLy(); |
| for (y = 0; y < ly; ++y) { |
| TPixelCM32 *pix, *line = ras->pixels(y), *lineEnd = line + lx; |
| TPixelGR8 *gr, *grLine = out->pixels(y); |
| |
| for (pix = line, gr = grLine; pix != lineEnd; ++pix, ++gr) |
| gr->value = (pix->isPurePaint() && !pix->getPaint()) ? 255 : 0; |
| } |
| } |
| |
| |
| |
| TRasterGR8P thresholdRaster(const TRasterP &ras, const MeshBuilderOptions &opts) |
| { |
| TRasterGR8P binaryRas(ras->getLx(), ras->getLy()); |
| |
| TRasterCM32P rasCM(ras); |
| if (rasCM) |
| thresholdRasterCM32(rasCM, binaryRas); |
| else |
| switch (ras->getPixelSize()) { |
| case 1: { |
| TRasterGR8P rasGR8(ras); |
| thresholdRasterGr(rasGR8, binaryRas, TPixelGR8::from(toPixel32(opts.m_transparentColor))); |
| break; |
| } |
| |
| case 2: |
| { |
| TRasterGR16P rasGR16(ras); |
| thresholdRasterGr(rasGR16, binaryRas, TPixelGR16::from(opts.m_transparentColor)); |
| break; |
| } |
| |
| case 4: |
| { |
| TRaster32P ras32(ras); |
| thresholdRaster(ras32, binaryRas, toPixel32(opts.m_transparentColor)); |
| break; |
| } |
| |
| case 8: |
| { |
| TRaster64P ras64(ras); |
| thresholdRaster(ras64, binaryRas, opts.m_transparentColor); |
| break; |
| } |
| |
| default: |
| assert(false); |
| } |
| |
| |
| TRasterGR8P result(ras->getLx(), ras->getLy()); |
| TRop::blur(result, binaryRas, opts.m_margin, 0, 0); |
| |
| thresholdRasterGr(result, result, TPixelGR8::White); |
| |
| return result; |
| } |
| |
| |
| |
| |
| |
| using namespace TRop::borders; |
| |
| |
| |
| template <typename T> |
| inline void delete_(T t) { delete t; } |
| |
| template <typename T> |
| struct Vector : public std::vector<T> { |
| |
| Vector() : std::vector<T>() {} |
| ~Vector() { std::for_each(this->begin(), this->end(), delete_<T>); } |
| }; |
| |
| |
| |
| typedef std::vector<TPoint> RasterBorder; |
| typedef std::vector<PolygonVertex> Polygon; |
| typedef Vector<Polygon *> Family; |
| typedef Vector<Family *> Tribe; |
| |
| |
| |
| struct PolygonReader { |
| Polygon *m_polygon; |
| |
| public: |
| typedef tcg::cyclic_iterator<RasterBorder::iterator> cyclic_iter; |
| |
| public: |
| PolygonReader() : m_polygon(0) {} |
| |
| void openContainer(const cyclic_iter &ct) |
| { |
| m_polygon = new Polygon; |
| m_polygon->push_back(PolygonVertex(*ct)); |
| } |
| |
| void addElement(const cyclic_iter &ct) { m_polygon->push_back(PolygonVertex(*ct)); } |
| |
| void closeContainer() {} |
| }; |
| |
| |
| |
| class BordersReader : public ImageMeshesReaderT<TPixelGR8> |
| { |
| public: |
| Vector<RasterBorder *> m_borders; |
| RasterBorder *m_current; |
| |
| public: |
| BordersReader() |
| : ImageMeshesReaderT<TPixelGR8>(PixelSelector<TPixelGR8>(false)), m_current(0) {} |
| |
| void openFace(ImageMesh *mesh, int faceIdx, const TPixelGR8 &color) |
| { |
| ImageMeshesReader::openFace(mesh, faceIdx); |
| |
| if (mesh) { |
| ImageMesh::face_type &fc = mesh->face(faceIdx); |
| fc.imageIndex() = (color.value) ? 0 : 1; |
| } |
| } |
| |
| |
| |
| void openEdge(const raster_edge_iterator &it) |
| { |
| m_current = new RasterBorder; |
| m_current->push_back(it.pos()); |
| } |
| |
| |
| |
| void addVertex(const raster_edge_iterator &it) |
| { |
| m_current->push_back(it.pos()); |
| } |
| |
| |
| |
| void closeEdge(ImageMesh *mesh, int edgeIdx) |
| { |
| ImageMesh::edge_type &ed = mesh->edge(edgeIdx); |
| ed.imageIndex() = m_borders.size(); |
| |
| m_borders.push_back(m_current); |
| m_current = 0; |
| |
| ImageMeshesReader::closeEdge(mesh, edgeIdx); |
| } |
| }; |
| |
| |
| |
| Polygon *reduceBorder(RasterBorder *border) |
| { |
| typedef RasterBorder::iterator iter; |
| typedef tcg::cyclic_iterator<iter> cyclic_iter; |
| |
| iter b(border->begin()), e(border->end()); |
| |
| cyclic_iter cBegin(b, b, e - 1, 0), |
| cEnd(b + 1, b, e - 1, 1); |
| |
| RasterEdgeEvaluator<cyclic_iter> eval( |
| cBegin - 1, cEnd + 1, 2.0, (std::numeric_limits<double>::max)()); |
| |
| PolygonReader reader; |
| tcg::sequence_ops::minimalPath(cBegin, cEnd, eval, reader); |
| |
| return reader.m_polygon; |
| } |
| |
| |
| |
| void reduceBorders(Tribe *tribe, const ImageMeshesReader &reader, const Vector<RasterBorder *> &borders, |
| int meshIdx, const ImageMesh::face_type &fc) |
| { |
| |
| |
| |
| const tcg::list<ImageMeshP> &meshes = reader.meshes(); |
| |
| if (meshIdx >= 0 && fc.imageIndex()) { |
| |
| Family *family = new Family; |
| tribe->push_back(family); |
| |
| const ImageMeshP &mesh = meshes[meshIdx]; |
| |
| Polygon *outerBorder = reduceBorder(borders[mesh->edge(0).imageIndex()]); |
| family->push_back(outerBorder); |
| |
| |
| int m, mCount = fc.meshesCount(); |
| for (m = 0; m < mCount; ++m) { |
| int mIdx = fc.mesh(m); |
| const ImageMeshP &childMesh = meshes[mIdx]; |
| |
| Polygon *innerBorder = reduceBorder(borders[childMesh->edge(0).imageIndex()]); |
| family->push_back(innerBorder); |
| |
| reduceBorders(tribe, reader, borders, mIdx, childMesh->face(0)); |
| } |
| } |
| |
| |
| int m, mCount = fc.meshesCount(); |
| for (m = 0; m < mCount; ++m) { |
| int mIdx = fc.mesh(m); |
| reduceBorders(tribe, reader, borders, mIdx, meshes[mIdx]->face(0)); |
| } |
| } |
| |
| |
| |
| Tribe *extractBorders(const TRasterGR8P &ras) |
| { |
| Tribe *result = new Tribe; |
| |
| BordersReader reader; |
| TRop::borders::readMeshes(ras, reader); |
| |
| reduceBorders(result, reader, reader.m_borders, -1, reader.outerFace()); |
| |
| return result; |
| } |
| |
| |
| |
| |
| |
| double buildMinimumEdgeLength(Tribe *tribe, int targetMaxVerticesCount) |
| { |
| |
| double area = 0.0; |
| |
| Tribe::iterator ft, fEnd(tribe->end()); |
| for (ft = tribe->begin(); ft != fEnd; ++ft) { |
| Family *fam = *ft; |
| |
| |
| area += fabs(tcg::polyline_ops::area(fam->front()->begin(), fam->front()->end())); |
| |
| |
| Family::iterator pt, pEnd(fam->end()); |
| for (pt = ++fam->begin(); pt != pEnd; ++pt) |
| area -= fabs(tcg::polyline_ops::area((*pt)->begin(), (*pt)->end())); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| return sqrt(area / (sqrt(1.5) * targetMaxVerticesCount)); |
| } |
| |
| |
| |
| |
| |
| void refineMeshes(const TMeshImageP &mi, const MeshBuilderOptions &options) |
| { |
| std::vector<TTextureMeshP> &meshes = mi->meshes(); |
| |
| |
| |
| |
| |
| double targetLength = options.m_targetEdgeLength; |
| |
| int m, mCount = meshes.size(); |
| for (m = 0; m < mCount; ++m) { |
| const TTextureMeshP &mesh = meshes[m]; |
| |
| tcg::TriMeshStuff::DefaultEvaluator<TTextureMesh> eval(0.0, (std::numeric_limits<double>::max)()); |
| |
| |
| |
| tcg::refineMesh(*mesh, eval); |
| |
| |
| eval.m_collapseValue = targetLength * 0.6; |
| eval.m_splitValue = targetLength * 1.4; |
| tcg::refineMesh(*mesh, eval, 20000); |
| |
| |
| |
| eval.m_collapseValue = 0.0; |
| eval.m_splitValue = 1.4 * targetLength; |
| tcg::refineMesh(*mesh, eval); |
| |
| eval.m_splitValue = (std::numeric_limits<double>::max)(); |
| eval.m_collapseValue = targetLength * 0.6; |
| tcg::refineMesh(*mesh, eval); |
| |
| |
| eval.m_splitValue = targetLength * 1.4; |
| tcg::refineMesh(*mesh, eval, 1000); |
| |
| |
| mesh->squeeze(); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| TMeshImageP buildMesh(const TRasterP &ras, const MeshBuilderOptions &options) |
| { |
| |
| TRasterGR8P binaryRas = thresholdRaster(ras, options); |
| |
| |
| Tribe *tribe = extractBorders(binaryRas); |
| |
| |
| double minEdgeLength = buildMinimumEdgeLength(tribe, options.m_targetMaxVerticesCount); |
| |
| MeshBuilderOptions opts(options); |
| opts.m_targetEdgeLength = std::max(opts.m_targetEdgeLength, minEdgeLength); |
| |
| |
| TMeshImageP meshImage(new TMeshImage); |
| std::vector<TTextureMeshP> &meshes = meshImage->meshes(); |
| |
| tcg::sequential_reader<std::vector<TTextureMeshP>> reader(&meshes); |
| tcg::gluTriangulate(tribe->begin(), tribe->end(), reader); |
| |
| delete tribe; |
| |
| |
| refineMeshes(meshImage, opts); |
| |
| return meshImage; |
| } |
| |