Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tcenterlinevectorizer.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
#include "tstopwatch.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#include "trastercm.h"
Toshihiro Shimizu 890ddd
#include "ttoonzimage.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_numeric_ops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_function_types.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <functional></functional>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#undef DEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct ControlPoint {
Toshihiro Shimizu 890ddd
	TStroke *m_stroke;
Toshihiro Shimizu 890ddd
	int m_index;
Toshihiro Shimizu 890ddd
	ControlPoint(TStroke *stroke, int index)
Toshihiro Shimizu 890ddd
		: m_stroke(stroke), m_index(index)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TPointD getPoint() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_stroke->getControlPoint(m_index);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void setPoint(const TPointD &p)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TThickPoint point = m_stroke->getControlPoint(m_index);
Toshihiro Shimizu 890ddd
		point.x = p.x;
Toshihiro Shimizu 890ddd
		point.y = p.y;
Toshihiro Shimizu 890ddd
		m_stroke->setControlPoint(m_index, point);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Node;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class DataPixel
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TPoint m_pos;
Toshihiro Shimizu 890ddd
	int m_value;
Toshihiro Shimizu 890ddd
	bool m_ink;
Toshihiro Shimizu 890ddd
	Node *m_node;
Toshihiro Shimizu 890ddd
	DataPixel() : m_value(0), m_ink(false), m_node(0) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
template class DV_EXPORT_API TSmartPointerT<trastert<datapixel>>;</trastert<datapixel>
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
typedef TRasterPT<datapixel> DataRasterP;</datapixel>
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Junction;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Node
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	Node *m_other;
Toshihiro Shimizu 890ddd
	DataPixel *m_pixel;
Toshihiro Shimizu 890ddd
	Node *m_prev, *m_next;
Toshihiro Shimizu 890ddd
	Junction *m_junction;
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Toshihiro Shimizu 890ddd
	bool m_flag;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
	bool m_visited;
Toshihiro Shimizu 890ddd
	Node()
Toshihiro Shimizu 890ddd
		: m_pixel(0),
Toshihiro Shimizu 890ddd
		  m_prev(0),
Toshihiro Shimizu 890ddd
		  m_next(0),
Toshihiro Shimizu 890ddd
		  m_junction(0),
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Toshihiro Shimizu 890ddd
		  m_flag(false),
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
		  m_visited(false)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ProtoStroke;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Junction
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TThickPoint m_center;
Toshihiro Shimizu 890ddd
	std::deque<node *=""> m_nodes;</node>
Toshihiro Shimizu 890ddd
	int m_junctionOrder;
Toshihiro Shimizu 890ddd
	std::vector<protostroke *=""> m_protoStrokes;</protostroke>
Toshihiro Shimizu 890ddd
	bool m_locked;
Toshihiro Shimizu 890ddd
	Junction()
Toshihiro Shimizu 890ddd
		: m_center(), m_nodes(), m_junctionOrder(0), m_protoStrokes(), m_locked(false) {}
Toshihiro Shimizu 890ddd
	bool isConvex();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ProtoStroke
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TPointD m_startDirection, m_endDirection;
Toshihiro Shimizu 890ddd
	Junction *m_startJunction, *m_endJunction;
Toshihiro Shimizu 890ddd
	std::deque<tthickpoint> m_points;</tthickpoint>
Toshihiro Shimizu 890ddd
	ProtoStroke()
Toshihiro Shimizu 890ddd
		: m_points(), m_startDirection(), m_endDirection(), m_startJunction(0), m_endJunction(0) {}
Toshihiro Shimizu 890ddd
	ProtoStroke(std::deque<tthickpoint>::iterator it_b,</tthickpoint>
Toshihiro Shimizu 890ddd
				std::deque<tthickpoint>::iterator it_e)</tthickpoint>
Toshihiro Shimizu 890ddd
		: m_points(it_b, it_e), m_startDirection(), m_endDirection(), m_startJunction(0), m_endJunction(0) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double computeDistance2(Node *na, Node *nb)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(na->m_pixel);
Toshihiro Shimizu 890ddd
	assert(nb->m_pixel);
Toshihiro Shimizu 890ddd
	TPointD d = convert(na->m_pixel->m_pos - nb->m_pixel->m_pos);
Toshihiro Shimizu 890ddd
	return d * d;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void renormalizeImage(TVectorImage *vi)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i, j;
Toshihiro Shimizu 890ddd
	int n = vi->getStrokeCount();
Toshihiro Shimizu 890ddd
	std::vector<controlpoint> points;</controlpoint>
Toshihiro Shimizu 890ddd
	points.reserve(n * 2);
