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