Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcenterlinevectP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//#define _SSDEBUG                                              // Uncomment to enable the debug viewer
Toshihiro Shimizu 890ddd
//#define _UPDATE                                               // Shows borders updated to current time
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Forward declarations
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct VectorizationContext;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//====================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
//      Rationale
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  NOTE: Input is a vector of Contours, representing the borders of a
Toshihiro Shimizu 890ddd
        polygonal region. First border is the outer one, followed by internal
Toshihiro Shimizu 890ddd
        counter-borders; each Contour is itself a vector of "ContourNode"s,
Toshihiro Shimizu 890ddd
        ordered so that the region to be thinned is at the RIGHT of segments
Toshihiro Shimizu 890ddd
        formed by successive nodes.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
        Output is a Graph structure representing the straight skeleton of the
Toshihiro Shimizu 890ddd
        thinned region. Original contours survive the thinning procedure.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
//      Straight Skeleton Debugger
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _SSDEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qwidget></qwidget>
Toshihiro Shimizu 890ddd
#include <qtransform></qtransform>
Toshihiro Shimizu 890ddd
#include <qeventloop></qeventloop>
Toshihiro Shimizu 890ddd
#include <qpainter></qpainter>
Toshihiro Shimizu 890ddd
#include <qmouseevent></qmouseevent>
Toshihiro Shimizu 890ddd
#include <qwheelevent></qwheelevent>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class SSDebugger : public QWidget
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	VectorizationContext &m_context;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QPoint m_pos,
Toshihiro Shimizu 890ddd
		m_pressPos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double m_scale;
Toshihiro Shimizu 890ddd
	QTransform m_transform;
Toshihiro Shimizu 890ddd
	QEventLoop m_loop;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	double m_height;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SSDebugger(VectorizationContext &context);