Toshihiro Shimizu 890ddd
	for (i = 0; i < n; i++) {
Toshihiro Shimizu 890ddd
		TStroke *stroke = vi->getStroke(i);
Toshihiro Shimizu 890ddd
		int m = stroke->getControlPointCount();
Toshihiro Shimizu 890ddd
		if (m > 0) {
Toshihiro Shimizu 890ddd
			if (m == 1)
Toshihiro Shimizu 890ddd
				points.push_back(ControlPoint(stroke, 0));
Toshihiro Shimizu 890ddd
			else {
Toshihiro Shimizu 890ddd
				points.push_back(ControlPoint(stroke, 0));
Toshihiro Shimizu 890ddd
				points.push_back(ControlPoint(stroke, m - 1));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int count = points.size();
Toshihiro Shimizu 890ddd
	for (i = 0; i < count; i++) {
Toshihiro Shimizu 890ddd
		ControlPoint &pi = points[i];
Toshihiro Shimizu 890ddd
		TPointD posi = pi.getPoint();
Toshihiro Shimizu 890ddd
		TPointD center = posi;
Toshihiro Shimizu 890ddd
		std::vector<int> neighbours;</int>
Toshihiro Shimizu 890ddd
		neighbours.push_back(i);
Toshihiro Shimizu 890ddd
		for (j = i + 1; j < count; j++) {
Toshihiro Shimizu 890ddd
			TPointD posj = points[j].getPoint();
Toshihiro Shimizu 890ddd
			double d = tdistance(posj, posi);
Toshihiro Shimizu 890ddd
			if (d < 0.01) {
Toshihiro Shimizu 890ddd
				neighbours.push_back(j);
Toshihiro Shimizu 890ddd
				center += posj;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		int m = neighbours.size();
Toshihiro Shimizu 890ddd
		if (m == 1)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		center = center * (1.0 / m);
Toshihiro Shimizu 890ddd
		for (j = 0; j < m; j++)
Toshihiro Shimizu 890ddd
			points[neighbours[j]].setPoint(center);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class OutlineVectorizer
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPalette *m_palette;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TRasterP m_src;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OutlineConfiguration m_configuration;
Toshihiro Shimizu 890ddd
	DataRasterP m_dataRaster;
Toshihiro Shimizu 890ddd
	vector<pair<int, datarasterp="">> m_dataRasterArray;</pair<int,>
Toshihiro Shimizu 890ddd
	TVectorImageP m_vimage;
Toshihiro Shimizu 890ddd
	vector<node *=""> m_nodes;</node>
Toshihiro Shimizu 890ddd
	list<vector<tthickpoint>> m_protoOutlines;</vector<tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	vector<junction *=""> m_junctions;</junction>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OutlineVectorizer(const OutlineConfiguration &configuration, TPalette *palette)
Toshihiro Shimizu 890ddd
		: m_configuration(configuration), m_palette(palette) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~OutlineVectorizer();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void traceOutline(Node *initialNode);
Toshihiro Shimizu 890ddd
	void createOutlineStrokes();
Toshihiro Shimizu 890ddd
	void makeDataRaster(const TRasterP &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Node *findOtherSide(Node *node);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void clearNodes();
Toshihiro Shimizu 890ddd
	Node *createNode(DataPixel *pix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void clearJunctions();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void init();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void link(DataPixel *pix, DataPixel *from, DataPixel *to);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPoint computeGradient(DataPixel *pix)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(m_dataRaster);
Toshihiro Shimizu 890ddd
		const int wrap = m_dataRaster->getWrap();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPoint g(0, 0);
Toshihiro Shimizu 890ddd
		int n, s, w, e, nw, sw, ne, se;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		w = pix[-1].m_value;
Toshihiro Shimizu 890ddd
		nw = pix[-1 + wrap].m_value;
Toshihiro Shimizu 890ddd
		sw = pix[-1 - wrap].m_value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		e = pix[+1].m_value;
Toshihiro Shimizu 890ddd
		ne = pix[+1 + wrap].m_value;
Toshihiro Shimizu 890ddd
		se = pix[+1 - wrap].m_value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		n = pix[+wrap].m_value;
Toshihiro Shimizu 890ddd
		s = pix[-wrap].m_value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		g.y = -sw + ne - se + nw + 2 * (n - s);
Toshihiro Shimizu 890ddd
		g.x = -sw + ne + se - nw + 2 * (e - w);
Toshihiro Shimizu 890ddd
		return g;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	// not implemented
Toshihiro Shimizu 890ddd
	OutlineVectorizer(const OutlineVectorizer &);
Toshihiro Shimizu 890ddd
	OutlineVectorizer &operator=(const OutlineVectorizer &);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
OutlineVectorizer::~OutlineVectorizer()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_protoOutlines.clear();
Toshihiro Shimizu 890ddd
	clearNodes();
Toshihiro Shimizu 890ddd
	clearJunctions();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::init()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DataRasterP dataRaster = m_dataRaster;
Toshihiro Shimizu 890ddd
	const int wrap = dataRaster->getWrap();
Toshihiro Shimizu 890ddd
	const int delta[] = {-wrap - 1, -wrap, -wrap + 1, 1, wrap + 1, wrap, wrap - 1, -1};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (y = 1; y < dataRaster->getLy() - 1; y++) {
Toshihiro Shimizu 890ddd
		DataPixel *pix = dataRaster->pixels(y);
Toshihiro Shimizu 890ddd
		DataPixel *endPix = pix + dataRaster->getLx() - 1;
Toshihiro Shimizu 890ddd
		pix++;
Toshihiro Shimizu 890ddd
		for (pix++; pix < endPix; ++pix) {
Toshihiro Shimizu 890ddd
			if ((pix->m_ink == false) ||
Toshihiro Shimizu 890ddd
				(pix[-wrap].m_ink && pix[wrap].m_ink &&
Toshihiro Shimizu 890ddd
				 pix[-1].m_ink && pix[1].m_ink))
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			int i;
Toshihiro Shimizu 890ddd
			for (i = 0; i < 8; i++)
Toshihiro Shimizu 890ddd
				if (pix[delta[i]].m_ink && pix[delta[(i + 1) & 0x7]].m_ink == false)
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
			int start = i;
Toshihiro Shimizu 890ddd
			if (i == 8)
Toshihiro Shimizu 890ddd
				continue; // punto isolato
Toshihiro Shimizu 890ddd
			for (;;) {
Toshihiro Shimizu 890ddd
				int j = (i + 1) & 0x7;
Toshihiro Shimizu 890ddd
				assert(i < 8 && pix[delta[i]].m_ink);
Toshihiro Shimizu 890ddd
				assert(j < 8 && pix[delta[j]].m_ink == false);
Toshihiro Shimizu 890ddd
				do
Toshihiro Shimizu 890ddd
					j = (j + 1) & 0x7;
Toshihiro Shimizu 890ddd
				while (pix[delta[j]].m_ink == false);
Toshihiro Shimizu 890ddd
				assert(j < 8 && pix[delta[j]].m_ink);
Toshihiro Shimizu 890ddd
				if (((i + 2) & 0x7) != j || (i & 1) == 0) {
Toshihiro Shimizu 890ddd
					// il bianco comprende anche un fianco
Toshihiro Shimizu 890ddd
					link(pix, pix + delta[i], pix + delta[j]);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				i = j;
Toshihiro Shimizu 890ddd
				assert(i < 8);
Toshihiro Shimizu 890ddd
				while (pix[delta[(i + 1) & 0x7]].m_ink)
Toshihiro Shimizu 890ddd
					i = (i + 1) & 0x7;
Toshihiro Shimizu 890ddd
				assert(i < 8 && pix[delta[i]].m_ink);
Toshihiro Shimizu 890ddd
				assert(pix[delta[(i + 1) & 0x7]].m_ink == false);
Toshihiro Shimizu 890ddd
				if (i == start)
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Node *OutlineVectorizer::createNode(DataPixel *pix)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Node *node = new Node();
Toshihiro Shimizu 890ddd
	node->m_pixel = pix;
Toshihiro Shimizu 890ddd
	node->m_other = pix->m_node;
Toshihiro Shimizu 890ddd
	pix->m_node = node;
Toshihiro Shimizu 890ddd
	m_nodes.push_back(node);
Toshihiro Shimizu 890ddd
	return node;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::clearNodes()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)m_nodes.size(); i++)
Toshihiro Shimizu 890ddd
		delete m_nodes[i];
Toshihiro Shimizu 890ddd
	m_nodes.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::clearJunctions()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)m_junctions.size(); i++)
Toshihiro Shimizu 890ddd
		delete m_junctions[i];
Toshihiro Shimizu 890ddd
	m_junctions.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::link(
Toshihiro Shimizu 890ddd
	DataPixel *pix,
Toshihiro Shimizu 890ddd
	DataPixel *srcPix,
Toshihiro Shimizu 890ddd
	DataPixel *dstPix)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Node *srcNode = 0, *dstNode = 0, *node = 0;
Toshihiro Shimizu 890ddd
	Node *tmp;
Toshihiro Shimizu 890ddd
	for (tmp = pix->m_node; tmp; tmp = tmp->m_other) {
Toshihiro Shimizu 890ddd
		if (tmp->m_pixel == 0)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		if (tmp->m_prev && tmp->m_prev->m_pixel == srcPix) {
Toshihiro Shimizu 890ddd
			assert(srcNode == 0);
Toshihiro Shimizu 890ddd
			if (node) {
Toshihiro Shimizu 890ddd
				assert(node->m_next->m_pixel == dstPix);
Toshihiro Shimizu 890ddd
				assert(node->m_prev == 0);
Toshihiro Shimizu 890ddd
				node->m_prev = tmp->m_prev;
Toshihiro Shimizu 890ddd
				tmp->m_prev->m_next = node;
Toshihiro Shimizu 890ddd
				tmp->m_next = tmp->m_prev = 0;
Toshihiro Shimizu 890ddd
				tmp->m_pixel = 0;
Toshihiro Shimizu 890ddd
				return;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			assert(tmp->m_next == 0);
Toshihiro Shimizu 890ddd
			srcNode = tmp->m_prev;
Toshihiro Shimizu 890ddd
			node = tmp;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (tmp->m_next && tmp->m_next->m_pixel == dstPix) {
Toshihiro Shimizu 890ddd
			assert(dstNode == 0);
Toshihiro Shimizu 890ddd
			if (node) {
Toshihiro Shimizu 890ddd
				assert(node->m_prev->m_pixel == srcPix);
Toshihiro Shimizu 890ddd
				assert(node->m_next == 0);
Toshihiro Shimizu 890ddd
				node->m_next = tmp->m_next;
Toshihiro Shimizu 890ddd
				tmp->m_next->m_prev = node;
Toshihiro Shimizu 890ddd
				tmp->m_next = tmp->m_prev = 0;
Toshihiro Shimizu 890ddd
				tmp->m_pixel = 0;
Toshihiro Shimizu 890ddd
				return;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			assert(tmp->m_prev == 0);
Toshihiro Shimizu 890ddd
			dstNode = tmp->m_next;
Toshihiro Shimizu 890ddd
			node = tmp;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (!node)
Toshihiro Shimizu 890ddd
		node = createNode(pix);
Toshihiro Shimizu 890ddd
	if (!srcNode)
Toshihiro Shimizu 890ddd
		srcNode = createNode(srcPix);
Toshihiro Shimizu 890ddd
	if (!dstNode)
Toshihiro Shimizu 890ddd
		dstNode = createNode(dstPix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!node->m_next) {
Toshihiro Shimizu 890ddd
		node->m_next = dstNode;
Toshihiro Shimizu 890ddd
		assert(dstNode->m_prev == 0);
Toshihiro Shimizu 890ddd
		dstNode->m_prev = node;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (!node->m_prev) {
Toshihiro Shimizu 890ddd
		node->m_prev = srcNode;
Toshihiro Shimizu 890ddd
		assert(srcNode->m_next == 0);
Toshihiro Shimizu 890ddd
		srcNode->m_next = node;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(node->m_next == dstNode);
Toshihiro Shimizu 890ddd
	assert(node->m_prev == srcNode);
Toshihiro Shimizu 890ddd
	assert(dstNode->m_prev == node);
Toshihiro Shimizu 890ddd
	assert(srcNode->m_next == node);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::traceOutline(Node *initialNode)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Node *startNode = initialNode;
Toshihiro Shimizu 890ddd
	Node *node;
Toshihiro Shimizu 890ddd
	do {
Toshihiro Shimizu 890ddd
		if (!startNode)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		node = findOtherSide(startNode);
Toshihiro Shimizu 890ddd
		if (!node)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double startDist2 = computeDistance2(startNode, node);
Toshihiro Shimizu 890ddd
		if (startDist2 > 0.1)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		startNode = startNode->m_next;
Toshihiro Shimizu 890ddd
	} while (startNode != initialNode);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!startNode)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	node = startNode;
Toshihiro Shimizu 890ddd
	std::vector<tthickpoint> points;</tthickpoint>
Toshihiro Shimizu 890ddd
	do {
Toshihiro Shimizu 890ddd
		node = node->m_next;
Toshihiro Shimizu 890ddd
		if (!node)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		node->m_visited = true;
Toshihiro Shimizu 890ddd
		points.push_back(TThickPoint(convert(node->m_pixel->m_pos), 0));
Toshihiro Shimizu 890ddd
	} while (node != startNode);
Toshihiro Shimizu 890ddd
	m_protoOutlines.push_back(points);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Node *OutlineVectorizer::findOtherSide(Node *node)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DataPixel *pix = node->m_pixel;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPoint dir = -computeGradient(pix);
Toshihiro Shimizu 890ddd
	if (dir == TPoint(0, 0))
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	TPoint d1(tsign(dir.x), 0), d2(0, tsign(dir.y));
Toshihiro Shimizu 890ddd
	int num = abs(dir.y), den = abs(dir.x);
Toshihiro Shimizu 890ddd
	if (num > den) {
Toshihiro Shimizu 890ddd
		tswap(d1, d2);
Toshihiro Shimizu 890ddd
		tswap(num, den);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TPoint pos = pix->m_pos;
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0;; i++) {
Toshihiro Shimizu 890ddd
		TPoint q(pos.x + d1.x * i + d2.x * num * i / den, pos.y + d1.y * i + d2.y * num * i / den);
Toshihiro Shimizu 890ddd
		DataPixel *nextPix = m_dataRaster->pixels(q.y) + q.x;
Toshihiro Shimizu 890ddd
		if (nextPix->m_ink == false)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		pix = nextPix;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	assert(pix);
Toshihiro Shimizu 890ddd
	if (!pix->m_node) {
Toshihiro Shimizu 890ddd
		const int wrap = m_dataRaster->getWrap();
Toshihiro Shimizu 890ddd
		if (pix[-1].m_node)
Toshihiro Shimizu 890ddd
			pix--;
Toshihiro Shimizu 890ddd
		else if (pix[1].m_node)
Toshihiro Shimizu 890ddd
			pix++;
Toshihiro Shimizu 890ddd
		else if (pix[wrap].m_node)
Toshihiro Shimizu 890ddd
			pix += wrap;
Toshihiro Shimizu 890ddd
		else if (pix[-wrap].m_node)
Toshihiro Shimizu 890ddd
			pix -= wrap;
Toshihiro Shimizu 890ddd
		else {
Toshihiro Shimizu 890ddd
			assert(0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (!pix->m_node)
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	Node *q = pix->m_node;
Toshihiro Shimizu 890ddd
	while (q->m_pixel == 0 && q->m_other)
Toshihiro Shimizu 890ddd
		q = q->m_other;
Toshihiro Shimizu 890ddd
	assert(q && q->m_pixel == pix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < 5; i++) {
Toshihiro Shimizu 890ddd
		if (!q->m_prev)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		q = q->m_prev;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Node *best = q;
Toshihiro Shimizu 890ddd
	double bestDist2 = computeDistance2(q, node);
Toshihiro Shimizu 890ddd
	for (i = 0; i < 10; i++) {
Toshihiro Shimizu 890ddd
		q = q->m_next;
Toshihiro Shimizu 890ddd
		if (!q)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		double dist2 = computeDistance2(q, node);
Toshihiro Shimizu 890ddd
		if (dist2 < bestDist2) {
Toshihiro Shimizu 890ddd
			bestDist2 = dist2;
Toshihiro Shimizu 890ddd
			best = q;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return best;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::createOutlineStrokes()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_vimage->enableRegionComputing(true, false);
Toshihiro Shimizu 890ddd
	int j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (j = 0; j < (int)m_nodes.size(); j++) {
Toshihiro Shimizu 890ddd
		Node *node = m_nodes[j];
Toshihiro Shimizu 890ddd
		if (node->m_pixel == 0 || node->m_visited)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		traceOutline(node);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef DEBUG
Toshihiro Shimizu 890ddd
	for (j = 0; j < (int)m_nodes.size(); j++) {
Toshihiro Shimizu 890ddd
		Node *node = m_nodes[j];
Toshihiro Shimizu 890ddd
		if (node->m_pixel == 0 || node->m_flag)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		outputNodes(node);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::list<std::vector<tthickpoint>>::iterator it_outlines = m_protoOutlines.begin();</std::vector<tthickpoint>
Toshihiro Shimizu 890ddd
	for (it_outlines; it_outlines != m_protoOutlines.end(); it_outlines++) {
Toshihiro Shimizu 890ddd
		if (it_outlines->size() > 3) {
Toshihiro Shimizu 890ddd
			std::vector<tthickpoint> points;</tthickpoint>
Toshihiro Shimizu 890ddd
			std::vector<tthickpoint>::iterator it;</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (it_outlines->size() > 10) {
Toshihiro Shimizu 890ddd
				it = it_outlines->begin() + 1;
Toshihiro Shimizu 890ddd
				for (;;) {
Toshihiro Shimizu 890ddd
					//Baco: Ricontrolla l'if seguente - in alcuni casi va fuori bounds...
Toshihiro Shimizu 890ddd
					if ((int)it_outlines->size() <= m_configuration.m_smoothness + 1)
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					if (it >= it_outlines->end() - (m_configuration.m_smoothness + 1))
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					for (j = 0; j < m_configuration.m_smoothness; j++)
Toshihiro Shimizu 890ddd
						it = it_outlines->erase(it);
Toshihiro Shimizu 890ddd
					++it;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			points.push_back(it_outlines->front());
Toshihiro Shimizu 890ddd
			it = it_outlines->begin();
Toshihiro Shimizu 890ddd
			TThickPoint old = *it;
Toshihiro Shimizu 890ddd
			++it;
Toshihiro Shimizu 890ddd
			for (; it != it_outlines->end(); ++it) {
Toshihiro Shimizu 890ddd
				TThickPoint point((1 / 2.0) * (*it + old));
Toshihiro Shimizu 890ddd
				points.push_back(point);
Toshihiro Shimizu 890ddd
				old = *it;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			points.push_back(it_outlines->back());
Toshihiro Shimizu 890ddd
			points.push_back(it_outlines->front());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TStroke *stroke = TStroke::interpolate(points, m_configuration.m_interpolationError);
Toshihiro Shimizu 890ddd
			stroke->setStyle(m_configuration.m_strokeStyleId);
Toshihiro Shimizu 890ddd
			stroke->setSelfLoop();
Toshihiro Shimizu 890ddd
			m_vimage->addStroke(stroke);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline int colorDistance2(const TPixel32 &c0, const TPixel32 &c1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return ((c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
#define MAX_TOLERANCE 20
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void OutlineVectorizer::makeDataRaster(const TRasterP &src)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_vimage = new TVectorImage();
Toshihiro Shimizu 890ddd
	if (!src)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_src = src;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	clearNodes();
Toshihiro Shimizu 890ddd
	clearJunctions();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int x, y, ii = 0;
Toshihiro Shimizu 890ddd
	TRaster32P srcRGBM = (TRaster32P)m_src;
Toshihiro Shimizu 890ddd
	TRasterCM32P srcCM = (TRasterCM32P)m_src;
Toshihiro Shimizu 890ddd
	TRasterGR8P srcGR = (TRasterGR8P)m_src;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Inizializzo DataRasterP per i casi in cui si ha un TRaster32P, un TRasterGR8P o un TRasterCM32P molto grande
Toshihiro Shimizu 890ddd
	DataRasterP dataRaster(m_src->getSize().lx + 2, m_src->getSize().ly + 2);
Toshihiro Shimizu 890ddd
	if (srcRGBM || srcGR || (srcCM && srcCM->getLx() * srcCM->getLy() > 5000000)) {
Toshihiro Shimizu 890ddd
		int ly = dataRaster->getLy();
Toshihiro Shimizu 890ddd
		int lx = dataRaster->getLx();
Toshihiro Shimizu 890ddd
		int wrap = dataRaster->getWrap();
Toshihiro Shimizu 890ddd
		DataPixel *dataPix0 = dataRaster->pixels(0);
Toshihiro Shimizu 890ddd
		DataPixel *dataPix1 = dataRaster->pixels(0) + m_src->getLx() + 1;
Toshihiro Shimizu 890ddd
		for (y = 0; y < ly; y++, dataPix0 += wrap, dataPix1 += wrap) {
Toshihiro Shimizu 890ddd
			dataPix0->m_pos.x = 0;
Toshihiro Shimizu 890ddd
			dataPix1->m_pos.x = lx - 1;
Toshihiro Shimizu 890ddd
			dataPix0->m_pos.y = dataPix1->m_pos.y = y;
Toshihiro Shimizu 890ddd
			dataPix0->m_value = dataPix1->m_value = 0;
Toshihiro Shimizu 890ddd
			dataPix0->m_ink = dataPix1->m_ink = false;
Toshihiro Shimizu 890ddd
			dataPix0->m_node = dataPix1->m_node = 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		dataPix0 = dataRaster->pixels(0);
Toshihiro Shimizu 890ddd
		dataPix1 = dataRaster->pixels(ly - 1);
Toshihiro Shimizu 890ddd
		for (x = 0; x < lx; x++, dataPix0++, dataPix1++) {
Toshihiro Shimizu 890ddd
			dataPix0->m_pos.x = dataPix1->m_pos.x = x;
Toshihiro Shimizu 890ddd
			dataPix0->m_pos.y = 0;
Toshihiro Shimizu 890ddd
			dataPix1->m_pos.y = ly - 1;
Toshihiro Shimizu 890ddd
			dataPix0->m_value = dataPix1->m_value = 0;
Toshihiro Shimizu 890ddd
			dataPix0->m_ink = dataPix1->m_ink = false;
Toshihiro Shimizu 890ddd
			dataPix0->m_node = dataPix1->m_node = 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (srcRGBM) {
Toshihiro Shimizu 890ddd
		assert(m_palette);
Toshihiro Shimizu 890ddd
		int inkId = m_palette->getClosestStyle(m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
		if (!inkId || m_configuration.m_inkColor != m_palette->getStyle(inkId)->getMainColor()) {
Toshihiro Shimizu 890ddd
			inkId = m_palette->getStyleCount();
Toshihiro Shimizu 890ddd
			m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
			m_palette->setStyle(inkId, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		assert(inkId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_dataRasterArray.push_back(pair<int, datarasterp="">(inkId, dataRaster));</int,>
Toshihiro Shimizu 890ddd
		int maxDistance2 = m_configuration.m_threshold * m_configuration.m_threshold;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (y = 0; y < m_src->getLy(); y++) {
Toshihiro Shimizu 890ddd
			TPixel32 *inPix = srcRGBM->pixels(y);
Toshihiro Shimizu 890ddd
			TPixel32 *inEndPix = inPix + srcRGBM->getLx();
Toshihiro Shimizu 890ddd
			DataPixel *dataPix = dataRaster->pixels(y + 1) + 1;
Toshihiro Shimizu 890ddd
			x = 0;
Toshihiro Shimizu 890ddd
			while (inPix < inEndPix) {
Toshihiro Shimizu 890ddd
				*dataPix = DataPixel();
Toshihiro Shimizu 890ddd
				int distance2 = colorDistance2(m_configuration.m_inkColor, *inPix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (y == 0 || y == m_src->getLy() - 1 || x == 0 || x == m_src->getLx() - 1 || inPix->m == 0) {
Toshihiro Shimizu 890ddd
					dataPix->m_value = 255;
Toshihiro Shimizu 890ddd
					dataPix->m_ink = false;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					dataPix->m_value = (inPix->r + 2 * inPix->g + inPix->b) >> 2;
Toshihiro Shimizu 890ddd
					dataPix->m_ink = (distance2 < maxDistance2);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				dataPix->m_pos.x = x++;
Toshihiro Shimizu 890ddd
				dataPix->m_pos.y = y;
Toshihiro Shimizu 890ddd
				dataPix->m_node = 0;
Toshihiro Shimizu 890ddd
				inPix++;
Toshihiro Shimizu 890ddd
				dataPix++;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (srcGR) {
Toshihiro Shimizu 890ddd
		assert(m_palette);
Toshihiro Shimizu 890ddd
		int inkId = m_palette->getClosestStyle(m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
		if (!inkId || m_configuration.m_inkColor != m_palette->getStyle(inkId)->getMainColor()) {
Toshihiro Shimizu 890ddd
			inkId = m_palette->getStyleCount();
Toshihiro Shimizu 890ddd
			m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
			m_palette->setStyle(inkId, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		assert(inkId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_dataRasterArray.push_back(pair<int, datarasterp="">(inkId, dataRaster));</int,>
Toshihiro Shimizu 890ddd
		int threshold = m_configuration.m_threshold;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (y = 0; y < m_src->getLy(); y++) {
Toshihiro Shimizu 890ddd
			TPixelGR8 *inPix = srcGR->pixels(y);
Toshihiro Shimizu 890ddd
			TPixelGR8 *inEndPix = inPix + srcGR->getLx();
Toshihiro Shimizu 890ddd
			DataPixel *dataPix = dataRaster->pixels(y + 1) + 1;
Toshihiro Shimizu 890ddd
			x = 0;
Toshihiro Shimizu 890ddd
			while (inPix < inEndPix) {
Toshihiro Shimizu 890ddd
				*dataPix = DataPixel();
Toshihiro Shimizu 890ddd
				if (y == 0 || y == m_src->getLy() - 1 || x == 0 || x == m_src->getLx() - 1) {
Toshihiro Shimizu 890ddd
					dataPix->m_value = 255;
Toshihiro Shimizu 890ddd
					dataPix->m_ink = false;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					dataPix->m_value = inPix->value;
Toshihiro Shimizu 890ddd
					dataPix->m_ink = (inPix->value < threshold);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				dataPix->m_pos.x = x++;
Toshihiro Shimizu 890ddd
				dataPix->m_pos.y = y;
Toshihiro Shimizu 890ddd
				dataPix->m_node = 0;
Toshihiro Shimizu 890ddd
				inPix++;
Toshihiro Shimizu 890ddd
				dataPix++;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	else if (srcCM) {
Toshihiro Shimizu 890ddd
		int currInk, nextInk = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (srcCM->getLx() * srcCM->getLy() > 5000000) {
Toshihiro Shimizu 890ddd
			int threshold = m_configuration.m_threshold;
Toshihiro Shimizu 890ddd
			int inkId = m_palette->getClosestStyle(TPixel::Black);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (TPixel::Black != m_palette->getStyle(inkId)->getMainColor()) {
Toshihiro Shimizu 890ddd
				inkId = m_palette->getStyleCount();
Toshihiro Shimizu 890ddd
				m_palette->getStylePage(1)->insertStyle(1, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
				m_palette->setStyle(inkId, m_configuration.m_inkColor);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			assert(inkId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_dataRasterArray.push_back(pair<int, datarasterp="">(inkId, dataRaster));</int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// inizializza la parte centrale
Toshihiro Shimizu 890ddd
			for (y = 0; y < m_src->getLy(); y++) {
Toshihiro Shimizu 890ddd
				TPixelCM32 *inPix = srcCM->pixels(y);
Toshihiro Shimizu 890ddd
				TPixelCM32 *inEndPix = inPix + m_src->getLx();
Toshihiro Shimizu 890ddd
				DataPixel *dataPix = dataRaster->pixels(y + 1) + 1;
Toshihiro Shimizu 890ddd
				x = 0;
Toshihiro Shimizu 890ddd
				while (inPix < inEndPix) {
Toshihiro Shimizu 890ddd
					*dataPix = DataPixel();
Toshihiro Shimizu 890ddd
					int value = inPix->getTone();
Toshihiro Shimizu 890ddd
					if (m_configuration.m_ignoreInkColors)
Toshihiro Shimizu 890ddd
						inkId = 1;
Toshihiro Shimizu 890ddd
					if (y == 0 || y == m_src->getLy() - 1 || x == 0 || x == m_src->getLx() - 1) {
Toshihiro Shimizu 890ddd
						dataPix->m_value = 255;
Toshihiro Shimizu 890ddd
						dataPix->m_ink = false;
Toshihiro Shimizu 890ddd
					} else {
Toshihiro Shimizu 890ddd
						dataPix->m_value = value;
Toshihiro Shimizu 890ddd
						dataPix->m_ink = (value < threshold);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
					dataPix->m_pos.x = x++;
Toshihiro Shimizu 890ddd
					dataPix->m_pos.y = y;
Toshihiro Shimizu 890ddd
					dataPix->m_node = 0;
Toshihiro Shimizu 890ddd
					inPix++;
Toshihiro Shimizu 890ddd
					dataPix++;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			do {
Toshihiro Shimizu 890ddd
				// Inizializzo DataRasterP
Toshihiro Shimizu 890ddd
				DataRasterP dataRaster(m_src->getSize().lx + 2, m_src->getSize().ly + 2);
Toshihiro Shimizu 890ddd
				int ly = dataRaster->getLy();
Toshihiro Shimizu 890ddd
				int lx = dataRaster->getLx();
Toshihiro Shimizu 890ddd
				int wrap = dataRaster->getWrap();
Toshihiro Shimizu 890ddd
				DataPixel *dataPix0 = dataRaster->pixels(0);
Toshihiro Shimizu 890ddd
				DataPixel *dataPix1 = dataRaster->pixels(0) + m_src->getLx() + 1;
Toshihiro Shimizu 890ddd
				for (y = 0; y < ly; y++, dataPix0 += wrap, dataPix1 += wrap) {
Toshihiro Shimizu 890ddd
					dataPix0->m_pos.x = 0;
Toshihiro Shimizu 890ddd
					dataPix1->m_pos.x = lx - 1;
Toshihiro Shimizu 890ddd
					dataPix0->m_pos.y = dataPix1->m_pos.y = y;
Toshihiro Shimizu 890ddd
					dataPix0->m_value = dataPix1->m_value = 0;
Toshihiro Shimizu 890ddd
					dataPix0->m_ink = dataPix1->m_ink = false;
Toshihiro Shimizu 890ddd
					dataPix0->m_node = dataPix1->m_node = 0;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				dataPix0 = dataRaster->pixels(0);
Toshihiro Shimizu 890ddd
				dataPix1 = dataRaster->pixels(ly - 1);
Toshihiro Shimizu 890ddd
				for (x = 0; x < lx; x++, dataPix0++, dataPix1++) {
Toshihiro Shimizu 890ddd
					dataPix0->m_pos.x = dataPix1->m_pos.x = x;
Toshihiro Shimizu 890ddd
					dataPix0->m_pos.y = 0;
Toshihiro Shimizu 890ddd
					dataPix1->m_pos.y = ly - 1;
Toshihiro Shimizu 890ddd
					dataPix0->m_value = dataPix1->m_value = 0;
Toshihiro Shimizu 890ddd
					dataPix0->m_ink = dataPix1->m_ink = false;
Toshihiro Shimizu 890ddd
					dataPix0->m_node = dataPix1->m_node = 0;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				int threshold = m_configuration.m_threshold; //tolerance: 1->MAX thresh: 1-255
Toshihiro Shimizu 890ddd
				currInk = nextInk;
Toshihiro Shimizu 890ddd
				nextInk = 0;
Toshihiro Shimizu 890ddd
				m_dataRasterArray.push_back(pair<int, datarasterp="">(currInk, dataRaster));</int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				// inizializza la parte centrale
Toshihiro Shimizu 890ddd
				for (y = 0; y < m_src->getLy(); y++) {
Toshihiro Shimizu 890ddd
					TPixelCM32 *inPix = srcCM->pixels(y);
Toshihiro Shimizu 890ddd
					TPixelCM32 *inEndPix = inPix + m_src->getLx();
Toshihiro Shimizu 890ddd
					DataPixel *dataPix = dataRaster->pixels(y + 1) + 1;
Toshihiro Shimizu 890ddd
					x = 0;
Toshihiro Shimizu 890ddd
					while (inPix < inEndPix) {
Toshihiro Shimizu 890ddd
						*dataPix = DataPixel();
Toshihiro Shimizu 890ddd
						int value = inPix->getTone();
Toshihiro Shimizu 890ddd
						if (value < 255 && !m_configuration.m_ignoreInkColors) {
Toshihiro Shimizu 890ddd
							int ink = inPix->getInk();
Toshihiro Shimizu 890ddd
							if (currInk == 0) {
Toshihiro Shimizu 890ddd
								currInk = ink;
Toshihiro Shimizu 890ddd
								m_dataRasterArray.back().first = ink;
Toshihiro Shimizu 890ddd
							} else if (ink != currInk) {
Toshihiro Shimizu 890ddd
								value = 255;
Toshihiro Shimizu 890ddd
								if (nextInk == 0) {
Toshihiro Shimizu 890ddd
									for (ii = 0; ii < (int)m_dataRasterArray.size() - 1; ii++)
Toshihiro Shimizu 890ddd
										if (m_dataRasterArray[ii].first == ink)
Toshihiro Shimizu 890ddd
											break;
Toshihiro Shimizu 890ddd
									if (ii == (int)m_dataRasterArray.size() - 1)
Toshihiro Shimizu 890ddd
										nextInk = ink;
Toshihiro Shimizu 890ddd
								}
Toshihiro Shimizu 890ddd
							}
Toshihiro Shimizu 890ddd
						}
Toshihiro Shimizu 890ddd
						dataPix->m_pos.x = x++;
Toshihiro Shimizu 890ddd
						dataPix->m_pos.y = y;
Toshihiro Shimizu 890ddd
						dataPix->m_value = value;
Toshihiro Shimizu 890ddd
						dataPix->m_ink = (value < threshold);
Toshihiro Shimizu 890ddd
						dataPix->m_node = 0;
Toshihiro Shimizu 890ddd
						inPix++;
Toshihiro Shimizu 890ddd
						dataPix++;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} while (nextInk != 0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (m_configuration.m_ignoreInkColors) {
Toshihiro Shimizu 890ddd
			assert(m_dataRasterArray.size() == 1);
Toshihiro Shimizu 890ddd
			m_dataRasterArray.back().first = 1;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		assert(false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP VectorizerCore::outlineVectorize(const TImageP &image, const OutlineConfiguration &configuration, TPalette *palette)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TVectorImageP out;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	OutlineVectorizer vectorizer(configuration, palette);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterImageP ri = image;
Toshihiro Shimizu 890ddd
	TToonzImageP vi = image;
Toshihiro Shimizu 890ddd
	if (ri)
Toshihiro Shimizu 890ddd
		vectorizer.makeDataRaster(ri->getRaster());
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		vectorizer.makeDataRaster(vi->getRaster());
Toshihiro Shimizu 890ddd
	int layersCount = vectorizer.m_dataRasterArray.size();
Toshihiro Shimizu 890ddd
	if (layersCount > 1) {
Toshihiro Shimizu 890ddd
		out = new TVectorImage();
Toshihiro Shimizu 890ddd
		out->setPalette(palette);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)layersCount; i++) {
Toshihiro Shimizu 890ddd
		vectorizer.m_dataRaster = vectorizer.m_dataRasterArray[i].second;
Toshihiro Shimizu 890ddd
		vectorizer.m_configuration.m_strokeStyleId = vectorizer.m_dataRasterArray[i].first;
Toshihiro Shimizu 890ddd
		vectorizer.m_protoOutlines.clear();
Toshihiro Shimizu 890ddd
		vectorizer.init();
Toshihiro Shimizu 890ddd
		vectorizer.createOutlineStrokes();
Toshihiro Shimizu 890ddd
		renormalizeImage(vectorizer.m_vimage.getPointer());
Toshihiro Shimizu 890ddd
		vectorizer.m_vimage->setPalette(palette);
Toshihiro Shimizu 890ddd
		if (layersCount > 1)
Toshihiro Shimizu 890ddd
			out->mergeImage(vectorizer.m_vimage, TAffine());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (i != (int)layersCount - 1)
Toshihiro Shimizu 890ddd
			vectorizer.m_vimage = new TVectorImage();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (layersCount == 1) ? vectorizer.m_vimage : out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool isPointInRegion(TPointD p, TRegion *r)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < 5; i++) {
Toshihiro Shimizu 890ddd
		double stepX = i * 0.2;
Toshihiro Shimizu 890ddd
		int j;
Toshihiro Shimizu 890ddd
		for (j = 0; j < 5; j++) {
Toshihiro Shimizu 890ddd
			double stepY = j * 0.2;
Toshihiro Shimizu 890ddd
			if (r->contains(TPointD(p.x + stepX, p.y + stepY)))
Toshihiro Shimizu 890ddd
				return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Se findInk == true :
Toshihiro Shimizu 890ddd
//    trova il punto piu' vicino a p con ink puro e restituisce true se e' contenuto nella regione
Toshihiro Shimizu 890ddd
// Se findInk == false :
Toshihiro Shimizu 890ddd
//    Trova il punto piu' vicino a p con paint puro e restituisce true se e' contenuto nella regione
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//(Daniele) Aggiunti controlli per evitare uscite dai bounds
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool isNearestInkOrPaintInRegion(bool findInk, const TRasterCM32P &ras, TRegion *r,
Toshihiro Shimizu 890ddd
								 const TAffine &aff, const TPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool isTheLastSquare = false;
Toshihiro Shimizu 890ddd
	int mx, my, Mx, My;
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 1; i <= 100; i++) {
Toshihiro Shimizu 890ddd
		int j, t, s, e;
Toshihiro Shimizu 890ddd
		if (p.x - i >= 0) {
Toshihiro Shimizu 890ddd
			my = tmax(p.y - i, 0);
Toshihiro Shimizu 890ddd
			My = tmin(p.y + i, ras->getLy() - 1);
Toshihiro Shimizu 890ddd
			for (j = my; j <= My; j++) {
Toshihiro Shimizu 890ddd
				TPixelCM32 col = ras->pixels(j)[p.x - i];
Toshihiro Shimizu 890ddd
				int tone = col.getTone();
Toshihiro Shimizu 890ddd
				if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Toshihiro Shimizu 890ddd
					if (isPointInRegion(aff * TPointD(double(p.x - i), double(j)), r))
Toshihiro Shimizu 890ddd
						return true;
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						isTheLastSquare = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (p.y + i < ras->getLy()) {
Toshihiro Shimizu 890ddd
			mx = tmax(p.x - i + 1, 0);
Toshihiro Shimizu 890ddd
			Mx = tmin(p.x + i, ras->getLx() - 1);
Toshihiro Shimizu 890ddd
			for (t = mx; t <= Mx; t++) {
Toshihiro Shimizu 890ddd
				TPixelCM32 col = ras->pixels(p.y + i)[t];
Toshihiro Shimizu 890ddd
				int tone = col.getTone();
Toshihiro Shimizu 890ddd
				if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Toshihiro Shimizu 890ddd
					if (isPointInRegion(aff * TPointD(double(t), double(p.y + i)), r))
Toshihiro Shimizu 890ddd
						return true;
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						isTheLastSquare = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (p.x + i < ras->getLx()) {
Toshihiro Shimizu 890ddd
			my = tmax(p.y - i, 0);
Toshihiro Shimizu 890ddd
			My = tmin(p.y + i - 1, ras->getLy() - 1);
Toshihiro Shimizu 890ddd
			for (s = my; s <= My; s++) {
Toshihiro Shimizu 890ddd
				TPixelCM32 col = ras->pixels(s)[p.x + i];
Toshihiro Shimizu 890ddd
				int tone = col.getTone();
Toshihiro Shimizu 890ddd
				if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Toshihiro Shimizu 890ddd
					if (isPointInRegion(aff * TPointD(double(p.x + i), double(s)), r))
Toshihiro Shimizu 890ddd
						return true;
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						isTheLastSquare = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (p.y - i >= 0) {
Toshihiro Shimizu 890ddd
			mx = tmax(p.x - i + 1, 0);
Toshihiro Shimizu 890ddd
			Mx = tmin(p.x + i - 1, ras->getLx() - 1);
Toshihiro Shimizu 890ddd
			for (e = mx; e <= Mx; e++) {
Toshihiro Shimizu 890ddd
				TPixelCM32 col = ras->pixels(p.y - i)[e];
Toshihiro Shimizu 890ddd
				int tone = col.getTone();
Toshihiro Shimizu 890ddd
				if ((findInk && tone == 0) || (!findInk && tone == 255)) {
Toshihiro Shimizu 890ddd
					if (isPointInRegion(aff * TPointD(double(e), double(p.y - i)), r))
Toshihiro Shimizu 890ddd
						return true;
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						isTheLastSquare = true;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (isTheLastSquare)
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isBright(const TPixelCM32 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return pix.getTone() >= threshold;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isBright(const TPixelGR8 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return pix.value >= threshold;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isBright(const TPixel32 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Using Value in HSV color model
Toshihiro Shimizu 890ddd
	return tmax(pix.r, tmax(pix.g, pix.b)) >= threshold * (pix.m / 255.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Using Lightness in HSL color model
Toshihiro Shimizu 890ddd
	//return (max(pix.r,max(pix.g,pix.b)) + min(pix.r,min(pix.g,pix.b))) / 2.0
Toshihiro Shimizu 890ddd
	//  >= threshold * (pix.m / 255.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Using (relative) Luminance
Toshihiro Shimizu 890ddd
	//return 0.2126 * pix.r + 0.7152 * pix.g + 0.0722 * pix.b >= threshold * (pix.m / 255.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isDark(const TPixelCM32 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isDark(const TPixelGR8 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isDark(const TPixelRGBM32 &pix, int threshold)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return !isBright(pix, threshold);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pix,="" selector="" typename=""></typename>
Toshihiro Shimizu 890ddd
bool getInternalPoint(const TRasterPT<pix> &ras, const Selector &sel,</pix>
Toshihiro Shimizu 890ddd
					  const TAffine &inverse, const VectorizerConfiguration &c,
Toshihiro Shimizu 890ddd
					  const TRegion *region, TPointD &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct Locals {
Toshihiro Shimizu 890ddd
		const TRasterPT<pix> &m_ras;</pix>
Toshihiro Shimizu 890ddd
		const Selector &m_sel;
Toshihiro Shimizu 890ddd
		const TAffine &m_inverse;
Toshihiro Shimizu 890ddd
		double m_pixelSize;
Toshihiro Shimizu 890ddd
		const TRegion &m_region;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static bool contains(const TRegion ®ion, const TPointD &p)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return region.getBBox().contains(p) && (region.leftScanlineIntersections(p.x, p.y) % 2);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool contains(const TPointD &p)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (!contains(m_region, p))
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			UINT sr, srCount = m_region.getSubregionCount();
Toshihiro Shimizu 890ddd
			for (sr = 0; sr != srCount; ++sr) {
Toshihiro Shimizu 890ddd
				if (contains(*m_region.getSubregion(sr), p))
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Subdivide the output scanline in even intervals, and sample each's midpoint
Toshihiro Shimizu 890ddd
		bool sampleMidpoints(TPointD &p,
Toshihiro Shimizu 890ddd
							 double x0, double x1, double y, int intervalsCount)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const double iCountD = intervalsCount;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (int i = 0; i != intervalsCount; ++i) {
Toshihiro Shimizu 890ddd
				double i_x0 = tcg::numeric_ops::lerp(x0, x1, i / iCountD),
Toshihiro Shimizu 890ddd
					   i_x1 = tcg::numeric_ops::lerp(x0, x1, (i + 1) / iCountD);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (sample(p = TPointD(0.5 * (i_x0 + i_x1), y)))
Toshihiro Shimizu 890ddd
					return true;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Sample the output scanline's midpoint
Toshihiro Shimizu 890ddd
		bool sample(TPointD &point)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return (contains(point) && adjustPoint(point) // Ensures that point is inRaster()
Toshihiro Shimizu 890ddd
					&& selected(point));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPoint toRaster(const TPointD &p)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const TPointD &pRasD = m_inverse * p;
Toshihiro Shimizu 890ddd
			return TPoint(pRasD.x, pRasD.y);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool inRaster(const TPointD &point)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const TPoint &pRas = toRaster(point);
Toshihiro Shimizu 890ddd
			return (pRas.x >= 0 && pRas.x < m_ras->getLx() && pRas.y >= 0 && pRas.y < m_ras->getLy());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool selected(const TPointD &point)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			assert(inRaster(point));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const TPoint &pRas = toRaster(point);
Toshihiro Shimizu 890ddd
			return m_sel(m_ras->pixels(pRas.y)[pRas.x]);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool adjustPoint(TPointD &p)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const TRectD &bbox = m_region.getBBox();
Toshihiro Shimizu 890ddd
			const double tol = tmax(1e-1 * m_pixelSize, 1e-4);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TPointD newP = p;
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				// Adjust along x axis
Toshihiro Shimizu 890ddd
				int iCount = scanlineIntersectionsBefore(newP.x, newP.y, true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double in0 = newP.x, out0 = bbox.x0, in1 = newP.x, out1 = bbox.x1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				isolateBorderX(in0, out0, newP.y, iCount, tol);
Toshihiro Shimizu 890ddd
				isolateBorderX(in1, out1, newP.y, iCount, tol);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				newP = TPointD(0.5 * (in0 + in1), newP.y);
Toshihiro Shimizu 890ddd
				assert(scanlineIntersectionsBefore(newP.x, newP.y, true) == iCount);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				// Adjust along y axis
Toshihiro Shimizu 890ddd
				int iCount = scanlineIntersectionsBefore(newP.x, newP.y, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double in0 = newP.y, out0 = bbox.y0, in1 = newP.y, out1 = bbox.y1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				isolateBorderY(newP.x, in0, out0, iCount, tol);
Toshihiro Shimizu 890ddd
				isolateBorderY(newP.x, in1, out1, iCount, tol);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				newP = TPointD(newP.x, 0.5 * (in0 + in1));
Toshihiro Shimizu 890ddd
				assert(scanlineIntersectionsBefore(newP.x, newP.y, false) == iCount);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return inRaster(newP) ? (p = newP, true) : false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void isolateBorderX(double &xIn, double &xOut, double y, int iCount,
Toshihiro Shimizu 890ddd
							const double tol)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			assert(scanlineIntersectionsBefore(xIn, y, true) == iCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			while (true) {
Toshihiro Shimizu 890ddd
				// Subdivide current interval
Toshihiro Shimizu 890ddd
				double mid = 0.5 * (xIn + xOut);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (scanlineIntersectionsBefore(mid, y, true) == iCount)
Toshihiro Shimizu 890ddd
					xIn = mid;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					xOut = mid;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (std::abs(xOut - xIn) < tol)
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void isolateBorderY(double x, double &yIn, double &yOut, int iCount,
Toshihiro Shimizu 890ddd
							const double tol)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			assert(scanlineIntersectionsBefore(x, yIn, false) == iCount);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			while (true) {
Toshihiro Shimizu 890ddd
				// Subdivide current interval
Toshihiro Shimizu 890ddd
				double mid = 0.5 * (yIn + yOut);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (scanlineIntersectionsBefore(x, mid, false) == iCount)
Toshihiro Shimizu 890ddd
					yIn = mid;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					yOut = mid;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (std::abs(yOut - yIn) < tol)
Toshihiro Shimizu 890ddd
					break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int scanlineIntersectionsBefore(double x, double y, bool hor)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			int result = m_region.scanlineIntersectionsBefore(x, y, hor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			UINT sr, srCount = m_region.getSubregionCount();
Toshihiro Shimizu 890ddd
			for (sr = 0; sr != srCount; ++sr)
Toshihiro Shimizu 890ddd
				result += m_region.getSubregion(sr)->scanlineIntersectionsBefore(x, y, hor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return result;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} locals = {ras, sel, inverse, c.m_thickScale, *region};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(region);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TRectD ®ionBBox = region->getBBox();
Toshihiro Shimizu 890ddd
	double regionMidY = 0.5 * (regionBBox.y0 + regionBBox.y1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int ic, icEnd = tceil((regionBBox.x1 - regionBBox.x0) / c.m_thickScale) + 1; // Say you have 4 pixels, in [0, 4]. We want to
Toshihiro Shimizu 890ddd
																				 // have at least 4 intervals where midpoints are
Toshihiro Shimizu 890ddd
																				 // taken - so end intervals count is 5.
Toshihiro Shimizu 890ddd
	for (ic = 1; ic < icEnd; ic *= 2) {
Toshihiro Shimizu 890ddd
		if (locals.sampleMidpoints(p, regionBBox.x0, regionBBox.x1, regionMidY, ic))
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//(Daniele)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Taking lone, unchecked points is dangerous - they could lie inside
Toshihiro Shimizu 890ddd
//region r and still have a wrong color (for example, if they lie
Toshihiro Shimizu 890ddd
//*on* a boundary stroke).
Toshihiro Shimizu 890ddd
//Plus, over-threshold regions should always be considered black.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//In order to improve this, we search a 4way-local-brightest
Toshihiro Shimizu 890ddd
//neighbour of p. Observe that, however, it may still lie outside r;
Toshihiro Shimizu 890ddd
//would that happen, p was not significative in the first place.
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TPixel32 takeLocalBrightest(const TRaster32P rr, TRegion *r, const VectorizerConfiguration &c, TPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPoint pMax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (r->contains(c.m_affine * convert(p))) {
Toshihiro Shimizu 890ddd
		pMax = p;
Toshihiro Shimizu 890ddd
		if (p.x > 0 && rr->pixels(p.y)[p.x - 1] > rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x - 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.x < rr->getLx() - 1 && rr->pixels(p.y)[p.x + 1] > rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x + 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.y > 0 && rr->pixels(p.y - 1)[p.x] > rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y - 1);
Toshihiro Shimizu 890ddd
		if (p.y < rr->getLy() - 1 && rr->pixels(p.y + 1)[p.x] > rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (p == pMax)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p = pMax;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isBright(rr->pixels(p.y)[p.x], c.m_threshold))
Toshihiro Shimizu 890ddd
		return TPixel32::Black;
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		return rr->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TPixel32 takeLocalBrightest(const TRasterGR8P rgr, TRegion *r, const VectorizerConfiguration &c, TPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPoint pMax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (r->contains(c.m_affine * convert(p))) {
Toshihiro Shimizu 890ddd
		pMax = p;
Toshihiro Shimizu 890ddd
		if (p.x > 0 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y)[p.x - 1])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x - 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.x < rgr->getLx() - 1 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y)[p.x + 1])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x + 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.y > 0 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y - 1)[p.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y - 1);
Toshihiro Shimizu 890ddd
		if (p.y < rgr->getLy() - 1 && rgr->pixels(pMax.y)[pMax.x] < rgr->pixels(p.y + 1)[p.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (p == pMax)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p = pMax;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isBright(rgr->pixels(p.y)[p.x], c.m_threshold))
Toshihiro Shimizu 890ddd
		return TPixel32::Black;
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		int val = rgr->pixels(p.y)[p.x].value;
Toshihiro Shimizu 890ddd
		return TPixel32(val, val, val, 255);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TPixel32 takeLocalDarkest(const TRaster32P rr, TRegion *r, const VectorizerConfiguration &c, TPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPoint pMax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (r->contains(c.m_affine * convert(p))) //1
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		pMax = p;
Toshihiro Shimizu 890ddd
		if (p.x > 0 && rr->pixels(p.y)[p.x - 1] < rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x - 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.x < rr->getLx() - 1 && rr->pixels(p.y)[p.x + 1] < rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x + 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.y > 0 && rr->pixels(p.y - 1)[p.x] < rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y - 1);
Toshihiro Shimizu 890ddd
		if (p.y < rr->getLy() - 1 && rr->pixels(p.y + 1)[p.x] < rr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (p == pMax)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p = pMax;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return rr->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TPixel32 takeLocalDarkest(const TRasterGR8P rgr, TRegion *r, const VectorizerConfiguration &c, TPoint &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPoint pMax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (r->contains(c.m_affine * convert(p))) {
Toshihiro Shimizu 890ddd
		pMax = p;
Toshihiro Shimizu 890ddd
		if (p.x > 0 && rgr->pixels(p.y)[p.x - 1] < rgr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x - 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.x < rgr->getLx() - 1 && rgr->pixels(p.y)[p.x + 1] < rgr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x + 1, p.y);
Toshihiro Shimizu 890ddd
		if (p.y > 0 && rgr->pixels(p.y - 1)[p.x] < rgr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y - 1);
Toshihiro Shimizu 890ddd
		if (p.y < rgr->getLy() - 1 && rgr->pixels(p.y + 1)[p.x] < rgr->pixels(pMax.y)[pMax.x])
Toshihiro Shimizu 890ddd
			pMax = TPoint(p.x, p.y + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (p == pMax)
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p = pMax;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int val = rgr->pixels(p.y)[p.x].value;
Toshihiro Shimizu 890ddd
	return TPixel32(val, val, val, 255);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================
Toshihiro Shimizu 890ddd
//  Vectorizer Core
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void VectorizerCore::applyFillColors(TRegion *r, const TRasterP &ras, TPalette *palette,
Toshihiro Shimizu 890ddd
									 const CenterlineConfiguration &c, int regionCount)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static inline bool alwaysTrue(const TPixelCM32 &) { return true; }
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TRasterCM32P rt = ras;
Toshihiro Shimizu 890ddd
	TRaster32P rr = ras;
Toshihiro Shimizu 890ddd
	TRasterGR8P rgr = ras;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(rt || rr || rgr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isBrightRegion = true;
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		unsigned int e, edgesCount = r->getEdgeCount();
Toshihiro Shimizu 890ddd
		for (e = 0; e < edgesCount; ++e) {
Toshihiro Shimizu 890ddd
			if (isInkRegionEdge(r->getEdge(e)->m_s)) {
Toshihiro Shimizu 890ddd
				if (r->getEdge(e)->m_w0 > r->getEdge(e)->m_w1)
Toshihiro Shimizu 890ddd
					isBrightRegion = false;
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (isInkRegionEdgeReversed(r->getEdge(e)->m_s)) {
Toshihiro Shimizu 890ddd
				if (r->getEdge(e)->m_w0 < r->getEdge(e)->m_w1)
Toshihiro Shimizu 890ddd
					isBrightRegion = false;
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TAffine inverse = c.m_affine.inv();
Toshihiro Shimizu 890ddd
	TPointD pd;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef bool (*cm_func)(const TPixelCM32 &, int);
Toshihiro Shimizu 890ddd
	typedef bool (*rgbm_func)(const TPixelRGBM32 &, int);
Toshihiro Shimizu 890ddd
	typedef bool (*gr_func)(const TPixelGR8 &, int);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool tookPoint = isBrightRegion ? rt ? getInternalPoint(rt, tcg::bind2nd(cm_func(isBright), c.m_threshold), inverse, c, r, pd) || // If no bright pixel could be found,
Toshihiro Shimizu 890ddd
											   getInternalPoint(rt, locals::alwaysTrue, inverse, c, r, pd)
Toshihiro Shimizu 890ddd
										 :																								   // then any pixel inside the region
Toshihiro Shimizu 890ddd
										  rr ? getInternalPoint(rr, tcg::bind2nd(rgbm_func(isBright), c.m_threshold), inverse, c, r, pd) : // must suffice.
Toshihiro Shimizu 890ddd
											  getInternalPoint(rgr, tcg::bind2nd(gr_func(isBright), c.m_threshold), inverse, c, r, pd)
Toshihiro Shimizu 890ddd
									: rt ? getInternalPoint(rt, tcg::bind2nd(cm_func(isDark), c.m_threshold), inverse, c, r, pd) : rr ? getInternalPoint(rr, tcg::bind2nd(rgbm_func(isDark), c.m_threshold), inverse, c, r, pd) : getInternalPoint(rgr, tcg::bind2nd(gr_func(isDark), c.m_threshold), inverse, c, r, pd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (tookPoint) {
Toshihiro Shimizu 890ddd
		pd = inverse * pd;
Toshihiro Shimizu 890ddd
		TPoint p(pd.x, pd.y); // The same thing that happened inside
Toshihiro Shimizu 890ddd
							  // getInternalPoint()
Toshihiro Shimizu 890ddd
		if (ras->getBounds().contains(p)) {
Toshihiro Shimizu 890ddd
			int styleId = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (rt) {
Toshihiro Shimizu 890ddd
				TPixelCM32 col = rt->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
				styleId = isBrightRegion ? col.getPaint() : col.getInk(); // Only paint colors with centerline
Toshihiro Shimizu 890ddd
			}															  // vectorization
Toshihiro Shimizu 890ddd
			else {
Toshihiro Shimizu 890ddd
				TPixel32 color;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				// Update color found to local brightness-extremals
Toshihiro Shimizu 890ddd
				if (rr) {
Toshihiro Shimizu 890ddd
					color = isBrightRegion ? takeLocalBrightest(rr, r, c, p) : takeLocalDarkest(rr, r, c, p);
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					color = isBrightRegion ? takeLocalBrightest(rgr, r, c, p) : takeLocalDarkest(rgr, r, c, p);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (color.m != 0) {
Toshihiro Shimizu 890ddd
					styleId = palette->getClosestStyle(color);
Toshihiro Shimizu 890ddd
					TPixel32 oldColor = palette->getStyle(styleId)->getMainColor();
Toshihiro Shimizu 890ddd
					if (!(isAlmostZero(double(oldColor.r - color.r), 15.0) &&
Toshihiro Shimizu 890ddd
						  isAlmostZero(double(oldColor.g - color.g), 15.0) &&
Toshihiro Shimizu 890ddd
						  isAlmostZero(double(oldColor.b - color.b), 15.0))) {
Toshihiro Shimizu 890ddd
						styleId = palette->getStyleCount();
Toshihiro Shimizu 890ddd
						palette->getStylePage(1)->insertStyle(1, color);
Toshihiro Shimizu 890ddd
						palette->setStyle(styleId, color);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			++regionCount;
Toshihiro Shimizu 890ddd
			r->setStyle(styleId);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)r->getSubregionCount(); ++i)
Toshihiro Shimizu 890ddd
		applyFillColors(r->getSubregion(i), ras, palette, c, regionCount);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void VectorizerCore::applyFillColors(TRegion *r, const TRasterP &ras, TPalette *palette,
Toshihiro Shimizu 890ddd
									 const OutlineConfiguration &c, int regionCount)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TRasterCM32P rt = ras;
Toshihiro Shimizu 890ddd
	TRaster32P rr = ras;
Toshihiro Shimizu 890ddd
	TRasterGR8P rgr = ras;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(rt || rr || rgr);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TAffine inverse = c.m_affine.inv();
Toshihiro Shimizu 890ddd
	bool doInks = !c.m_ignoreInkColors,
Toshihiro Shimizu 890ddd
		 doPaints = !c.m_leaveUnpainted;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve a point inside the specified region
Toshihiro Shimizu 890ddd
	TPointD pd;
Toshihiro Shimizu 890ddd
	if (r->getInternalPoint(pd)) {
Toshihiro Shimizu 890ddd
		pd = inverse * pd;	// Convert point to raster coordinates
Toshihiro Shimizu 890ddd
		TPoint p(pd.x, pd.y); //
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Retrieve the corresponding pixel in the raster image
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (ras->getBounds().contains(p)) {
Toshihiro Shimizu 890ddd
			int styleId = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (rt) {
Toshihiro Shimizu 890ddd
				// Toonz colormap case
Toshihiro Shimizu 890ddd
				TPixelCM32 col = rt->pixels(p.y)[p.x]; // In the outline vectorization case, color
Toshihiro Shimizu 890ddd
				int tone = col.getTone();			   // can be either ink or paint
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (tone == 0) // Full ink case
Toshihiro Shimizu 890ddd
					styleId = doInks ? col.getInk() : 1;
Toshihiro Shimizu 890ddd
				else if (tone == 255 && doPaints) // Full paint case
Toshihiro Shimizu 890ddd
					styleId = col.getPaint();
Toshihiro Shimizu 890ddd
				else if (tone != 255) {
Toshihiro Shimizu 890ddd
					if (regionCount % 2 == 1) {
Toshihiro Shimizu 890ddd
						// Whenever regionCount is odd, ink is checked first
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						if (isNearestInkOrPaintInRegion(true, rt, r, c.m_affine, p))
Toshihiro Shimizu 890ddd
							styleId = doInks ? col.getInk() : 1;
Toshihiro Shimizu 890ddd
						else if (doPaints && isNearestInkOrPaintInRegion(false, rt, r, c.m_affine, p))
Toshihiro Shimizu 890ddd
							styleId = col.getPaint();
Toshihiro Shimizu 890ddd
					} else {
Toshihiro Shimizu 890ddd
						// Whenever regionCount is even, paint is checked first
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						if (doPaints && isNearestInkOrPaintInRegion(false, rt, r, c.m_affine, p))
Toshihiro Shimizu 890ddd
							styleId = col.getPaint();
Toshihiro Shimizu 890ddd
						else if (isNearestInkOrPaintInRegion(true, rt, r, c.m_affine, p))
Toshihiro Shimizu 890ddd
							styleId = doInks ? col.getInk() : 1;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				TPixel32 color;
Toshihiro Shimizu 890ddd
				if (rr)
Toshihiro Shimizu 890ddd
					color = rr->pixels(p.y)[p.x];
Toshihiro Shimizu 890ddd
				else {
Toshihiro Shimizu 890ddd
					int val = rgr->pixels(p.y)[p.x].value;
Toshihiro Shimizu 890ddd
					color = (val < 80) ? TPixel32::Black : TPixel32::White;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if ((color.m != 0) && ((!c.m_leaveUnpainted) || (c.m_leaveUnpainted && color == c.m_inkColor))) {
Toshihiro Shimizu 890ddd
					styleId = palette->getClosestStyle(color);
Toshihiro Shimizu 890ddd
					TPixel32 oldColor = palette->getStyle(styleId)->getMainColor();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (!(isAlmostZero(double(oldColor.r - color.r), 15.0) &&
Toshihiro Shimizu 890ddd
						  isAlmostZero(double(oldColor.g - color.g), 15.0) &&
Toshihiro Shimizu 890ddd
						  isAlmostZero(double(oldColor.b - color.b), 15.0))) {
Toshihiro Shimizu 890ddd
						styleId = palette->getStyleCount();
Toshihiro Shimizu 890ddd
						palette->getStylePage(1)->insertStyle(1, color);
Toshihiro Shimizu 890ddd
						palette->setStyle(styleId, color);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			++regionCount;
Toshihiro Shimizu 890ddd
			r->setStyle(styleId);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)r->getSubregionCount(); ++i)
Toshihiro Shimizu 890ddd
		applyFillColors(r->getSubregion(i), ras, palette, c, regionCount);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void VectorizerCore::applyFillColors(TVectorImageP vi, const TImageP &img, TPalette *palette,
Toshihiro Shimizu 890ddd
									 const VectorizerConfiguration &c)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const CenterlineConfiguration ¢Conf = static_cast<const &="" centerlineconfiguration="">(c);</const>
Toshihiro Shimizu 890ddd
	const OutlineConfiguration &outConf = static_cast<const &="" outlineconfiguration="">(c);</const>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If configuration is not set for color fill at all, quit.
Toshihiro Shimizu 890ddd
	if (c.m_leaveUnpainted && (!c.m_outline || outConf.m_ignoreInkColors))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TToonzImageP ti = img;
Toshihiro Shimizu 890ddd
	TRasterImageP ri = img;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ti || ri);
Toshihiro Shimizu 890ddd
	TRasterP ras = ti ? TRasterP(ti->getRaster()) : TRasterP(ri->getRaster());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	vi->findRegions();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int r, regionsCount = vi->getRegionCount();
Toshihiro Shimizu 890ddd
	if (c.m_outline) {
Toshihiro Shimizu 890ddd
		for (r = 0; r < regionsCount; ++r)
Toshihiro Shimizu 890ddd
			applyFillColors(vi->getRegion(r), ras, palette, outConf, 1);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		for (r = 0; r < regionsCount; ++r)
Toshihiro Shimizu 890ddd
			applyFillColors(vi->getRegion(r), ras, palette, centConf, 1); //1 - c.m_makeFrame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		clearInkRegionFlags(vi);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TVectorImageP VectorizerCore::vectorize(const TImageP &img, const VectorizerConfiguration &c, TPalette *plt)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TVectorImageP vi;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (c.m_outline)
Toshihiro Shimizu 890ddd
		vi = newOutlineVectorize(img, static_cast<const &="" newoutlineconfiguration="">(c), plt);</const>
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		TImageP img2(img);
Toshihiro Shimizu 890ddd
		vi = centerlineVectorize(img2, static_cast<const &="" centerlineconfiguration="">(c), plt);</const>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (vi) {
Toshihiro Shimizu 890ddd
			for (int i = 0; i < (int)vi->getStrokeCount(); ++i) {
Toshihiro Shimizu 890ddd
				TStroke *stroke = vi->getStroke(i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (int j = 0; j < stroke->getControlPointCount(); ++j) {
Toshihiro Shimizu 890ddd
					TThickPoint p = stroke->getControlPoint(j);
Toshihiro Shimizu 890ddd
					p = TThickPoint(c.m_affine * p, c.m_thickScale * p.thick);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					stroke->setControlPoint(j, p);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			applyFillColors(vi, img2, plt, c);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return vi;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void VectorizerCore::emitPartialDone(void)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	emit partialDone(m_currPartial++, m_totalPartials);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
void VectorizerCore::emitPartialDone(int current)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  m_currPartial= current;
Toshihiro Shimizu 890ddd
  emit partialDone(current, m_totalPartials);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
*/