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