Shinya Kitaoka 810553
#pragma once
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef BORDERS_EXTRACTOR_HPP
Toshihiro Shimizu 890ddd
#define BORDERS_EXTRACTOR_HPP
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Toonz includes
Toshihiro Shimizu 890ddd
#include "raster_edge_iterator.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_traits.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_containers_reader.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_hash.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_misc.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "borders_extractor.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace TRop {
Shinya Kitaoka 120a6e
namespace borders {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
//    Private stuff
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pixelselector=""></typename>
Shinya Kitaoka 120a6e
class _DummyReader {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  void openContainer(const RasterEdgeIterator<pixelselector> &) {}</pixelselector>
Shinya Kitaoka 120a6e
  void addElement(const RasterEdgeIterator<pixelselector> &) {}</pixelselector>
Shinya Kitaoka 120a6e
  void closeContainer() {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
//    Borders Extraction procedure
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void _signEdge(RunsMapP &runsMap, int x, int y0, int y1,
Shinya Kitaoka 120a6e
                      UCHAR increasingSign, UCHAR decreasingSign) {
Shinya Kitaoka 120a6e
  for (; y0 < y1; ++y0) runsMap->runHeader(x, y0) |= increasingSign;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (y0 > y1) {
Shinya Kitaoka 120a6e
    --x;
Shinya Kitaoka 120a6e
    do {
Shinya Kitaoka 120a6e
      --y0;
Shinya Kitaoka 120a6e
      runsMap->runHeader(x, y0) |= decreasingSign;
Shinya Kitaoka 120a6e
    } while (y0 > y1);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containerreader="" pixel,="" pixelselector,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void _readBorder(const TRasterPT<pixel> &rin, const PixelSelector &selector,</pixel>
Shinya Kitaoka 120a6e
                 RunsMapP &runsMap, int x, int y, bool counter,
Shinya Kitaoka 120a6e
                 ContainerReader &reader) {
Shinya Kitaoka 120a6e
  typedef typename PixelSelector::value_type value_type;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UCHAR increasingSign = _BORDER_LEFT, decreasingSign = _BORDER_RIGHT;
Shinya Kitaoka 120a6e
  if (!counter)
Shinya Kitaoka 120a6e
    increasingSign |= _HIERARCHY_INCREASE,
Shinya Kitaoka 120a6e
        decreasingSign |= _HIERARCHY_DECREASE;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // First, read the border entirely, while erasing the border from
Shinya Kitaoka 120a6e
  // the runsMap.
Shinya Kitaoka 120a6e
  RasterEdgeIterator<pixelselector> it(rin, selector, TPoint(x, y),</pixelselector>
Shinya Kitaoka 120a6e
                                       counter ? TPoint(1, 0) : TPoint(0, 1));
Shinya Kitaoka 120a6e
  //++it;   //As we could be in the middle of a straight edge, increment to get
Shinya Kitaoka 120a6e
  //a corner
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPoint start(it.pos()), startDir(it.dir());
Shinya Kitaoka 120a6e
  reader.openContainer(it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPoint oldPos(start);
Shinya Kitaoka 120a6e
  for (++it; it.pos() != start || it.dir() != startDir; ++it) {
Shinya Kitaoka 120a6e
    const TPoint &currPos(it.pos());
Shinya Kitaoka 120a6e
    reader.addElement(it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Sign the corresponding (vertical) edge
Shinya Kitaoka 120a6e
    _signEdge(runsMap, oldPos.x, oldPos.y, currPos.y, increasingSign,
Shinya Kitaoka 120a6e
              decreasingSign);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    oldPos = currPos;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  _signEdge(runsMap, oldPos.x, oldPos.y, it.pos().y, increasingSign,
Shinya Kitaoka 120a6e
            decreasingSign);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  reader.closeContainer();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containerreader="" pixel,="" pixelselector,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void readBorders(const TRasterPT<pixel> &rin, const PixelSelector &selector,</pixel>
Shinya Kitaoka 120a6e
                 ContainerReader &reader, RunsMapP *rasterRunsMap) {
Shinya Kitaoka 120a6e
  typedef TRasterPT<pixel> RasterTypeP;</pixel>
Shinya Kitaoka 120a6e
  typedef _DummyReader<pixelselector> DummyReader;</pixelselector>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First, extract the run-length representation for rin
Shinya Kitaoka 120a6e
  RunsMapP runsMap;
Shinya Kitaoka 120a6e
  if (rasterRunsMap && *rasterRunsMap) {
Shinya Kitaoka 120a6e
    // If it was supplied, use it
Shinya Kitaoka 120a6e
    runsMap = *rasterRunsMap;
Shinya Kitaoka 120a6e
    runsMap->lock();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // In case, build it anew
Shinya Kitaoka 120a6e
    runsMap = RunsMapP(rin->getLx(), rin->getLy());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    runsMap->lock();
Shinya Kitaoka 120a6e
    buildRunsMap(runsMap, rin, selector);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (rasterRunsMap)
Shinya Kitaoka 120a6e
    // Return the runsMap if requested
Shinya Kitaoka 120a6e
    *rasterRunsMap = runsMap;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build a fake reader for internal borders
Shinya Kitaoka 120a6e
  DummyReader dummyReader;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, use it to extract borders - iterate through runs and, whenever
Shinya Kitaoka 120a6e
  // one is found with opaque color (ie not transparent), extract its
Shinya Kitaoka 120a6e
  // associated border. The border is erased internally after the read.
Shinya Kitaoka 120a6e
  int lx = rin->getLx(), ly = rin->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int hierarchyLevel = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int x, y;
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    Pixel *lineStart     = rin->pixels(y), *pix;
Shinya Kitaoka 120a6e
    TPixelGR8 *runsStart = runsMap->pixels(y), *run;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UCHAR nextHeader, prevHeader = 0;
Shinya Kitaoka 120a6e
    for (x = 0, pix = lineStart, run = runsStart; x < lx;) {
Shinya Kitaoka 120a6e
      nextHeader = run->value;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (hierarchyLevel) {
Shinya Kitaoka 120a6e
        if (prevHeader & _BORDER_RIGHT) {
Shinya Kitaoka 120a6e
          if (prevHeader & _HIERARCHY_DECREASE) --hierarchyLevel;
Shinya Kitaoka 120a6e
        } else  // Every right border in a region should be signed. Do so now.
Shinya Kitaoka 120a6e
          _readBorder(rin, selector, runsMap, x, y, true, dummyReader);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (hierarchyLevel) {
Shinya Kitaoka 120a6e
        if (nextHeader & _BORDER_LEFT) {
Shinya Kitaoka 120a6e
          if (nextHeader & _HIERARCHY_INCREASE) ++hierarchyLevel;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          ++hierarchyLevel;
Shinya Kitaoka 120a6e
          _readBorder(rin, selector, runsMap, x, y, false, reader);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (!(selector.transparent(
Shinya Kitaoka 120a6e
                *pix)))  // External transparent region - do not extract
Shinya Kitaoka 120a6e
        {
Shinya Kitaoka 120a6e
          ++hierarchyLevel;
Shinya Kitaoka 120a6e
          if (!(nextHeader & _BORDER_LEFT))
Shinya Kitaoka 120a6e
            _readBorder(rin, selector, runsMap, x, y, false, reader);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Increment variables
Shinya Kitaoka 120a6e
      x += runsMap->runLength(x, y), pix = lineStart + x, run = runsStart + x;
Shinya Kitaoka 120a6e
      prevHeader = (run - 1)->value;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(x == lx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (hierarchyLevel) {
Shinya Kitaoka 120a6e
      assert((prevHeader & _BORDER_RIGHT) &&
Shinya Kitaoka 120a6e
             (prevHeader & _HIERARCHY_DECREASE));
Shinya Kitaoka 120a6e
      --hierarchyLevel;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(!hierarchyLevel);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  runsMap->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
//    New Mesh Extraction procedure
Toshihiro Shimizu 890ddd
//*********************************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
enum {
Shinya Kitaoka 120a6e
  _PROCESSED                  = 0x1,
Shinya Kitaoka 120a6e
  _HIERARCHY_UP               = 0x2,
Shinya Kitaoka 120a6e
  _HIERARCHY_DN               = 0x4,
Shinya Kitaoka 120a6e
  _PROCESSED_AND_HIERARCHY_UP = (_PROCESSED | _HIERARCHY_UP)
Shinya Kitaoka 120a6e
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename rasteredgeiter=""></typename>
Shinya Kitaoka 120a6e
inline bool _isVertex(
Shinya Kitaoka 120a6e
    const RasterEdgeIter &it,
Shinya Kitaoka 120a6e
    const typename RasterEdgeIter::value_type &oldOtherColor) {
Shinya Kitaoka 120a6e
  return (it.otherColor() != oldOtherColor) ||
Shinya Kitaoka 120a6e
         (it.turn() == it.adherence() &&
Shinya Kitaoka 120a6e
          (!(it.turn() & RasterEdgeIter::AMBIGUOUS)) &&
Shinya Kitaoka 120a6e
          it.elbowColor() != oldOtherColor);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline size_t _pointHash(const TPoint &point) { return point.x ^ point.y; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename rasteredgeiter=""></typename>
Toshihiro Shimizu 890ddd
struct _ExternalEdgeSigner {
Shinya Kitaoka 120a6e
  static inline void signAndIncrement(RunsMapP &runsMap, RasterEdgeIter &it) {
Shinya Kitaoka 120a6e
    if (it.dir().y > 0) {
Shinya Kitaoka 120a6e
      TPoint pos = it.pos();
Shinya Kitaoka 120a6e
      int newY   = (++it).pos().y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (; pos.y != newY; ++pos.y)
Shinya Kitaoka 120a6e
        runsMap->runHeader(pos.x, pos.y) |= _PROCESSED_AND_HIERARCHY_UP;
Shinya Kitaoka 120a6e
    } else if (it.dir().y < 0) {
Shinya Kitaoka 120a6e
      TPoint pos = it.pos();
Shinya Kitaoka 120a6e
      int newY   = (++it).pos().y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TPixelGR8 *pix = runsMap->pixels(pos.y - 1) + pos.x;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (; pos.y != newY; --pos.y, --pix) {
Shinya Kitaoka 120a6e
        pix->value |= _PROCESSED;
Shinya Kitaoka 120a6e
        (--pix)->value |= _HIERARCHY_DN;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      ++it;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename rasteredgeiter=""></typename>
Toshihiro Shimizu 890ddd
struct _InternalEdgeSigner {
Shinya Kitaoka 120a6e
  static inline void signAndIncrement(RunsMapP &runsMap, RasterEdgeIter &it) {
Shinya Kitaoka 120a6e
    if (it.dir().y) {
Shinya Kitaoka 120a6e
      TPoint pos = it.pos();
Shinya Kitaoka 120a6e
      int newY   = (++it).pos().y;
Shinya Kitaoka 120a6e
      int dir    = it.dir().y;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      TPixelGR8 *pix =
Shinya Kitaoka 120a6e
          runsMap->pixels((it.dir().y > 0) ? pos.y : pos.y - 1) + pos.x;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (; pos.y != newY; pos.y += dir, pix += dir) {
Shinya Kitaoka 120a6e
        pix->value |= _PROCESSED_AND_HIERARCHY_UP;
Shinya Kitaoka 120a6e
        (--pix)->value |= _HIERARCHY_DN;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else
Shinya Kitaoka 120a6e
      ++it;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
template 
Shinya Kitaoka 120a6e
          typename EdgeSigner>
Toshihiro Shimizu 890ddd
int _readEdge(RasterEdgeIter &it, const RasterEdgeIter &end, RunsMapP runsMap,
Shinya Kitaoka 120a6e
              int &vIdx, Mesh &mesh, tcg::hash<tpoint, int=""> &pointsHash,</tpoint,>
Shinya Kitaoka 120a6e
              ContainersReader &reader) {
Shinya Kitaoka 120a6e
  typedef tcg::container_reader_traits
Shinya Kitaoka 120a6e
                                       typename Mesh::edge_type>
Shinya Kitaoka 120a6e
      edge_output;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typename Mesh::edge_type ed;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ed.addVertex(vIdx);
Shinya Kitaoka 120a6e
  ed.direction(0) = it.dir();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  edge_output::openContainer(reader, it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  typename RasterEdgeIter::value_type oldOtherColor = it.otherColor();
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    EdgeSigner::signAndIncrement(runsMap, it);
Shinya Kitaoka 120a6e
    edge_output::addElement(reader, it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  } while ((it != end) && !_isVertex(it, oldOtherColor));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Identify the newly found vertex. If it's a brand new one, add it
Shinya Kitaoka 120a6e
  tcg::hash<tpoint, int="">::iterator ht = pointsHash.find(it.pos());</tpoint,>
Shinya Kitaoka 120a6e
  vIdx = (ht == pointsHash.end())
Shinya Kitaoka 120a6e
             ? pointsHash[it.pos()] =
Shinya Kitaoka 120a6e
                   mesh.addVertex(typename Mesh::vertex_type(it.pos()))
Shinya Kitaoka 120a6e
             : ht.m_idx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ed.addVertex(vIdx);
Shinya Kitaoka 120a6e
  ed.direction(1) = (it.turn() == RasterEdgeIter::STRAIGHT)
Shinya Kitaoka 120a6e
                        ? -it.dir()
Shinya Kitaoka 120a6e
                        : (it.turn() == RasterEdgeIter::LEFT)
Shinya Kitaoka 120a6e
                              ? tcg::point_ops::ortLeft(it.dir())
Shinya Kitaoka 120a6e
                              : tcg::point_ops::ortRight(it.dir());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int eIdx = mesh.addEdge(ed);
Shinya Kitaoka 120a6e
  edge_output::closeContainer(reader, &mesh, eIdx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return eIdx;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containersreader="" mesh,="" rasteredgeiter,="" typename=""></typename>
Shinya Kitaoka 120a6e
void _readMeshes(const RasterEdgeIter &begin, RunsMapP &runsMap,
Shinya Kitaoka 120a6e
                 ContainersReader &reader) {
Shinya Kitaoka 120a6e
  typedef tcg::container_reader_traits
Shinya Kitaoka 120a6e
                                       typename Mesh::face_type>
Shinya Kitaoka 120a6e
      face_output;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Iterate it clockwise. Process lines with vertical displacement. In each
Shinya Kitaoka 120a6e
  // line, search
Shinya Kitaoka 120a6e
  // for unprocessed raster edges.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Use hierarchy signs in the runsMap to understand the search scope in this
Shinya Kitaoka 120a6e
  // sub-region.
Shinya Kitaoka 120a6e
  int hierarchyLevel = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  RasterEdgeIter it(begin);
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    if (it.dir().y > 0) {
Shinya Kitaoka 120a6e
      // Process line
Shinya Kitaoka 120a6e
      TPoint pos           = it.pos();
Shinya Kitaoka 120a6e
      const TPixelGR8 *pix = runsMap->pixels(pos.y) + pos.x;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      hierarchyLevel = 0;
Shinya Kitaoka 120a6e
      assert((pix->value & _PROCESSED) && (pix->value & _HIERARCHY_UP));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      do {
Shinya Kitaoka 120a6e
        // Iterate through the line. Extract a mesh each time an unprocessed
Shinya Kitaoka 120a6e
        // raster edge is found.
Shinya Kitaoka 120a6e
        if (!(pix->value & _PROCESSED)) {
Shinya Kitaoka 120a6e
          assert(hierarchyLevel == 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
          Mesh *meshPtr = new Mesh;
Shinya Kitaoka 120a6e
          _readMesh(it.raster(), it.selector(), runsMap, pos.x, pos.y, *meshPtr,
Shinya Kitaoka 120a6e
                    reader);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
          face_output::addElement(reader, meshPtr);
Shinya Kitaoka 120a6e
        }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if (pix->value & _HIERARCHY_UP) ++hierarchyLevel;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        TUINT32 l = runsMap->runLength(pos.x, pos.y);
Shinya Kitaoka 120a6e
        pos.x += l;
Shinya Kitaoka 120a6e
        pix += l;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if ((pix - 1)->value & _HIERARCHY_DN) --hierarchyLevel;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      } while (hierarchyLevel > 0);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    ++it;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  } while (it != begin);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containersreader="" mesh,="" rasteredgeiter,="" typename=""></typename>
Shinya Kitaoka 120a6e
void _readBorder(const RasterEdgeIter &begin, RunsMapP runsMap, int vIdx,
Shinya Kitaoka 120a6e
                 Mesh &mesh, tcg::hash<tpoint, int=""> &pointsHash,</tpoint,>
Shinya Kitaoka 120a6e
                 ContainersReader &reader) {
Shinya Kitaoka 120a6e
  typedef typename Mesh::face_type face_type;
Shinya Kitaoka 120a6e
  typedef typename Mesh::edge_type edge_type;
Shinya Kitaoka 120a6e
  typedef tcg::container_reader_traits
Shinya Kitaoka 120a6e
                                       typename Mesh::face_type>
Shinya Kitaoka 120a6e
      face_output;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // As long as we don't get back to the initial iterator, extract edges
Shinya Kitaoka 120a6e
  RasterEdgeIter it(begin);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Create the face to be extracted at the right of processed border, and add
Shinya Kitaoka 120a6e
  // it to
Shinya Kitaoka 120a6e
  // the mesh. Observe that insertion is made manually in the mesh's faces list.
Shinya Kitaoka 120a6e
  // This prevents the mesh from automatically link edges to the face.
Shinya Kitaoka 120a6e
  face_type fc;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    // Retrieve current vertex
Shinya Kitaoka 120a6e
    typename Mesh::vertex_type &vx = mesh.vertex(vIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Search in it the edge corresponding to current iterating direction
Shinya Kitaoka 120a6e
    int e, edgesCount = vx.edgesCount(), eIdx = -1, side = -1;
Shinya Kitaoka 120a6e
    for (e = 0; e < edgesCount; ++e) {
Shinya Kitaoka 120a6e
      edge_type &ed = mesh.edge(vx.edge(e));
Shinya Kitaoka 120a6e
      side          = ed.vertex(0) == vIdx ? 0 : 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (ed.direction(side) == it.dir()) {
Shinya Kitaoka 120a6e
        eIdx = ed.getIndex();
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (e == edgesCount) {
Shinya Kitaoka 120a6e
      // In case the edge was not found, it needs to be extracted now.
Shinya Kitaoka 120a6e
      eIdx = _readEdge
Shinya Kitaoka 120a6e
                       _InternalEdgeSigner<rasteredgeiter>>(</rasteredgeiter>
Shinya Kitaoka 120a6e
          it, begin, runsMap, vIdx, mesh, pointsHash, reader);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // The edge was already extracted. We just need to update the iterator
Shinya Kitaoka 120a6e
      // then.
Shinya Kitaoka 120a6e
      const edge_type &ed = mesh.edge(eIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      vIdx                      = ed.vertex(1 - side);
Shinya Kitaoka 120a6e
      const TPoint &oppositePos = mesh.vertex(vIdx).P();
Shinya Kitaoka 120a6e
      const TPoint &oppositeDir = ed.direction(1 - side);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // We need to perform the last ++it in the already extracted edge since we
Shinya Kitaoka 120a6e
      // need
Shinya Kitaoka 120a6e
      // to give it the incoming direction.
Shinya Kitaoka 120a6e
      it.setEdge(oppositePos + oppositeDir, -oppositeDir), ++it;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    fc.addEdge(eIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } while (it != begin);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // The face has now been described (from the mesh viewpoint). Add it to the
Shinya Kitaoka 120a6e
  // mesh.
Shinya Kitaoka 120a6e
  int fIdx = mesh.addFace(fc);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // We still need to extract its sub-meshes content now.
Shinya Kitaoka 120a6e
  face_output::openContainer(reader, &mesh, fIdx, begin.rightColor());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  _readMeshes<rasteredgeiter, containersreader="" mesh,="">(begin, runsMap, reader);</rasteredgeiter,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  face_output::closeContainer(reader);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containersreader="" mesh,="" pixelselector,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void _readMesh(const TRasterPT<typename pixelselector::pixel_type=""> &rin,</typename>
Shinya Kitaoka 120a6e
               const PixelSelector &selector, RunsMapP &runsMap, int x, int y,
Shinya Kitaoka 120a6e
               Mesh &mesh, ContainersReader &reader) {
Shinya Kitaoka 120a6e
  typedef typename Mesh::vertex_type vertex_type;
Shinya Kitaoka 120a6e
  typedef typename Mesh::edge_type edge_type;
Shinya Kitaoka 120a6e
  typedef tcg::container_reader_traits<containersreader, edge_type=""> edge_output;</containersreader,>
Shinya Kitaoka 120a6e
  typedef typename PixelSelector::value_type value_type;
Shinya Kitaoka 120a6e
  typedef RasterEdgeIterator<pixelselector> raster_edge_iterator;</pixelselector>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Iterate silently until a vertex is encountered (or until the initial point
Shinya Kitaoka 120a6e
  // is found)
Shinya Kitaoka 120a6e
  raster_edge_iterator it(rin, selector, TPoint(x, y), TPoint(0, 1)), begin(it);
Shinya Kitaoka 120a6e
  it.setAdherence(raster_edge_iterator::LEFT);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  value_type beginColor = begin.rightColor();
Shinya Kitaoka 120a6e
  for (++it; it != begin && !_isVertex(it, beginColor); ++it)
Shinya Kitaoka 120a6e
    ;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Use a hash to keep track of found vertices
Shinya Kitaoka 120a6e
  tcg::hash<tpoint, int=""> pointsHash(&_pointHash);</tpoint,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int vIdx = pointsHash[it.pos()] = mesh.addVertex(it.pos());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // The outer edges are extracted first in clockwise orientation.
Shinya Kitaoka 120a6e
  begin = it;
Shinya Kitaoka 120a6e
  do {
Shinya Kitaoka 120a6e
    _readEdge
Shinya Kitaoka 120a6e
              _ExternalEdgeSigner<raster_edge_iterator>>(</raster_edge_iterator>
Shinya Kitaoka 120a6e
        it, begin, runsMap, vIdx, mesh, pointsHash, reader);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  } while (it != begin);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Then, their associated faces are extracted.
Shinya Kitaoka 120a6e
  it.setAdherence(raster_edge_iterator::RIGHT);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int e, outerEdgesCount = mesh.edgesCount();
Shinya Kitaoka 120a6e
  for (e = 0; e < outerEdgesCount; ++e) {
Shinya Kitaoka 120a6e
    const edge_type &ed = mesh.edge(e);
Shinya Kitaoka 120a6e
    if (ed.face(0) < 0) {
Shinya Kitaoka 120a6e
      vIdx                  = ed.vertex(0);
Shinya Kitaoka 120a6e
      const vertex_type &vx = mesh.vertex(vIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      it.setEdge(vx.P(), ed.direction(0));
Shinya Kitaoka 120a6e
      _readBorder(it, runsMap, vIdx, mesh, pointsHash, reader);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Edges following those must have either side associated with a face.
Shinya Kitaoka 120a6e
  // Which must be extracted too.
Shinya Kitaoka 120a6e
  for (e = outerEdgesCount; e < mesh.edgesCount(); ++e) {
Shinya Kitaoka 120a6e
    const edge_type &ed = mesh.edge(e);
Shinya Kitaoka 120a6e
    if (ed.face(1) < 0) {
Shinya Kitaoka 120a6e
      vIdx                  = ed.vertex(1);
Shinya Kitaoka 120a6e
      const vertex_type &vx = mesh.vertex(vIdx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      it.setEdge(vx.P(), ed.direction(1));
Shinya Kitaoka 120a6e
      _readBorder(it, runsMap, vIdx, mesh, pointsHash, reader);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containersreader="" mesh,="" pixelselector,="" typename=""></typename>
Shinya Kitaoka 120a6e
void readMeshes(const TRasterPT<typename pixelselector::pixel_type=""> &rin,</typename>
Shinya Kitaoka 120a6e
                const PixelSelector &selector, ContainersReader &reader,
Shinya Kitaoka 120a6e
                RunsMapP *rasterRunsMap) {
Shinya Kitaoka 120a6e
  typedef typename PixelSelector::pixel_type pixel_type;
Shinya Kitaoka 120a6e
  typedef TRasterPT<pixel_type> RasterTypeP;</pixel_type>
Shinya Kitaoka 120a6e
  typedef Mesh mesh_type;
Shinya Kitaoka 120a6e
  typedef tcg::container_reader_traits
Shinya Kitaoka 120a6e
                                       typename Mesh::face_type>
Shinya Kitaoka 120a6e
      face_output;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First, extract the run-length representation for rin
Shinya Kitaoka 120a6e
  RunsMapP runsMap;
Shinya Kitaoka 120a6e
  if (rasterRunsMap && *rasterRunsMap) {
Shinya Kitaoka 120a6e
    // If a runsmap was supplied, use it
Shinya Kitaoka 120a6e
    runsMap = *rasterRunsMap;
Shinya Kitaoka 120a6e
    runsMap->lock();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert((runsMap->getLx() == rin->getLx() + 1) &&
Shinya Kitaoka 120a6e
           (runsMap->getLy() == rin->getLy()));
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // In case, build it anew
Shinya Kitaoka 120a6e
    runsMap = RunsMapP(rin->getLx() + 1, rin->getLy());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Observe the +1 on the x-axis. One additional pixel is currently required
Shinya Kitaoka 120a6e
    // on the right
Shinya Kitaoka 120a6e
    // side of the runsmap - for ease of use in the algorithm.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    runsMap->lock();
Shinya Kitaoka 120a6e
    buildRunsMap(runsMap, rin, selector);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (rasterRunsMap)
Shinya Kitaoka 120a6e
    // Return the runsMap if requested
Shinya Kitaoka 120a6e
    *rasterRunsMap = runsMap;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  face_output::openContainer(reader, 0, -1, selector.transparent());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, use it to extract borders - iterate through runs and, whenever
Shinya Kitaoka 120a6e
  // one is found with opaque color (ie not transparent), extract its
Shinya Kitaoka 120a6e
  // associated border. The border is erased internally after the read.
Shinya Kitaoka 120a6e
  int lx = rin->getLx(), ly = rin->getLy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int x, y;
Shinya Kitaoka 120a6e
  for (y = 0; y < ly; ++y) {
Shinya Kitaoka 120a6e
    // Process each row
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    pixel_type *lineStart = rin->pixels(y), *pix;
Shinya Kitaoka 120a6e
    TPixelGR8 *runsStart  = runsMap->pixels(y), *run;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    UCHAR nextHeader, prevHeader = 0;
Shinya Kitaoka 120a6e
    for (x = 0, pix = lineStart, run = runsStart; x < lx;) {
Shinya Kitaoka 120a6e
      nextHeader = run->value;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!(selector.transparent(*pix) || nextHeader & _PROCESSED)) {
Shinya Kitaoka 120a6e
        mesh_type *meshPtr = new mesh_type;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Read the mesh. All its internal sub-meshes are read as well.
Shinya Kitaoka 120a6e
        _readMesh(rin, selector, runsMap, x, y, *meshPtr, reader);
Shinya Kitaoka 120a6e
        face_output::addElement(reader, meshPtr);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Increment variables
Shinya Kitaoka 120a6e
      x += runsMap->runLength(x, y), pix = lineStart + x, run = runsStart + x;
Shinya Kitaoka 120a6e
      prevHeader = (run - 1)->value;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(x == lx);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  face_output::closeContainer(reader);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  runsMap->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
}  // namespace TRop::borders
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#endif  // BORDERS_EXTRACTOR_HPP