Toshihiro Shimizu 890ddd
	~SSDebugger() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void loop() { m_loop.exec(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void paintEvent(QPaintEvent *event);
Toshihiro Shimizu 890ddd
	void keyPressEvent(QKeyEvent *event);
Toshihiro Shimizu 890ddd
	void mouseMoveEvent(QMouseEvent *event);
Toshihiro Shimizu 890ddd
	void mousePressEvent(QMouseEvent *event);
Toshihiro Shimizu 890ddd
	void mouseReleaseEvent(QMouseEvent *event);
Toshihiro Shimizu 890ddd
	void wheelEvent(QWheelEvent *event);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline QPoint winToWorld(int x, int y);
Toshihiro Shimizu 890ddd
	inline QPoint worldToWin(double x, double y);
Toshihiro Shimizu 890ddd
	inline QPointF winToWorldF(int x, int y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline bool isOnScreen(ContourNode *node);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Node Updates
Toshihiro Shimizu 890ddd
	TPointD updated(ContourNode *input);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif // _SSDEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
//      Classes
Toshihiro Shimizu 890ddd
//**************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ContourEdge
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	enum { NOT_OPPOSITE = 0x1 };
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TPointD m_direction;
Toshihiro Shimizu 890ddd
	unsigned short m_attributes;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ContourEdge() : m_attributes(0) {}
Toshihiro Shimizu 890ddd
	ContourEdge(TPointD dir) : m_direction(dir), m_attributes(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int hasAttribute(int attr) const { return m_attributes & attr; }
Toshihiro Shimizu 890ddd
	void setAttribute(int attr) { m_attributes |= attr; }
Toshihiro Shimizu 890ddd
	void clearAttribute(int attr) { m_attributes &= ~attr; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class IndexTable
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef std::list<contournode *=""> IndexColumn;</contournode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<indexcolumn> m_columns; //!< Countours set by 'column identifier'.</indexcolumn>
Toshihiro Shimizu 890ddd
	std::vector<int> m_identifiers;		//!< Column identifiers by original contour index.</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTE: Contours are stored in 'comb' structure (vector of lists) since contours may both
Toshihiro Shimizu 890ddd
	// be SPLIT (new entry in a list) and MERGED (two lists merge).
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	IndexTable() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	IndexColumn *operator[](int i) { return &m_columns[i]; }
Toshihiro Shimizu 890ddd
	IndexColumn &columnOfId(int id) { return m_columns[m_identifiers[id]]; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Initialization
Toshihiro Shimizu 890ddd
	void build(ContourFamily &family);
Toshihiro Shimizu 890ddd
	void clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Specific handlers
Toshihiro Shimizu 890ddd
	IndexColumn::iterator find(ContourNode *index);
Toshihiro Shimizu 890ddd
	void merge(IndexColumn::iterator index1, IndexColumn::iterator index2);
Toshihiro Shimizu 890ddd
	void remove(IndexColumn::iterator index);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Event
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	/*! \remark  Values are sorted by preference at simultaneous events.    */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	enum Type //! An event's possible types.
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		special,		  //!< A vertex event that is also an edge event (V case).
Toshihiro Shimizu 890ddd
		edge,			  //!< An edge shrinks to 0 length.
Toshihiro Shimizu 890ddd
		vertex,			  //!< Two contour nodes clash.
Toshihiro Shimizu 890ddd
		split_regenerate, //!< Placeholder type for split events that must be regenerated.
Toshihiro Shimizu 890ddd
		split,			  //!< An edge is split by a clashing contour node.
Toshihiro Shimizu 890ddd
		failure
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	double m_height;
Toshihiro Shimizu 890ddd
	double m_displacement;
Toshihiro Shimizu 890ddd
	ContourNode *m_generator;
Toshihiro Shimizu 890ddd
	ContourNode *m_coGenerator;
Toshihiro Shimizu 890ddd
	Type m_type;
Toshihiro Shimizu 890ddd
	unsigned int m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	VectorizationContext *m_context;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	// In-builder event constructor
Toshihiro Shimizu 890ddd
	Event(ContourNode *generator, VectorizationContext *context);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Event calculators
Toshihiro Shimizu 890ddd
	inline void calculateEdgeEvent();
Toshihiro Shimizu 890ddd
	inline void calculateSplitEvent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Auxiliary event calculators
Toshihiro Shimizu 890ddd
	inline double splitDisplacementWith(ContourNode *plane);
Toshihiro Shimizu 890ddd
	inline bool tryRayEdgeCollisionWith(ContourNode *edge);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Event handlers
Toshihiro Shimizu 890ddd
	inline bool process();
Toshihiro Shimizu 890ddd
	inline void processEdgeEvent();
Toshihiro Shimizu 890ddd
	inline void processMaxEvent();
Toshihiro Shimizu 890ddd
	inline void processSplitEvent();
Toshihiro Shimizu 890ddd
	inline void processVertexEvent();
Toshihiro Shimizu 890ddd
	inline void processSpecialEvent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	inline bool testRayEdgeCollision(ContourNode *opposite,
Toshihiro Shimizu 890ddd
									 double &displacement, double &height, double &side1, double &side2);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct EventGreater {
Toshihiro Shimizu 890ddd
	bool operator()(const Event &event1, const Event &event2) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return event1.m_height > event2.m_height || (event1.m_height == event2.m_height && event1.m_type > event2.m_type);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class Timeline : public std::priority_queue<event, std::vector<event="">, EventGreater></event,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	Timeline() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTE: Timeline construction contains the most complex part of vectorization;
Toshihiro Shimizu 890ddd
	// progress bar partial notification happens there, so thisVectorizer's signal
Toshihiro Shimizu 890ddd
	// emission methods must be passed and used.
Toshihiro Shimizu 890ddd
	void build(ContourFamily &polygons, VectorizationContext &context, VectorizerCore *thisVectorizer);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------
Toshihiro Shimizu 890ddd
//    Preliminary methods/functions
Toshihiro Shimizu 890ddd
//--------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// IndexTable methods
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void IndexTable::build(ContourFamily &family)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_columns.resize(family.size());
Toshihiro Shimizu 890ddd
	m_identifiers.resize(family.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NOTE: At the beginning, m_identifiers= 1, .. , m_columns.size() - 1;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_columns.size(); ++i) {
Toshihiro Shimizu 890ddd
		m_identifiers[i] = i;
Toshihiro Shimizu 890ddd
		m_columns[i].push_back(&family[i][0]);
Toshihiro Shimizu 890ddd
		//Each node referenced in the Table is signed as 'head' of the cirular list.
Toshihiro Shimizu 890ddd
		family[i][0].setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Explanation: during the skeletonization process, ContourNodes and calculated
Toshihiro Shimizu 890ddd
//Events are unaware of global index-changes generated by other events, so
Toshihiro Shimizu 890ddd
//the position of index stored in one Event has to be retrieved in the
Toshihiro Shimizu 890ddd
//IndexTable before event processing begins.
Toshihiro Shimizu 890ddd
//NOTE: Can this be done in a more efficient way?...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline IndexTable::IndexColumn::iterator
Toshihiro Shimizu 890ddd
IndexTable::find(ContourNode *sought)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int indexId = m_identifiers[sought->m_ancestorContour];
Toshihiro Shimizu 890ddd
	IndexColumn::iterator res;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Search for the HEAD attribute in index's Contour
Toshihiro Shimizu 890ddd
	for (; !sought->hasAttribute(ContourNode::HEAD); sought = sought->m_next)
Toshihiro Shimizu 890ddd
		;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, find index through our column
Toshihiro Shimizu 890ddd
	for (res = m_columns[indexId].begin(); (*res) != sought; ++res)
Toshihiro Shimizu 890ddd
		;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Handles active contour merging due to split/vertex events
Toshihiro Shimizu 890ddd
void IndexTable::merge(IndexColumn::iterator index1, IndexColumn::iterator index2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	IndexColumn::iterator current;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int identifier1 = m_identifiers[(*index1)->m_ancestorContour],
Toshihiro Shimizu 890ddd
		identifier2 = m_identifiers[(*index2)->m_ancestorContour];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	remove(index2); // We maintain only one index of the merged contour
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, append columns
Toshihiro Shimizu 890ddd
	if (!m_columns[identifier2].empty()) {
Toshihiro Shimizu 890ddd
		append<indextable::indexcolumn, indextable::indexcolumn::reverse_iterator="">(</indextable::indexcolumn,>
Toshihiro Shimizu 890ddd
			m_columns[identifier1], m_columns[identifier2]);
Toshihiro Shimizu 890ddd
		m_columns[identifier2].clear();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Then, update stored identifiers
Toshihiro Shimizu 890ddd
	for (unsigned int k = 0; k < m_columns.size(); ++k) {
Toshihiro Shimizu 890ddd
		if (m_identifiers[k] == identifier2)
Toshihiro Shimizu 890ddd
			m_identifiers[k] = identifier1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Removes given index in Table
Toshihiro Shimizu 890ddd
inline void IndexTable::remove(IndexColumn::iterator index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_columns[m_identifiers[(*index)->m_ancestorContour]].erase(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void IndexTable::clear()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_columns.clear(), m_identifiers.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
//                    Straight Skeleton Algorithm
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
//      Global Variables
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct VectorizationContext {
Toshihiro Shimizu 890ddd
	VectorizerCoreGlobals *m_globals;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Globals
Toshihiro Shimizu 890ddd
	unsigned int m_totalNodes;	 //Number of original contour nodes
Toshihiro Shimizu 890ddd
	unsigned int m_contoursCount;  //Number of contours in input region
Toshihiro Shimizu 890ddd
	IndexTable m_activeTable;	  //Index table of active contours
Toshihiro Shimizu 890ddd
	SkeletonGraph *m_output;	   //Output skeleton of input region
Toshihiro Shimizu 890ddd
	double m_currentHeight;		   //Height of our 'roof-flooding' process
Toshihiro Shimizu 890ddd
	Timeline m_timeline;		   //Ordered queue of all possible events
Toshihiro Shimizu 890ddd
	unsigned int m_algoritmicTime; //Number of events precessed up to now
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Containers
Toshihiro Shimizu 890ddd
	std::vector<contouredge> m_edgesHeap;</contouredge>
Toshihiro Shimizu 890ddd
	std::vector<contournode> m_nodesHeap; //of *non-original* nodes only</contournode>
Toshihiro Shimizu 890ddd
	unsigned int m_nodesHeapCount;		  //number of nodes used in nodesHeap
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//'Linear Axis-added' *pseudo-original* nodes and edges
Toshihiro Shimizu 890ddd
	std::vector<contournode> m_linearNodesHeap;</contournode>
Toshihiro Shimizu 890ddd
	std::vector<contouredge> m_linearEdgesHeap;</contouredge>
Toshihiro Shimizu 890ddd
	unsigned int m_linearNodesHeapCount;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	VectorizationContext(VectorizerCoreGlobals *globals)
Toshihiro Shimizu 890ddd
		: m_globals(globals) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ContourNode *getNode() { return &m_nodesHeap[m_nodesHeapCount++]; }
Toshihiro Shimizu 890ddd
	ContourNode *getLinearNode() { return &m_linearNodesHeap[m_linearNodesHeapCount]; }
Toshihiro Shimizu 890ddd
	ContourEdge *getLinearEdge() { return &m_linearEdgesHeap[m_linearNodesHeapCount++]; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void addLinearNodeBefore(ContourNode *node);
Toshihiro Shimizu 890ddd
	inline void repairDegenerations(const std::vector<contournode *=""> °enerates);</contournode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void prepareGlobals();
Toshihiro Shimizu 890ddd
	inline void prepareContours(ContourFamily &family);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline void newSkeletonLink(unsigned int cur, ContourNode *node);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//WARNING: To be launched only *after* prepareContours - node countings happen there
Toshihiro Shimizu 890ddd
inline void VectorizationContext::prepareGlobals()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//NOTE: Let n be the total number of nodes in the family, k the number of split events
Toshihiro Shimizu 890ddd
	//      effectively happening in the process, m the number of original contours of the family.
Toshihiro Shimizu 890ddd
	//      Now:
Toshihiro Shimizu 890ddd
	//        * Each split event eliminates its generating reflex node and introduces
Toshihiro Shimizu 890ddd
	//          two convex nodes
Toshihiro Shimizu 890ddd
	//        * Each edge event eliminates its couple of generating nodes and
Toshihiro Shimizu 890ddd
	//          introduces one new convex node
Toshihiro Shimizu 890ddd
	//        * Each max event eliminates 3 generating nodes without introducing new ones
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//So, split events introduce 2k non-original nodes, and (k-m+2) is the number of max events
Toshihiro Shimizu 890ddd
	//necessarily happening, since (m-1) are the *merging* split events.
Toshihiro Shimizu 890ddd
	//On the n+k-3(k-m+2) nodes remaining for pure edge events, as many non-original nodes are inserted.
Toshihiro Shimizu 890ddd
	//=> This yields 2k + n-2k+3m-6= n+3m-6 non-original nodes. Contemporaneous events such as
Toshihiro Shimizu 890ddd
	//vertex and special events can only decrease the number of non-original nodes requested.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Initialize non-original nodes container
Toshihiro Shimizu 890ddd
	m_nodesHeap.resize(m_totalNodes + 3 * m_contoursCount - 6);
Toshihiro Shimizu 890ddd
	m_nodesHeapCount = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Reset time/height variables
Toshihiro Shimizu 890ddd
	m_currentHeight = 0;
Toshihiro Shimizu 890ddd
	m_algoritmicTime = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Clean IndexTable
Toshihiro Shimizu 890ddd
	m_activeTable.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void VectorizationContext::newSkeletonLink(unsigned int cur, ContourNode *node)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (node->hasAttribute(ContourNode::SK_NODE_DROPPED)) {
Toshihiro Shimizu 890ddd
		SkeletonArc arcCopy(node);
Toshihiro Shimizu 890ddd
		m_output->newLink(node->m_outputNode, cur, arcCopy);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		arcCopy.turn();
Toshihiro Shimizu 890ddd
		m_output->newLink(cur, node->m_outputNode, arcCopy);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================
Toshihiro Shimizu 890ddd
//    Thinning Functions/Methods
Toshihiro Shimizu 890ddd
//===================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------
Toshihiro Shimizu 890ddd
//      Repair Polygon Degenerations
Toshihiro Shimizu 890ddd
//----------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: After "Polygonizer", there may be simpleness degenerations
Toshihiro Shimizu 890ddd
//about polygons which are dangerous to deal in the thinning process.
Toshihiro Shimizu 890ddd
//Typically, these correspond to cases in which node->m_direction.z ~ 0
Toshihiro Shimizu 890ddd
//(too fast), and are concave.
Toshihiro Shimizu 890ddd
//We then deal with them *before* the process begins, by splitting one
Toshihiro Shimizu 890ddd
//such node in two slower ones (known as 'Linear Axis' method).
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void VectorizationContext::addLinearNodeBefore(ContourNode *node)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newNode = getLinearNode();
Toshihiro Shimizu 890ddd
	ContourEdge *newEdge = getLinearEdge();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_position = node->m_position;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build new edge
Toshihiro Shimizu 890ddd
	if (node->m_direction.z < 0.1)
Toshihiro Shimizu 890ddd
		newEdge->m_direction = rotate270(node->m_edge->m_direction);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		newEdge->m_direction = normalize(
Toshihiro Shimizu 890ddd
			node->m_edge->m_direction + node->m_prev->m_edge->m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_edge = newEdge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Link newNode
Toshihiro Shimizu 890ddd
	newNode->m_prev = node->m_prev;
Toshihiro Shimizu 890ddd
	newNode->m_next = node;
Toshihiro Shimizu 890ddd
	node->m_prev->m_next = newNode;
Toshihiro Shimizu 890ddd
	node->m_prev = newNode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build remaining infos
Toshihiro Shimizu 890ddd
	node->buildNodeInfos(); //Rebuild
Toshihiro Shimizu 890ddd
	newNode->buildNodeInfos();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_updateTime = 0;
Toshihiro Shimizu 890ddd
	newNode->m_ancestor = node->m_ancestor;
Toshihiro Shimizu 890ddd
	newNode->m_ancestorContour = node->m_ancestorContour;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Set node and newNode's edges not to be recognized as possible
Toshihiro Shimizu 890ddd
	//opposites by the other (could happen in *future* instants)
Toshihiro Shimizu 890ddd
	//                *DO NOT REMOVE!*
Toshihiro Shimizu 890ddd
	node->m_notOpposites.push_back(newNode->m_edge);
Toshihiro Shimizu 890ddd
	node->m_notOpposites.push_back(newNode->m_prev->m_edge);
Toshihiro Shimizu 890ddd
	newNode->m_notOpposites.push_back(node->m_edge);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Further sign newly added node
Toshihiro Shimizu 890ddd
	newNode->setAttribute(ContourNode::LINEAR_ADDED);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void VectorizationContext::repairDegenerations(const std::vector<contournode *=""> °enerates)</contournode>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_linearNodesHeap.resize(degenerates.size());
Toshihiro Shimizu 890ddd
	m_linearEdgesHeap.resize(degenerates.size());
Toshihiro Shimizu 890ddd
	m_linearNodesHeapCount = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < degenerates.size(); ++i) {
Toshihiro Shimizu 890ddd
		if (!degenerates[i]->hasAttribute(ContourNode::AMBIGUOUS_LEFT)) {
Toshihiro Shimizu 890ddd
			addLinearNodeBefore(degenerates[i]);
Toshihiro Shimizu 890ddd
			m_totalNodes++;
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 Infos Construction
Toshihiro Shimizu 890ddd
//--------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void VectorizationContext::prepareContours(ContourFamily &family)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<contournode *=""> degenerateNodes;</contournode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build circular links
Toshihiro Shimizu 890ddd
	unsigned int i, j, k;
Toshihiro Shimizu 890ddd
	unsigned int current;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_contoursCount = family.size();
Toshihiro Shimizu 890ddd
	m_totalNodes = 0;
Toshihiro Shimizu 890ddd
	for (i = 0; i < family.size(); ++i) {
Toshihiro Shimizu 890ddd
		for (j = 0, k = family[i].size() - 1; j < family[i].size(); k = j, ++j) {
Toshihiro Shimizu 890ddd
			family[i][k].m_next = &family[i][j];
Toshihiro Shimizu 890ddd
			family[i][j].m_prev = &family[i][k];
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		m_totalNodes += family[i].size();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build node edges
Toshihiro Shimizu 890ddd
	m_edgesHeap.resize(m_totalNodes);
Toshihiro Shimizu 890ddd
	current = 0;
Toshihiro Shimizu 890ddd
	for (i = 0; i < family.size(); ++i) {
Toshihiro Shimizu 890ddd
		for (j = 0, k = family[i].size() - 1; j < family[i].size(); k = j, ++j) {
Toshihiro Shimizu 890ddd
			m_edgesHeap[current].m_direction =
Toshihiro Shimizu 890ddd
				normalize(planeProjection(family[i][j].m_position - family[i][k].m_position));
Toshihiro Shimizu 890ddd
			family[i][k].m_edge = &m_edgesHeap[current];
Toshihiro Shimizu 890ddd
			current++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool maxThicknessNotZero = m_globals->currConfig->m_maxThickness > 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now build remaining infos
Toshihiro Shimizu 890ddd
	for (i = 0; i < family.size(); ++i) {
Toshihiro Shimizu 890ddd
		for (j = 0; j < family[i].size(); ++j) {
Toshihiro Shimizu 890ddd
			family[i][j].buildNodeInfos();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			family[i][j].m_updateTime = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			family[i][j].m_ancestor = j;
Toshihiro Shimizu 890ddd
			family[i][j].m_ancestorContour = i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Check the following degeneration
Toshihiro Shimizu 890ddd
			if (family[i][j].m_concave && family[i][j].m_direction.z < 0.3) {
Toshihiro Shimizu 890ddd
				//Push this node among degenerate ones
Toshihiro Shimizu 890ddd
				degenerateNodes.push_back(&family[i][j]);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Insert output node in sharp angles
Toshihiro Shimizu 890ddd
			if (!family[i][j].m_concave && family[i][j].m_direction.z < 0.6 && maxThicknessNotZero) {
Toshihiro Shimizu 890ddd
				family[i][j].setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
				family[i][j].m_outputNode = m_output->newNode(family[i][j].m_position);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Push on nodes having AMBIGUOUS_RIGHT attribute
Toshihiro Shimizu 890ddd
			if (family[i][j].hasAttribute(ContourNode::AMBIGUOUS_RIGHT))
Toshihiro Shimizu 890ddd
				family[i][j].m_position += 0.02 * family[i][j].m_direction;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, ensure polygon degenerations found are solved
Toshihiro Shimizu 890ddd
	if (maxThicknessNotZero)
Toshihiro Shimizu 890ddd
		repairDegenerations(degenerateNodes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//WARNING: m_edge field of *this* and *previous* node must already be defined.
Toshihiro Shimizu 890ddd
inline void ContourNode::buildNodeInfos(bool forceConvex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPointD direction;
Toshihiro Shimizu 890ddd
	double parameter;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate node convexity
Toshihiro Shimizu 890ddd
	if (forceConvex)
Toshihiro Shimizu 890ddd
		m_concave = 0;
Toshihiro Shimizu 890ddd
	else if (cross(m_edge->m_direction, m_prev->m_edge->m_direction) < 0) {
Toshihiro Shimizu 890ddd
		m_concave = 1;
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		m_concave = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build node direction
Toshihiro Shimizu 890ddd
	direction = m_edge->m_direction - m_prev->m_edge->m_direction;
Toshihiro Shimizu 890ddd
	parameter = norm(direction);
Toshihiro Shimizu 890ddd
	if (parameter > 0.01) {
Toshihiro Shimizu 890ddd
		direction = direction * (1 / parameter);
Toshihiro Shimizu 890ddd
		if (m_concave)
Toshihiro Shimizu 890ddd
			direction = -direction;
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		direction = rotate270(m_edge->m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_direction.x = direction.x;
Toshihiro Shimizu 890ddd
	m_direction.y = direction.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate node speed
Toshihiro Shimizu 890ddd
	m_direction.z = cross(planeProjection(m_direction), m_edge->m_direction);
Toshihiro Shimizu 890ddd
	if (m_direction.z < 0)
Toshihiro Shimizu 890ddd
		m_direction.z = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate angular momentum
Toshihiro Shimizu 890ddd
	m_AngularMomentum = cross(m_position, m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_concave) {
Toshihiro Shimizu 890ddd
		m_AuxiliaryMomentum1 = m_AuxiliaryMomentum2 = m_AngularMomentum;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_AuxiliaryMomentum1 =
Toshihiro Shimizu 890ddd
			cross(m_position, T3DPointD(m_edge->m_direction.y, -m_edge->m_direction.x, 1));
Toshihiro Shimizu 890ddd
		m_AuxiliaryMomentum2 =
Toshihiro Shimizu 890ddd
			cross(m_position, T3DPointD(m_prev->m_edge->m_direction.y, -m_prev->m_edge->m_direction.x, 1));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------
Toshihiro Shimizu 890ddd
//      Timeline Construction
Toshihiro Shimizu 890ddd
//---------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//NOTE: In the following, we achieve these results:
Toshihiro Shimizu 890ddd
//        * Build the timeline - events priority queue
Toshihiro Shimizu 890ddd
//        * Process those split events which *necessarily* happen
Toshihiro Shimizu 890ddd
//Pre-processing of split events is useful in order to lower execution times.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Each node is first associated to a random integer; then a referencing
Toshihiro Shimizu 890ddd
//vector is ordered according to those integers - events are calculated
Toshihiro Shimizu 890ddd
//following this order. Split events are therefore calculated sparsely
Toshihiro Shimizu 890ddd
//along the polygons, allowing a significant time reduction effect.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RandomizedNode
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ContourNode *m_node;
Toshihiro Shimizu 890ddd
	int m_number;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	RandomizedNode() {}
Toshihiro Shimizu 890ddd
	RandomizedNode(ContourNode *node) : m_node(node), m_number(rand()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline ContourNode *operator->(void)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_node;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RandomizedNodeLess
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RandomizedNodeLess() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline bool operator()(RandomizedNode a, RandomizedNode b)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (a.m_number < b.m_number);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void Timeline::build(ContourFamily &polygons, VectorizationContext &context,
Toshihiro Shimizu 890ddd
					 VectorizerCore *thisVectorizer)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i, j, current;
Toshihiro Shimizu 890ddd
	std::vector<randomizednode> nodesToBeTreated(context.m_totalNodes);</randomizednode>
Toshihiro Shimizu 890ddd
	T3DPointD momentum, ray;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build casual ordered node-array
Toshihiro Shimizu 890ddd
	for (i = 0, current = 0; i < polygons.size(); ++i)
Toshihiro Shimizu 890ddd
		for (j = 0; j < polygons[i].size(); ++j)
Toshihiro Shimizu 890ddd
			nodesToBeTreated[current++] = RandomizedNode(&polygons[i][j]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Same for linear-added nodes
Toshihiro Shimizu 890ddd
	for (i = 0; i < context.m_linearNodesHeapCount; ++i)
Toshihiro Shimizu 890ddd
		nodesToBeTreated[current++] = RandomizedNode(&context.m_linearNodesHeap[i]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double maxThickness = context.m_globals->currConfig->m_maxThickness;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Compute events generated by nodes
Toshihiro Shimizu 890ddd
	//NOTE: are edge events to be computed BEFORE split ones?
Toshihiro Shimizu 890ddd
	for (i = 0; i < nodesToBeTreated.size(); ++i) {
Toshihiro Shimizu 890ddd
		//Break calculation at user cancel press
Toshihiro Shimizu 890ddd
		if (thisVectorizer->isCanceled())
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		Event currentEvent(nodesToBeTreated[i].m_node, &context);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Notify event calculation
Toshihiro Shimizu 890ddd
		if (!nodesToBeTreated[i].m_node->hasAttribute(ContourNode::LINEAR_ADDED))
Toshihiro Shimizu 890ddd
			thisVectorizer->emitPartialDone();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (currentEvent.m_type != Event::failure && currentEvent.m_height < maxThickness)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _PREPROCESS
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (currentEvent.m_type == Event::split) {
Toshihiro Shimizu 890ddd
				if (currentEvent.m_coGenerator->m_concave) {
Toshihiro Shimizu 890ddd
					ray = T3DPointD(currentEvent.m_coGenerator->m_edge->m_direction.y,
Toshihiro Shimizu 890ddd
									-currentEvent.m_coGenerator->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
					momentum =
Toshihiro Shimizu 890ddd
						cross(currentEvent.m_coGenerator->m_position, ray);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (currentEvent.m_generator->m_direction * momentum +
Toshihiro Shimizu 890ddd
							ray * currentEvent.m_generator->m_AngularMomentum <
Toshihiro Shimizu 890ddd
						0) {
Toshihiro Shimizu 890ddd
						timeline.push(currentEvent);
Toshihiro Shimizu 890ddd
						continue;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (currentEvent.m_coGenerator->m_next->m_concave) {
Toshihiro Shimizu 890ddd
					ray = T3DPointD(currentEvent.m_coGenerator->m_edge->m_direction.y,
Toshihiro Shimizu 890ddd
									-currentEvent.m_coGenerator->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
					momentum =
Toshihiro Shimizu 890ddd
						cross(currentEvent.m_coGenerator->m_next->m_position, ray);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (currentEvent.m_generator->m_direction * momentum +
Toshihiro Shimizu 890ddd
							ray * currentEvent.m_generator->m_AngularMomentum >
Toshihiro Shimizu 890ddd
						0) {
Toshihiro Shimizu 890ddd
						timeline.push(currentEvent);
Toshihiro Shimizu 890ddd
						continue;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (cross(currentEvent.m_generator->m_edge->m_direction,
Toshihiro Shimizu 890ddd
						  currentEvent.m_coGenerator->m_edge->m_direction) > 0.02 &&
Toshihiro Shimizu 890ddd
					cross(currentEvent.m_coGenerator->m_edge->m_direction,
Toshihiro Shimizu 890ddd
						  currentEvent.m_generator->m_prev->m_edge->m_direction) > 0.02) // 0.02 in comparison with 'parameter' in buildNodeInfos
Toshihiro Shimizu 890ddd
				{
Toshihiro Shimizu 890ddd
					//Pre-processing succeeded
Toshihiro Shimizu 890ddd
					currentEvent.process();
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		push(currentEvent);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
//      Event Calculation
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Calculates event generated by input node
Toshihiro Shimizu 890ddd
Event::Event(ContourNode *generator, VectorizationContext *context)
Toshihiro Shimizu 890ddd
	: m_height(infinity), m_displacement(infinity), m_generator(generator), m_type(failure), m_algoritmicTime(context->m_algoritmicTime), m_context(context)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (generator->m_concave)
Toshihiro Shimizu 890ddd
		calculateSplitEvent();
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		calculateEdgeEvent();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// The edge event *generated by a node* is defined as the earliest edge event
Toshihiro Shimizu 890ddd
// generated by its adjacent edges. Remember that 'edge events' correspond to
Toshihiro Shimizu 890ddd
// those in which one edge gets 0 length.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::calculateEdgeEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static inline void buildDisplacements(ContourNode *edgeFirst, double &d1, double &d2)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			ContourNode *edgeSecond = edgeFirst->m_next;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// If bisectors are almost opposite, avoid: there must be another bisector
Toshihiro Shimizu 890ddd
			// colliding with m_generator *before* coGenerator - allowing a positive
Toshihiro Shimizu 890ddd
			// result here may interfere with it.
Toshihiro Shimizu 890ddd
			if ((edgeFirst->m_concave && edgeSecond->m_concave) || edgeFirst->m_direction * edgeSecond->m_direction < -0.9) {
Toshihiro Shimizu 890ddd
				d1 = d2 = -1.0;
Toshihiro Shimizu 890ddd
				return;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double det = edgeFirst->m_direction.y * edgeSecond->m_direction.x - edgeFirst->m_direction.x * edgeSecond->m_direction.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double cx = edgeSecond->m_position.x - edgeFirst->m_position.x,
Toshihiro Shimizu 890ddd
				   cy = edgeSecond->m_position.y - edgeFirst->m_position.y;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			d1 = (edgeSecond->m_direction.x * cy - edgeSecond->m_direction.y * cx) / det;
Toshihiro Shimizu 890ddd
			d2 = (edgeFirst->m_direction.x * cy - edgeFirst->m_direction.y * cx) / det;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static inline double height(ContourNode *node, double displacement)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return node->m_position.z + displacement * node->m_direction.z;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double minHeight, minDisplacement;
Toshihiro Shimizu 890ddd
	bool positiveEdgeDispl;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_type = edge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Calculate the two possible displacement parameters
Toshihiro Shimizu 890ddd
	double firstDisplacement, prevDisplacement, nextDisplacement, lastDisplacement;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// right == prev
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	locals::buildDisplacements(m_generator, nextDisplacement, lastDisplacement);
Toshihiro Shimizu 890ddd
	locals::buildDisplacements(m_generator->m_prev, firstDisplacement, prevDisplacement);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Take the smallest positive between them and assign the co-generator
Toshihiro Shimizu 890ddd
	// NOTE: In a missed vertex event, the threshold value is to compare with the possible pushes at the end of processSplit
Toshihiro Shimizu 890ddd
	// However, admitting slightly negative displacements should be ok: due to the weak linear axis imposed for concave
Toshihiro Shimizu 890ddd
	// vertices, it is impossible to have little negative displacements apart from the above mentioned pushed case.
Toshihiro Shimizu 890ddd
	//   ..currently almost true..
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static const double minusTol = -0.03;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool prevDispPositive = (prevDisplacement > minusTol);
Toshihiro Shimizu 890ddd
	bool nextDispPositive = (nextDisplacement > minusTol);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (nextDispPositive) {
Toshihiro Shimizu 890ddd
		if (!prevDispPositive || nextDisplacement < prevDisplacement) {
Toshihiro Shimizu 890ddd
			m_coGenerator = m_generator;
Toshihiro Shimizu 890ddd
			minDisplacement = nextDisplacement;
Toshihiro Shimizu 890ddd
			minHeight = locals::height(m_coGenerator, nextDisplacement);
Toshihiro Shimizu 890ddd
			positiveEdgeDispl = (nextDispPositive && lastDisplacement > minusTol);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_coGenerator = m_generator->m_prev;
Toshihiro Shimizu 890ddd
			minDisplacement = prevDisplacement;
Toshihiro Shimizu 890ddd
			minHeight = locals::height(m_coGenerator, firstDisplacement);			// Height is built on the edge's first
Toshihiro Shimizu 890ddd
			positiveEdgeDispl = (prevDispPositive && firstDisplacement > minusTol); // endpoint to have the same values on adjacent
Toshihiro Shimizu 890ddd
		}																			// generators. It's important for SPECIAL events.
Toshihiro Shimizu 890ddd
	} else if (prevDispPositive) {
Toshihiro Shimizu 890ddd
		m_coGenerator = m_generator->m_prev;
Toshihiro Shimizu 890ddd
		minDisplacement = prevDisplacement;
Toshihiro Shimizu 890ddd
		minHeight = locals::height(m_coGenerator, firstDisplacement); // Same here
Toshihiro Shimizu 890ddd
		positiveEdgeDispl = (prevDispPositive && firstDisplacement > minusTol);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_type = failure;
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTA: Le const di tolleranza sono da confrontare tra:
Toshihiro Shimizu 890ddd
	// a) i push alla fine di processSplit per evitare rogne coi vertex multipli
Toshihiro Shimizu 890ddd
	// b) Le condizioni di esclusione su side1 e side2 in trySplit che evitano a)
Toshihiro Shimizu 890ddd
	// c) Le condizioni di riconoscimento di vertex e special events - perche' se mancano...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Special cases: (forse da raffinare le condizioni - comunque ora sono efficaci)
Toshihiro Shimizu 890ddd
	if (nextDispPositive && !m_generator->m_concave) {
Toshihiro Shimizu 890ddd
		if (m_generator->m_prev->m_concave && m_generator->m_next->m_concave &&
Toshihiro Shimizu 890ddd
			fabs(nextDisplacement - prevDisplacement) < 0.1) //condizione debole per escludere subito i casi evidentemente innocenti
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// Check 'V' (special) event - can generate a new concave vertex
Toshihiro Shimizu 890ddd
			ContourNode *prevRay = m_generator->m_prev,
Toshihiro Shimizu 890ddd
						*nextRay = m_generator->m_next;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double side = prevRay->m_direction * nextRay->m_AngularMomentum +
Toshihiro Shimizu 890ddd
						  nextRay->m_direction * prevRay->m_AngularMomentum;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// NOTE: fabs(side) / || prevRay->dir x nextRay->dir ||  is the distance between the two rays.
Toshihiro Shimizu 890ddd
			if (fabs(side) < 0.03 * norm(cross(prevRay->m_direction, nextRay->m_direction)))
Toshihiro Shimizu 890ddd
				m_type = special, m_coGenerator = m_generator;
Toshihiro Shimizu 890ddd
		} else if (fabs(nextDisplacement - prevDisplacement) < 0.01) {
Toshihiro Shimizu 890ddd
			// Then choose to make the event with a concave vertex (to resemble the 'LL' case)
Toshihiro Shimizu 890ddd
			m_coGenerator = m_generator->m_next->m_concave ? m_generator : m_generator->m_prev;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, if calculated height is coherent, this Event is valid.
Toshihiro Shimizu 890ddd
	if (positiveEdgeDispl										// Edges shrinking to a point after a FORWARD
Toshihiro Shimizu 890ddd
		|| minHeight > m_context->m_currentHeight - 0.01)		// displacement are processable - this dominates
Toshihiro Shimizu 890ddd
		m_height = minHeight, m_displacement = minDisplacement; // height considerations which may be affected by
Toshihiro Shimizu 890ddd
	else														// numerical errors
Toshihiro Shimizu 890ddd
		m_type = failure;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::calculateSplitEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	bool forceFirst;
Toshihiro Shimizu 890ddd
	ContourNode *opposite, *first, *last;
Toshihiro Shimizu 890ddd
	std::list<contournode *="">::iterator currentContour;</contournode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Sign *edges* not to be taken as possible opposites
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_generator->m_notOpposites.size(); ++i)
Toshihiro Shimizu 890ddd
		m_generator->m_notOpposites[i]->setAttribute(ContourEdge::NOT_OPPOSITE);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Check adjacent edge events
Toshihiro Shimizu 890ddd
	calculateEdgeEvent(); // DO NOT REMOVE - adjacent convexes may have
Toshihiro Shimizu 890ddd
						  // been calculated too earlier
Toshihiro Shimizu 890ddd
	// First check opposites in the m_generator active contour
Toshihiro Shimizu 890ddd
	first = m_generator->m_next->m_next; // Adjacent edges were already considered
Toshihiro Shimizu 890ddd
	last = m_generator->m_prev->m_prev;  // by calculateEdgeEvents()
Toshihiro Shimizu 890ddd
	for (opposite = first; opposite != last; opposite = opposite->m_next) {
Toshihiro Shimizu 890ddd
		if (!opposite->m_edge->hasAttribute(ContourEdge::NOT_OPPOSITE))
Toshihiro Shimizu 890ddd
			tryRayEdgeCollisionWith(opposite);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	IndexTable &activeTable = m_context->m_activeTable;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, try in the remaining active contours whose identifier is != our
Toshihiro Shimizu 890ddd
	for (i = 0; i < activeTable.m_columns.size(); ++i) {
Toshihiro Shimizu 890ddd
		for (currentContour = activeTable[i]->begin();
Toshihiro Shimizu 890ddd
			 currentContour != activeTable[i]->end(); currentContour++) {
Toshihiro Shimizu 890ddd
			//Da spostare sopra il 2o for
Toshihiro Shimizu 890ddd
			if (activeTable.m_identifiers[(*currentContour)->m_ancestorContour] !=
Toshihiro Shimizu 890ddd
				activeTable.m_identifiers[m_generator->m_ancestorContour]) {
Toshihiro Shimizu 890ddd
				first = *currentContour;
Toshihiro Shimizu 890ddd
				for (opposite = first, forceFirst = 1;
Toshihiro Shimizu 890ddd
					 //Better the first next cond. - in case of thinning errors, at least it does not get loop'd.
Toshihiro Shimizu 890ddd
					 !opposite->hasAttribute(ContourNode::HEAD) //opposite!=first
Toshihiro Shimizu 890ddd
					 || (forceFirst ? forceFirst = 0, 1 : 0);
Toshihiro Shimizu 890ddd
					 opposite = opposite->m_next) {
Toshihiro Shimizu 890ddd
					if (!opposite->m_edge->hasAttribute(ContourEdge::NOT_OPPOSITE))
Toshihiro Shimizu 890ddd
						tryRayEdgeCollisionWith(opposite);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Restore edge attributes
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_generator->m_notOpposites.size(); ++i)
Toshihiro Shimizu 890ddd
		m_generator->m_notOpposites[i]->clearAttribute(ContourEdge::NOT_OPPOSITE);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool Event::testRayEdgeCollision(
Toshihiro Shimizu 890ddd
	ContourNode *opposite,
Toshihiro Shimizu 890ddd
	double &displacement, double &height, double &side1, double &side2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Initialize test vectors
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTE: In the convex case, slab guards MUST be orthogonal to the edge, due to this case:
Toshihiro Shimizu 890ddd
	//
Toshihiro Shimizu 890ddd
	//    ______/|                the ray would not hit the edge - AND THUS FOREGO INTERACTION
Toshihiro Shimizu 890ddd
	//           |                WITH IT COMPLETELY
Toshihiro Shimizu 890ddd
	//     ->    |
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	T3DPointD firstSlabGuard = opposite->m_concave ? opposite->m_direction
Toshihiro Shimizu 890ddd
												   : T3DPointD(opposite->m_edge->m_direction.y, -opposite->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
	T3DPointD lastSlabGuard = opposite->m_next->m_concave ? opposite->m_next->m_direction
Toshihiro Shimizu 890ddd
														  : T3DPointD(opposite->m_edge->m_direction.y, -opposite->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	T3DPointD roofSlabOrthogonal(-opposite->m_edge->m_direction.y, opposite->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (roofSlabOrthogonal * (opposite->m_position - m_generator->m_position) > -0.01 // Ray's vertex generator is below the roof slab
Toshihiro Shimizu 890ddd
		//&& roofSlabOrthogonal * m_generator->m_direction > 0                                    // Ray must go 'against' the roof slab
Toshihiro Shimizu 890ddd
		&& planeProjection(roofSlabOrthogonal) * planeProjection(m_generator->m_direction) > 0 // Ray must go against the opposing edge
Toshihiro Shimizu 890ddd
		&& (side1 = m_generator->m_direction * opposite->m_AuxiliaryMomentum1 +				   // Ray must pass inside the first slab guard
Toshihiro Shimizu 890ddd
					firstSlabGuard * m_generator->m_AngularMomentum) > -0.01				   //
Toshihiro Shimizu 890ddd
		&& (side2 = m_generator->m_direction * opposite->m_next->m_AuxiliaryMomentum2 +		   // Ray must pass inside the second slab guard
Toshihiro Shimizu 890ddd
					lastSlabGuard * m_generator->m_AngularMomentum) < 0.01					   //
Toshihiro Shimizu 890ddd
		&& (m_generator->m_ancestorContour != opposite->m_ancestorContour					   // Helps with immediate splits from coincident
Toshihiro Shimizu 890ddd
			|| m_generator->m_ancestor != opposite->m_ancestor))							   // linear vertexes
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		displacement = splitDisplacementWith(opposite);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Possible Security checks for almost complanarity cases
Toshihiro Shimizu 890ddd
		//----------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (displacement > -0.01 && displacement < 0.01) {
Toshihiro Shimizu 890ddd
			T3DPointD slabLeftOrthogonal(-opposite->m_edge->m_direction.y, opposite->m_edge->m_direction.x, 1);
Toshihiro Shimizu 890ddd
			double check1 = (m_generator->m_position - opposite->m_position) *
Toshihiro Shimizu 890ddd
							normalize(cross(opposite->m_direction, slabLeftOrthogonal));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double check2 = (m_generator->m_position - opposite->m_next->m_position) *
Toshihiro Shimizu 890ddd
							normalize(cross(opposite->m_next->m_direction, slabLeftOrthogonal));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (check1 > 0.02 || check2 < -0.02)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//----------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Check height/displacement conditions
Toshihiro Shimizu 890ddd
		if (displacement > -0.01 && displacement < m_displacement + 0.01 // admitting concurrent events
Toshihiro Shimizu 890ddd
			&& (height = m_generator->m_position.z + displacement * m_generator->m_direction.z) > m_context->m_currentHeight - 0.01)
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
inline bool Event::tryRayEdgeCollisionWith(ContourNode *opposite)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newCoGenerator;
Toshihiro Shimizu 890ddd
	Type type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double displacement, height, side1, side2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (testRayEdgeCollision(opposite, displacement, height, side1, side2)) {
Toshihiro Shimizu 890ddd
		type = split_regenerate;
Toshihiro Shimizu 890ddd
		newCoGenerator = opposite;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Check against the REAL slab guards for type deduction
Toshihiro Shimizu 890ddd
		double firstSide = opposite->m_concave ? side1 : m_generator->m_direction * opposite->m_AngularMomentum + opposite->m_direction * m_generator->m_AngularMomentum,
Toshihiro Shimizu 890ddd
			   secondSide = opposite->m_next->m_concave ? side2 : m_generator->m_direction * opposite->m_next->m_AngularMomentum + opposite->m_next->m_direction * m_generator->m_AngularMomentum;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (firstSide > -0.01 && secondSide < 0.01) {
Toshihiro Shimizu 890ddd
			double displacement_, height_;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (firstSide < 0.01) {
Toshihiro Shimizu 890ddd
				// Ray hits first extremity of edge
Toshihiro Shimizu 890ddd
				if (opposite->m_concave || testRayEdgeCollision(opposite->m_prev, displacement_, height_, side1, side2))
Toshihiro Shimizu 890ddd
					type = vertex;
Toshihiro Shimizu 890ddd
			} else if (secondSide > -0.01) {
Toshihiro Shimizu 890ddd
				// Ray hits second extremity of edge
Toshihiro Shimizu 890ddd
				if (opposite->m_next->m_concave || testRayEdgeCollision(opposite->m_next, displacement_, height_, side1, side2)) {
Toshihiro Shimizu 890ddd
					type = vertex;
Toshihiro Shimizu 890ddd
					newCoGenerator = opposite->m_next;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				type = split;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (type == split_regenerate && height <= m_context->m_currentHeight) // Split regeneration is allowed only at
Toshihiro Shimizu 890ddd
			return false;													  // future times
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// If competing with another event split/vertex, approve replacement only if the angle
Toshihiro Shimizu 890ddd
		// between m_generator and newCoGenerator is < than with current m_coGenerator.
Toshihiro Shimizu 890ddd
		if (m_type != edge && fabs(displacement - m_displacement) < 0.01 && angleLess(m_coGenerator->m_edge->m_direction, newCoGenerator->m_edge->m_direction, m_generator->m_edge->m_direction))
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Pero' nel caso di quasi contemporaneo con un convesso, puo' permettere di scegliere quello con Displacement > !! ...
Toshihiro Shimizu 890ddd
		// Da rivedere... (cmq succede raramente che crei grossi problemi)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_type = type, m_coGenerator = newCoGenerator;
Toshihiro Shimizu 890ddd
		m_displacement = displacement, m_height = height;
Toshihiro Shimizu 890ddd
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
inline double Event::splitDisplacementWith(ContourNode *slab)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPointD slabLeftOrthogonal(-slab->m_edge->m_direction.y, slab->m_edge->m_direction.x);
Toshihiro Shimizu 890ddd
	double denom = m_generator->m_direction.z + slabLeftOrthogonal * TPointD(m_generator->m_direction.x, m_generator->m_direction.y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (denom < 0.01)
Toshihiro Shimizu 890ddd
		return -1; // generator-emitted ray is almost parallel to slab
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD difference = planeProjection(slab->m_position - m_generator->m_position);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (slabLeftOrthogonal * difference +
Toshihiro Shimizu 890ddd
			slab->m_position.z - m_generator->m_position.z) /
Toshihiro Shimizu 890ddd
		   denom;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
//      Event Processing
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Event::Process discriminates event types and calls their specific handlers
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool Event::process()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Timeline &timeline = m_context->m_timeline;
Toshihiro Shimizu 890ddd
	unsigned int &algoritmicTime = m_context->m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_generator->hasAttribute(ContourNode::ELIMINATED)) {
Toshihiro Shimizu 890ddd
		switch (m_type) {
Toshihiro Shimizu 890ddd
		case special: {
Toshihiro Shimizu 890ddd
			assert(!m_coGenerator->hasAttribute(ContourNode::ELIMINATED));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (m_coGenerator->m_prev->hasAttribute(ContourNode::ELIMINATED) || // These two are most probably useless - could
Toshihiro Shimizu 890ddd
				m_coGenerator->m_next->hasAttribute(ContourNode::ELIMINATED) || // try to remove them once I'm in for some testing...
Toshihiro Shimizu 890ddd
				m_algoritmicTime < m_coGenerator->m_prev->m_updateTime ||
Toshihiro Shimizu 890ddd
				m_algoritmicTime < m_coGenerator->m_next->m_updateTime) {
Toshihiro Shimizu 890ddd
				//recalculate event
Toshihiro Shimizu 890ddd
				Event newEvent(m_generator, m_context);
Toshihiro Shimizu 890ddd
				if (newEvent.m_type != failure)
Toshihiro Shimizu 890ddd
					timeline.push(newEvent);
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//else allow processing
Toshihiro Shimizu 890ddd
			algoritmicTime++;
Toshihiro Shimizu 890ddd
			processSpecialEvent();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE edge:
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				if (m_coGenerator->hasAttribute(ContourNode::ELIMINATED) ||
Toshihiro Shimizu 890ddd
					m_algoritmicTime < m_coGenerator->m_next->m_updateTime) {
Toshihiro Shimizu 890ddd
					//recalculate event
Toshihiro Shimizu 890ddd
					Event newEvent(m_generator, m_context);
Toshihiro Shimizu 890ddd
					if (newEvent.m_type != failure)
Toshihiro Shimizu 890ddd
						timeline.push(newEvent);
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Deal with edge superposition cases *only* when m_generator has the m_direction.z == 0.0
Toshihiro Shimizu 890ddd
				if ((m_coGenerator->m_direction.z == 0.0 && m_coGenerator != m_generator) ||
Toshihiro Shimizu 890ddd
					(m_coGenerator->m_next->m_direction.z == 0.0 && m_coGenerator == m_generator))
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//else allow processing
Toshihiro Shimizu 890ddd
				algoritmicTime++; //global
Toshihiro Shimizu 890ddd
				if (m_generator->m_next->m_next == m_generator->m_prev)
Toshihiro Shimizu 890ddd
					processMaxEvent();
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					processEdgeEvent();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE vertex:
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				if (m_coGenerator->hasAttribute(ContourNode::ELIMINATED)) {
Toshihiro Shimizu 890ddd
					//recalculate event
Toshihiro Shimizu 890ddd
					Event newEvent(m_generator, m_context);
Toshihiro Shimizu 890ddd
					if (newEvent.m_type != failure)
Toshihiro Shimizu 890ddd
						timeline.push(newEvent);
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				// Unlike the split case, we don't need to rebuild if
Toshihiro Shimizu 890ddd
				// the event is not up to date with m_coGenerator - since
Toshihiro Shimizu 890ddd
				// the event is not about splitting an edge
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (m_coGenerator == m_generator->m_next->m_next	 // CAN devolve to a special event - which should
Toshihiro Shimizu 890ddd
					|| m_coGenerator == m_generator->m_prev->m_prev) // already be present in the timeline
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//then, process it
Toshihiro Shimizu 890ddd
				algoritmicTime++;
Toshihiro Shimizu 890ddd
				processVertexEvent();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE split_regenerate:
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				if (m_coGenerator->hasAttribute(ContourNode::ELIMINATED) ||
Toshihiro Shimizu 890ddd
					(m_algoritmicTime < m_coGenerator->m_next->m_updateTime)) {
Toshihiro Shimizu 890ddd
					//recalculate event
Toshihiro Shimizu 890ddd
					Event newEvent(m_generator, m_context);
Toshihiro Shimizu 890ddd
					if (newEvent.m_type != failure)
Toshihiro Shimizu 890ddd
						timeline.push(newEvent);
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				// This may actually happen on current implementation, due to quirky event
Toshihiro Shimizu 890ddd
				// generation and preferential events rejection. See function tryRay..()
Toshihiro Shimizu 890ddd
				// around the end. Historically resolved to a split event, so we maintain that.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//assert(false);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case split: // No break is intended
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (m_coGenerator->hasAttribute(ContourNode::ELIMINATED) ||
Toshihiro Shimizu 890ddd
				(m_algoritmicTime < m_coGenerator->m_next->m_updateTime)) {
Toshihiro Shimizu 890ddd
				//recalculate event
Toshihiro Shimizu 890ddd
				Event newEvent(m_generator, m_context);
Toshihiro Shimizu 890ddd
				if (newEvent.m_type != failure)
Toshihiro Shimizu 890ddd
					timeline.push(newEvent);
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// else allow processing (but check these conditions)
Toshihiro Shimizu 890ddd
			if (m_coGenerator != m_generator->m_next &&
Toshihiro Shimizu 890ddd
				m_coGenerator != m_generator->m_prev->m_prev) // Because another edge already occurs at his place
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				algoritmicTime++;
Toshihiro Shimizu 890ddd
				processSplitEvent();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true; // Processing succeeded
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION:  Here is the typical case:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//        \       /
Toshihiro Shimizu 890ddd
//         \  x  /
Toshihiro Shimizu 890ddd
//          2---1 = m_coGenerator
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//m_coGenerator's edge reduces to 0. Then, nodes 1 and 2 gets ELIMINATED from
Toshihiro Shimizu 890ddd
//the active contour and a new node at position "x" is placed instead.
Toshihiro Shimizu 890ddd
//Observe also that nodes 1 or 2 may be concave (but not both)...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::processEdgeEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newNode;
Toshihiro Shimizu 890ddd
	T3DPointD position(m_generator->m_position + m_displacement * m_generator->m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Eliminate and unlink extremities of m_coGenerator's edge
Toshihiro Shimizu 890ddd
	m_coGenerator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Then, take a node from heap and insert it at their place.
Toshihiro Shimizu 890ddd
	newNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newNode->m_position = position;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_next = m_coGenerator->m_next->m_next;
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->m_next->m_prev = newNode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_prev = m_coGenerator->m_prev;
Toshihiro Shimizu 890ddd
	m_coGenerator->m_prev->m_next = newNode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Then, initialize new node (however, 3rd component is m_height...)
Toshihiro Shimizu 890ddd
	newNode->m_position =
Toshihiro Shimizu 890ddd
		m_generator->m_position + m_displacement * m_generator->m_direction;
Toshihiro Shimizu 890ddd
	newNode->m_edge = m_coGenerator->m_next->m_edge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->buildNodeInfos(1); // 1 => Force convex node
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_ancestor = m_coGenerator->m_next->m_ancestor;
Toshihiro Shimizu 890ddd
	newNode->m_ancestorContour = m_coGenerator->m_next->m_ancestorContour;
Toshihiro Shimizu 890ddd
	newNode->m_updateTime = m_context->m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// We allocate an output vertex on newNode's position under these conditions
Toshihiro Shimizu 890ddd
	// NOTE: Update once graph_old is replaced
Toshihiro Shimizu 890ddd
	if (newNode->m_direction.z < 0.7 ||
Toshihiro Shimizu 890ddd
		m_coGenerator->hasAttribute(ContourNode::SK_NODE_DROPPED) ||
Toshihiro Shimizu 890ddd
		m_coGenerator->m_next->hasAttribute(ContourNode::SK_NODE_DROPPED)) {
Toshihiro Shimizu 890ddd
		newNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
		newNode->m_outputNode = m_context->m_output->newNode(position);
Toshihiro Shimizu 890ddd
		m_context->newSkeletonLink(newNode->m_outputNode, m_coGenerator);
Toshihiro Shimizu 890ddd
		m_context->newSkeletonLink(newNode->m_outputNode, m_coGenerator->m_next);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// If m_coGenerator or its m_next is HEAD of this contour, then
Toshihiro Shimizu 890ddd
	// redefine newNode as the new head.
Toshihiro Shimizu 890ddd
	if (m_coGenerator->hasAttribute(ContourNode::HEAD) || m_coGenerator->m_next->hasAttribute(ContourNode::HEAD)) {
Toshihiro Shimizu 890ddd
		std::list<contournode *="">::iterator it;</contournode>
Toshihiro Shimizu 890ddd
		std::list<contournode *=""> &column =</contournode>
Toshihiro Shimizu 890ddd
			m_context->m_activeTable.columnOfId(m_generator->m_ancestorContour);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (it = column.begin(); !(*it)->hasAttribute(ContourNode::ELIMINATED); ++it)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//assert(*it == m_coGenerator || *it == m_coGenerator->m_next);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		*it = newNode, newNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, calculate the Event raising by newNode
Toshihiro Shimizu 890ddd
	Event newEvent(newNode, m_context);
Toshihiro Shimizu 890ddd
	if (newEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newEvent);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Typical triangle case
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::processMaxEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	T3DPointD position(m_generator->m_position + m_displacement * m_generator->m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int outputNode = m_context->m_output->newNode(position);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(outputNode, m_generator);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(outputNode, m_generator->m_prev);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(outputNode, m_generator->m_next);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Then remove active contour and eliminate nodes
Toshihiro Shimizu 890ddd
	std::list<contournode *="">::iterator eventVertexIndex =</contournode>
Toshihiro Shimizu 890ddd
		m_context->m_activeTable.find(m_generator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_context->m_activeTable.remove(eventVertexIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_generator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_generator->m_prev->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_generator->m_next->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: Ordinary split event:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//   m_coGenerator = a'---------b'
Toshihiro Shimizu 890ddd
//                         x
Toshihiro Shimizu 890ddd
//                         b = m_generator
Toshihiro Shimizu 890ddd
//                        / \
Toshihiro Shimizu 890ddd
//                       c   a
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//We eliminate b and split/merge the border/s represented in the scheme.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::processSplitEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newLeftNode, *newRightNode; // left-right in the sense of the picture
Toshihiro Shimizu 890ddd
	T3DPointD position(m_generator->m_position + m_displacement * m_generator->m_direction);
Toshihiro Shimizu 890ddd
	IndexTable &activeTable = m_context->m_activeTable;
Toshihiro Shimizu 890ddd
	unsigned int &algoritmicTime = m_context->m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// First, we find in the Index Table the contours involved
Toshihiro Shimizu 890ddd
	std::list<contournode *="">::iterator genContour, coGenContour;</contournode>
Toshihiro Shimizu 890ddd
	genContour = activeTable.find(m_generator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (activeTable.m_identifiers[m_generator->m_ancestorContour] !=
Toshihiro Shimizu 890ddd
		activeTable.m_identifiers[m_coGenerator->m_ancestorContour]) {
Toshihiro Shimizu 890ddd
		// We have two different contours, that merge in one
Toshihiro Shimizu 890ddd
		coGenContour = activeTable.find(m_coGenerator);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, update known nodes
Toshihiro Shimizu 890ddd
	m_generator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Allocate 2 new nodes and link the following way:
Toshihiro Shimizu 890ddd
	newLeftNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newRightNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newLeftNode->m_position = newRightNode->m_position = position;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// On the right side
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->m_prev = newRightNode;
Toshihiro Shimizu 890ddd
	newRightNode->m_next = m_coGenerator->m_next;
Toshihiro Shimizu 890ddd
	m_generator->m_prev->m_next = newRightNode;
Toshihiro Shimizu 890ddd
	newRightNode->m_prev = m_generator->m_prev;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// On the left side
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next = newLeftNode;
Toshihiro Shimizu 890ddd
	newLeftNode->m_prev = m_coGenerator;
Toshihiro Shimizu 890ddd
	m_generator->m_next->m_prev = newLeftNode;
Toshihiro Shimizu 890ddd
	newLeftNode->m_next = m_generator->m_next;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Assign and calculate the new nodes' informations
Toshihiro Shimizu 890ddd
	newLeftNode->m_edge = m_generator->m_edge;
Toshihiro Shimizu 890ddd
	newRightNode->m_edge = m_coGenerator->m_edge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newLeftNode->m_ancestor = m_generator->m_ancestor;
Toshihiro Shimizu 890ddd
	newLeftNode->m_ancestorContour = m_generator->m_ancestorContour;
Toshihiro Shimizu 890ddd
	newRightNode->m_ancestor = m_coGenerator->m_ancestor;
Toshihiro Shimizu 890ddd
	newRightNode->m_ancestorContour = m_coGenerator->m_ancestorContour;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// We can force the new nodes to be convex
Toshihiro Shimizu 890ddd
	newLeftNode->buildNodeInfos(1);
Toshihiro Shimizu 890ddd
	newRightNode->buildNodeInfos(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newLeftNode->m_updateTime = newRightNode->m_updateTime = algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, output the found interaction
Toshihiro Shimizu 890ddd
	newLeftNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
	newRightNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
	newLeftNode->m_outputNode = m_context->m_output->newNode(position);
Toshihiro Shimizu 890ddd
	newRightNode->m_outputNode = newLeftNode->m_outputNode;
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newLeftNode->m_outputNode, m_generator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Update the active Index Table:
Toshihiro Shimizu 890ddd
	if (activeTable.m_identifiers[m_generator->m_ancestorContour] !=
Toshihiro Shimizu 890ddd
		activeTable.m_identifiers[m_coGenerator->m_ancestorContour]) {
Toshihiro Shimizu 890ddd
		// If we have two different contours, they merge in one
Toshihiro Shimizu 890ddd
		// We keep coGenContour and remove genContour
Toshihiro Shimizu 890ddd
		(*genContour)->clearAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		activeTable.merge(coGenContour, genContour);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// Else we have only one contour, which splits in two
Toshihiro Shimizu 890ddd
		(*genContour)->clearAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		*genContour = newLeftNode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newLeftNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		newRightNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		activeTable.columnOfId(m_generator->m_ancestorContour).push_back(newRightNode);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// (Vertex compatibility): Moving newRightNode a bit on
Toshihiro Shimizu 890ddd
	newRightNode->m_position += 0.02 * newRightNode->m_direction;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, calculate the new left and right Events
Toshihiro Shimizu 890ddd
	Event newLeftEvent(newLeftNode, m_context);
Toshihiro Shimizu 890ddd
	if (newLeftEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newLeftEvent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Event newRightEvent(newRightNode, m_context);
Toshihiro Shimizu 890ddd
	if (newRightEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newRightEvent);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//               c     L     a'
Toshihiro Shimizu 890ddd
//                \         /
Toshihiro Shimizu 890ddd
//  m_generator =  b   x   b' = m_coGenerator
Toshihiro Shimizu 890ddd
//                /         \
Toshihiro Shimizu 890ddd
//               a     R     c'
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Reflex vertices b and b' collide. Observe that a new reflex vertex may rise
Toshihiro Shimizu 890ddd
//here.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::processVertexEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newLeftNode, *newRightNode; // left-right in the sense of the picture
Toshihiro Shimizu 890ddd
	T3DPointD position(m_generator->m_position + m_displacement * m_generator->m_direction);
Toshihiro Shimizu 890ddd
	IndexTable &activeTable = m_context->m_activeTable;
Toshihiro Shimizu 890ddd
	unsigned int &algoritmicTime = m_context->m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// First, we find in the Index Table the contours involved
Toshihiro Shimizu 890ddd
	std::list<contournode *="">::iterator genContour, coGenContour;</contournode>
Toshihiro Shimizu 890ddd
	genContour = activeTable.find(m_generator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (activeTable.m_identifiers[m_generator->m_ancestorContour] !=
Toshihiro Shimizu 890ddd
		activeTable.m_identifiers[m_coGenerator->m_ancestorContour]) {
Toshihiro Shimizu 890ddd
		// We have two different contours, that merge in one
Toshihiro Shimizu 890ddd
		coGenContour = activeTable.find(m_coGenerator);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, update known nodes
Toshihiro Shimizu 890ddd
	m_generator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_coGenerator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Allocate 2 new nodes and link the following way:
Toshihiro Shimizu 890ddd
	newLeftNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newRightNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newLeftNode->m_position = newRightNode->m_position = position;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// On the right side
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->m_prev = newRightNode;
Toshihiro Shimizu 890ddd
	newRightNode->m_next = m_coGenerator->m_next;
Toshihiro Shimizu 890ddd
	m_generator->m_prev->m_next = newRightNode;
Toshihiro Shimizu 890ddd
	newRightNode->m_prev = m_generator->m_prev;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// On the left side
Toshihiro Shimizu 890ddd
	m_coGenerator->m_prev->m_next = newLeftNode;
Toshihiro Shimizu 890ddd
	newLeftNode->m_prev = m_coGenerator->m_prev;
Toshihiro Shimizu 890ddd
	m_generator->m_next->m_prev = newLeftNode;
Toshihiro Shimizu 890ddd
	newLeftNode->m_next = m_generator->m_next;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Assign and calculate the new nodes' informations
Toshihiro Shimizu 890ddd
	newLeftNode->m_edge = m_generator->m_edge;
Toshihiro Shimizu 890ddd
	newRightNode->m_edge = m_coGenerator->m_edge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newLeftNode->m_ancestor = m_generator->m_ancestor;
Toshihiro Shimizu 890ddd
	newLeftNode->m_ancestorContour = m_generator->m_ancestorContour;
Toshihiro Shimizu 890ddd
	newRightNode->m_ancestor = m_coGenerator->m_ancestor;
Toshihiro Shimizu 890ddd
	newRightNode->m_ancestorContour = m_coGenerator->m_ancestorContour;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// We *CAN'T* force the new nodes to be convex here
Toshihiro Shimizu 890ddd
	newLeftNode->buildNodeInfos();
Toshihiro Shimizu 890ddd
	newRightNode->buildNodeInfos();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newLeftNode->m_updateTime = newRightNode->m_updateTime = algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now, output the found interaction
Toshihiro Shimizu 890ddd
	newLeftNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
	newRightNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
	newLeftNode->m_outputNode = m_context->m_output->newNode(position);
Toshihiro Shimizu 890ddd
	newRightNode->m_outputNode = newLeftNode->m_outputNode;
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newLeftNode->m_outputNode, m_generator);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newLeftNode->m_outputNode, m_coGenerator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Update the active Index Table
Toshihiro Shimizu 890ddd
	if (activeTable.m_identifiers[m_generator->m_ancestorContour] !=
Toshihiro Shimizu 890ddd
		activeTable.m_identifiers[m_coGenerator->m_ancestorContour]) {
Toshihiro Shimizu 890ddd
		// If we have two different contours, they merge in one
Toshihiro Shimizu 890ddd
		(*coGenContour)->clearAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		activeTable.merge(genContour, coGenContour);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Check if the generator is head, if so update.
Toshihiro Shimizu 890ddd
		if (m_generator->hasAttribute(ContourNode::HEAD)) {
Toshihiro Shimizu 890ddd
			newLeftNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
			*genContour = newLeftNode;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// Else we have only one contour, which splits in two
Toshihiro Shimizu 890ddd
		(*genContour)->clearAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		*genContour = newLeftNode;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newLeftNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
		newRightNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		activeTable.columnOfId(m_generator->m_ancestorContour).push_back(newRightNode);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Before calculating the new interactions, to each new node we assign
Toshihiro Shimizu 890ddd
	// as impossible opposite edges the adjacent of the other node.
Toshihiro Shimizu 890ddd
	if (newLeftNode->m_concave) {
Toshihiro Shimizu 890ddd
		newLeftNode->m_notOpposites = m_generator->m_notOpposites;
Toshihiro Shimizu 890ddd
		append<vector<contouredge *="">, vector<contouredge *="">::reverse_iterator>(newLeftNode->m_notOpposites, m_coGenerator->m_notOpposites);</contouredge></vector<contouredge>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newLeftNode->m_notOpposites.push_back(newRightNode->m_edge);
Toshihiro Shimizu 890ddd
		newLeftNode->m_notOpposites.push_back(newRightNode->m_prev->m_edge);
Toshihiro Shimizu 890ddd
	} else if (newLeftNode->m_concave) {
Toshihiro Shimizu 890ddd
		newRightNode->m_notOpposites = m_generator->m_notOpposites;
Toshihiro Shimizu 890ddd
		append<vector<contouredge *="">, vector<contouredge *="">::reverse_iterator>(newRightNode->m_notOpposites, m_coGenerator->m_notOpposites);</contouredge></vector<contouredge>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newRightNode->m_notOpposites.push_back(newLeftNode->m_edge);
Toshihiro Shimizu 890ddd
		newRightNode->m_notOpposites.push_back(newLeftNode->m_prev->m_edge);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// We also forbid newRightNode to be involved in events at the same location of this one.
Toshihiro Shimizu 890ddd
	// We just push its position in the m_direction by 0.02.
Toshihiro Shimizu 890ddd
	newRightNode->m_position += 0.02 * newRightNode->m_direction;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, calculate the new left and right Events
Toshihiro Shimizu 890ddd
	Event newLeftEvent(newLeftNode, m_context);
Toshihiro Shimizu 890ddd
	if (newLeftEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newLeftEvent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Event newRightEvent(newRightNode, m_context);
Toshihiro Shimizu 890ddd
	if (newRightEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newRightEvent);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//             x
Toshihiro Shimizu 890ddd
//        ---c   a---
Toshihiro Shimizu 890ddd
//            \ /
Toshihiro Shimizu 890ddd
//             b = m_coGenerator
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Typical "V" event in which rays emitted from a, b and c collide.
Toshihiro Shimizu 890ddd
//This events have to be recognized different from vertex events, and
Toshihiro Shimizu 890ddd
//better treated as a whole event, rather than two simultaneous edge events.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Event::processSpecialEvent()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ContourNode *newNode;
Toshihiro Shimizu 890ddd
	T3DPointD position(m_generator->m_position + m_displacement * m_generator->m_direction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_coGenerator->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_coGenerator->m_prev->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->setAttribute(ContourNode::ELIMINATED);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Get and link newNode to the rest of this contour
Toshihiro Shimizu 890ddd
	newNode = m_context->getNode();
Toshihiro Shimizu 890ddd
	newNode->m_position = position;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_coGenerator->m_prev->m_prev->m_next = newNode;
Toshihiro Shimizu 890ddd
	newNode->m_prev = m_coGenerator->m_prev->m_prev;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_coGenerator->m_next->m_next->m_prev = newNode;
Toshihiro Shimizu 890ddd
	newNode->m_next = m_coGenerator->m_next->m_next;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Then, initialize newNode infos
Toshihiro Shimizu 890ddd
	newNode->m_edge = m_coGenerator->m_next->m_edge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newNode->m_ancestor = m_coGenerator->m_next->m_ancestor;
Toshihiro Shimizu 890ddd
	newNode->m_ancestorContour = m_coGenerator->m_next->m_ancestorContour;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Neither this case can be forced convex
Toshihiro Shimizu 890ddd
	newNode->buildNodeInfos();
Toshihiro Shimizu 890ddd
	newNode->m_updateTime = m_context->m_algoritmicTime;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Now build output
Toshihiro Shimizu 890ddd
	newNode->setAttribute(ContourNode::SK_NODE_DROPPED);
Toshihiro Shimizu 890ddd
	newNode->m_outputNode = m_context->m_output->newNode(position);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newNode->m_outputNode, m_coGenerator->m_prev);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newNode->m_outputNode, m_coGenerator);
Toshihiro Shimizu 890ddd
	m_context->newSkeletonLink(newNode->m_outputNode, m_coGenerator->m_next);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// If m_coGenerator or one of his adjacents is HEAD of this contour, then
Toshihiro Shimizu 890ddd
	// redefine newNode as the new head.
Toshihiro Shimizu 890ddd
	if (m_coGenerator->hasAttribute(ContourNode::HEAD) || m_coGenerator->m_next->hasAttribute(ContourNode::HEAD) || m_coGenerator->m_prev->hasAttribute(ContourNode::HEAD)) {
Toshihiro Shimizu 890ddd
		std::list<contournode *="">::iterator it;</contournode>
Toshihiro Shimizu 890ddd
		std::list<contournode *=""> &column =</contournode>
Toshihiro Shimizu 890ddd
			m_context->m_activeTable.columnOfId(m_generator->m_ancestorContour);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (it = column.begin(); !(*it)->hasAttribute(ContourNode::ELIMINATED); ++it)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//assert(*it == m_coGenerator || *it == m_coGenerator->m_next || *it == m_coGenerator->m_prev);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		*it = newNode, newNode->setAttribute(ContourNode::HEAD);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, calculate the Event raising by newNode
Toshihiro Shimizu 890ddd
	Event newEvent(newNode, m_context);
Toshihiro Shimizu 890ddd
	if (newEvent.m_type != Event::failure)
Toshihiro Shimizu 890ddd
		m_context->m_timeline.push(newEvent);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------
Toshihiro Shimizu 890ddd
//    Straight Skeleton mains
Toshihiro Shimizu 890ddd
//-------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SkeletonGraph *skeletonize(ContourFamily ®ionContours, VectorizationContext &context,
Toshihiro Shimizu 890ddd
						   VectorizerCore *thisVectorizer)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	SkeletonGraph *output = context.m_output = new SkeletonGraph;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	context.prepareContours(regionContours);
Toshihiro Shimizu 890ddd
	context.prepareGlobals();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	IndexTable &activeTable = context.m_activeTable;
Toshihiro Shimizu 890ddd
	activeTable.build(regionContours);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double maxThickness = context.m_globals->currConfig->m_maxThickness;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (maxThickness > 0.0) //if(!currConfig->m_outline)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		Timeline &timeline = context.m_timeline;
Toshihiro Shimizu 890ddd
		timeline.build(regionContours, context, thisVectorizer);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _SSDEBUG
Toshihiro Shimizu 890ddd
		SSDebugger debugger(context);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool spawnDebugger = false;
Toshihiro Shimizu 890ddd
		if (timeline.size() > 1000) {
Toshihiro Shimizu 890ddd
			debugger.m_height = context.m_currentHeight;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			debugger.show();
Toshihiro Shimizu 890ddd
			debugger.raise();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			debugger.repaint();
Toshihiro Shimizu 890ddd
			debugger.loop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			spawnDebugger = true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (thisVectorizer->isCanceled()) {
Toshihiro Shimizu 890ddd
			//Bailing out
Toshihiro Shimizu 890ddd
			while (!timeline.empty())
Toshihiro Shimizu 890ddd
				timeline.pop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			context.m_nodesHeap.clear();
Toshihiro Shimizu 890ddd
			context.m_edgesHeap.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			context.m_linearNodesHeap.clear();
Toshihiro Shimizu 890ddd
			context.m_linearEdgesHeap.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return output;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Process timeline
Toshihiro Shimizu 890ddd
		while (!timeline.empty()) {
Toshihiro Shimizu 890ddd
			Event currentEvent = timeline.top();
Toshihiro Shimizu 890ddd
			timeline.pop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//If maxThickness hit, stop before processing
Toshihiro Shimizu 890ddd
			if (currentEvent.m_height >= maxThickness)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Redraw debugger window
Toshihiro Shimizu 890ddd
#ifdef _SSDEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (spawnDebugger && debugger.isOnScreen(currentEvent.m_generator)) {
Toshihiro Shimizu 890ddd
				debugger.m_height = currentEvent.m_height;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				debugger.repaint();
Toshihiro Shimizu 890ddd
				debugger.loop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (currentEvent.m_type == Event::split || currentEvent.m_type == Event::vertex)
Toshihiro Shimizu 890ddd
					currentEvent.tryRayEdgeCollisionWith(currentEvent.m_coGenerator);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (currentEvent.m_type == Event::edge)
Toshihiro Shimizu 890ddd
					currentEvent.calculateEdgeEvent();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif // _SSDEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Process event
Toshihiro Shimizu 890ddd
			currentEvent.process();
Toshihiro Shimizu 890ddd
			context.m_currentHeight = currentEvent.m_height;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//The thinning process terminates: deleting non-original nodes and edges.
Toshihiro Shimizu 890ddd
		while (!timeline.empty())
Toshihiro Shimizu 890ddd
			timeline.pop();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _SSDEBUG
Toshihiro Shimizu 890ddd
		if (spawnDebugger) {
Toshihiro Shimizu 890ddd
			debugger.m_height = context.m_currentHeight;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			debugger.repaint();
Toshihiro Shimizu 890ddd
			debugger.loop();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
#endif // _SSDEBUG
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, update remaining nodes not processed due to maxThickness and connect them to output skeleton
Toshihiro Shimizu 890ddd
	unsigned int i, l, n;
Toshihiro Shimizu 890ddd
	IndexTable::IndexColumn::iterator j;
Toshihiro Shimizu 890ddd
	ContourNode *k;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < regionContours.size(); ++i)
Toshihiro Shimizu 890ddd
		for (j = activeTable[i]->begin(); j != activeTable[i]->end(); ++j) {
Toshihiro Shimizu 890ddd
			unsigned int count = 0;
Toshihiro Shimizu 890ddd
			unsigned int addedNode;
Toshihiro Shimizu 890ddd
			for (k = *j; !k->hasAttribute(ContourNode::HEAD) || !count; k = k->m_next) {
Toshihiro Shimizu 890ddd
				addedNode =
Toshihiro Shimizu 890ddd
					output->newNode(k->m_position + k->m_direction * ((maxThickness - k->m_position.z) / (k->m_direction.z > 0.01 ? k->m_direction.z : 1)));
Toshihiro Shimizu 890ddd
				context.newSkeletonLink(addedNode, k);
Toshihiro Shimizu 890ddd
				//output->node(addedNode).setAttribute(ContourNode::SS_OUTLINE);
Toshihiro Shimizu 890ddd
				++count;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			n = output->getNodesCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			SkeletonArc arcCopy;
Toshihiro Shimizu 890ddd
			SkeletonArc arcCopyRev;
Toshihiro Shimizu 890ddd
			arcCopy.setAttribute(SkeletonArc::SS_OUTLINE);
Toshihiro Shimizu 890ddd
			arcCopyRev.setAttribute(SkeletonArc::SS_OUTLINE_REVERSED);
Toshihiro Shimizu 890ddd
			for (l = 1; l < count; ++l) {
Toshihiro Shimizu 890ddd
				output->newLink(n - l, n - l - 1, arcCopyRev);
Toshihiro Shimizu 890ddd
				output->newLink(n - l - 1, n - l, arcCopy);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			output->newLink(n - l, n - 1, arcCopyRev);
Toshihiro Shimizu 890ddd
			output->newLink(n - 1, n - l, arcCopy);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	context.m_nodesHeap.clear();
Toshihiro Shimizu 890ddd
	context.m_edgesHeap.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	context.m_linearNodesHeap.clear();
Toshihiro Shimizu 890ddd
	context.m_linearEdgesHeap.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return output;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SkeletonList *skeletonize(Contours &contours, VectorizerCore *thisVectorizer,
Toshihiro Shimizu 890ddd
						  VectorizerCoreGlobals &g)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	VectorizationContext context(&g);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkeletonList *res = new SkeletonList;
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Find overall number of nodes
Toshihiro Shimizu 890ddd
	unsigned int overallNodes = 0;
Toshihiro Shimizu 890ddd
	for (i = 0; i < contours.size(); ++i)
Toshihiro Shimizu 890ddd
		for (j = 0; j < contours[i].size(); ++j)
Toshihiro Shimizu 890ddd
			overallNodes += contours[i][j].size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	thisVectorizer->setOverallPartials(overallNodes);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < contours.size(); ++i) {
Toshihiro Shimizu 890ddd
		res->push_back(skeletonize(contours[i], context, thisVectorizer));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (thisVectorizer->isCanceled())
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------
Toshihiro Shimizu 890ddd
//    DEBUG
Toshihiro Shimizu 890ddd
//--------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _SSDEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
SSDebugger::SSDebugger(VectorizationContext &context)
Toshihiro Shimizu 890ddd
	: m_context(context), m_scale(1.0), m_loop(this), m_transform(1, 0, 0, -1, 0, height())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setMouseTracking(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline TPointD SSDebugger::updated(ContourNode *node)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
#ifndef _PREPROCESS
Toshihiro Shimizu 890ddd
#ifdef _UPDATE
Toshihiro Shimizu 890ddd
	if (node->m_direction.z > 1e-4) {
Toshihiro Shimizu 890ddd
		return planeProjection(node->m_position + ((m_height - node->m_position.z) / node->m_direction.z) * node->m_direction);
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		return planeProjection(node->m_position);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return planeProjection(node->m_position);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define line(a, b) p.drawLine(QLineF((a).x, (a).y, (b).x, (b).y));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::paintEvent(QPaintEvent *)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QPainter p(this);
Toshihiro Shimizu 890ddd
	p.setTransform(m_transform);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Draw currently produced skeleton
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const SkeletonGraph &skeleton = *m_context.m_output;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p.setPen(Qt::blue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int n, nCount = skeleton.getNodesCount();
Toshihiro Shimizu 890ddd
		for (n = 0; n != nCount; ++n) {
Toshihiro Shimizu 890ddd
			const SkeletonGraph::Node &node = skeleton.getNode(n);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int l, lCount = node.getLinksCount();
Toshihiro Shimizu 890ddd
			for (l = 0; l != lCount; ++l)
Toshihiro Shimizu 890ddd
				line(*node, *skeleton.getNode(node.getLink(l).getNext()));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Draw background Debug Point
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Versione updated
Toshihiro Shimizu 890ddd
	IndexTable &activeTable = m_context.m_activeTable;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	ContourNode *first, *last, *currNode;
Toshihiro Shimizu 890ddd
	std::list<contournode *="">::iterator currentContour;</contournode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < activeTable.m_columns.size(); ++i) {
Toshihiro Shimizu 890ddd
		for (currentContour = activeTable[i]->begin();
Toshihiro Shimizu 890ddd
			 currentContour != activeTable[i]->end(); currentContour++) {
Toshihiro Shimizu 890ddd
			//Draw edge
Toshihiro Shimizu 890ddd
			p.setPen(Qt::black);
Toshihiro Shimizu 890ddd
			last = first = *currentContour;
Toshihiro Shimizu 890ddd
			first = first->m_next;
Toshihiro Shimizu 890ddd
			//assert(!last->hasAttribute(ContourNode::ELIMINATED));
Toshihiro Shimizu 890ddd
			line(updated(last), updated(first));
Toshihiro Shimizu 890ddd
			for (currNode = first; !currNode->hasAttribute(ContourNode::HEAD); currNode = currNode->m_next) {
Toshihiro Shimizu 890ddd
				//assert(!currNode->hasAttribute(ContourNode::ELIMINATED));
Toshihiro Shimizu 890ddd
				line(updated(currNode), updated(currNode->m_next));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Draw bisector
Toshihiro Shimizu 890ddd
			p.setPen(Qt::red);
Toshihiro Shimizu 890ddd
			last = first = *currentContour;
Toshihiro Shimizu 890ddd
			first = first->m_next;
Toshihiro Shimizu 890ddd
			line(updated(last), updated(last) + planeProjection(last->m_direction));
Toshihiro Shimizu 890ddd
			for (currNode = first; !currNode->hasAttribute(ContourNode::HEAD); currNode = currNode->m_next)
Toshihiro Shimizu 890ddd
				line(updated(currNode), updated(currNode) + planeProjection(currNode->m_direction));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Draw edge
Toshihiro Shimizu 890ddd
			p.setPen(Qt::green);
Toshihiro Shimizu 890ddd
			last = first = *currentContour;
Toshihiro Shimizu 890ddd
			first = first->m_next;
Toshihiro Shimizu 890ddd
			line(updated(last), updated(last) + last->m_edge->m_direction);
Toshihiro Shimizu 890ddd
			for (currNode = first; !currNode->hasAttribute(ContourNode::HEAD); currNode = currNode->m_next)
Toshihiro Shimizu 890ddd
				line(updated(currNode), updated(currNode) + currNode->m_edge->m_direction);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, draw text strings
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		p.setPen(Qt::red);
Toshihiro Shimizu 890ddd
		p.setTransform(QTransform());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const QPointF &worldPos = winToWorldF(m_pos.x(), m_pos.y());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		p.drawText(rect().bottomLeft(), QString("WinPos: %1 %2  WorldPos: %3 %4")
Toshihiro Shimizu 890ddd
											.arg(m_pos.x())
Toshihiro Shimizu 890ddd
											.arg(m_pos.y())
Toshihiro Shimizu 890ddd
											.arg(worldPos.x())
Toshihiro Shimizu 890ddd
											.arg(worldPos.y()));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::keyPressEvent(QKeyEvent *event)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_loop.exit();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::mouseMoveEvent(QMouseEvent *event)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_pos = event->pos();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (event->buttons() == Qt::MiddleButton) {
Toshihiro Shimizu 890ddd
		m_transform.translate((event->x() - m_pressPos.x()) / m_scale,
Toshihiro Shimizu 890ddd
							  (m_pressPos.y() - event->y()) / m_scale);
Toshihiro Shimizu 890ddd
		m_pressPos = event->pos();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::mousePressEvent(QMouseEvent *event)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_pressPos = m_pos = event->pos();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::mouseReleaseEvent(QMouseEvent *event)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QPoint SSDebugger::worldToWin(double x, double y)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_transform.map(QPointF(x, y)).toPoint();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QPoint SSDebugger::winToWorld(int x, int y)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_transform.inverted().map(QPoint(x, y));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QPointF SSDebugger::winToWorldF(int x, int y)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_transform.inverted().map(QPointF(x, y));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void SSDebugger::wheelEvent(QWheelEvent *event)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QPoint w_coords;
Toshihiro Shimizu 890ddd
	double zoom_par = 1 + event->delta() * 0.001;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_scale *= zoom_par;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	w_coords = winToWorld(event->x(), event->y());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_transform.translate(w_coords.x(), w_coords.y());
Toshihiro Shimizu 890ddd
	m_transform.scale(zoom_par, zoom_par);
Toshihiro Shimizu 890ddd
	m_transform.translate(-w_coords.x(), -w_coords.y());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	update();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool SSDebugger::isOnScreen(ContourNode *node)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TPointD &pos = updated(node);
Toshihiro Shimizu 890ddd
	return rect().contains(worldToWin(pos.x, pos.y));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif