Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tcenterlinevectP.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
//    Skeleton re-organization
Toshihiro Shimizu 890ddd
//*********************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------
Toshihiro Shimizu 890ddd
//    Skeleton re-organization Globals
Toshihiro Shimizu 890ddd
//----------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
VectorizerCoreGlobals *globals;
Toshihiro Shimizu 890ddd
std::vector<unsigned int=""> contourFamilyOfOrganized;</unsigned>
Toshihiro Shimizu 890ddd
JointSequenceGraph *currJSGraph;
Toshihiro Shimizu 890ddd
ContourFamily *currContourFamily;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------
Toshihiro Shimizu 890ddd
//      Skeleton re-organization
Toshihiro Shimizu 890ddd
//--------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION:  The raw skeleton data obtained from StraightSkeletonizer
Toshihiro Shimizu 890ddd
//class need to be grouped in joints and sequences before proceding with
Toshihiro Shimizu 890ddd
//conversion in quadratics - which works on single sequences.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//NOTE: Due to maxHeight, we have to assume that a single SkeletonGraph can hold
Toshihiro Shimizu 890ddd
//more connected graphs at once.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//a) Isolate graph-like part of skeleton
Toshihiro Shimizu 890ddd
//b) Retrieve remaining single sequences.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::map<uint, std::less<uint="" uint,="">> uintMap;</uint,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//void organizeGraphs(SkeletonList* skeleton)
Toshihiro Shimizu 890ddd
void organizeGraphs(SkeletonList *skeleton, VectorizerCoreGlobals &g)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	globals = &g;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkeletonList::iterator currGraphPtr;
Toshihiro Shimizu 890ddd
	Sequence currSequence;
Toshihiro Shimizu 890ddd
	uintMap jointsMap;
Toshihiro Shimizu 890ddd
	UINT i, j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	UINT counter = 0; //We also count current graph number, to associate
Toshihiro Shimizu 890ddd
					  //organized graphs to their contour family
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	contourFamilyOfOrganized.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (currGraphPtr = skeleton->begin(); currGraphPtr != skeleton->end(); ++currGraphPtr) {
Toshihiro Shimizu 890ddd
		SkeletonGraph &currGraph = **currGraphPtr;
Toshihiro Shimizu 890ddd
		currSequence.m_graphHolder = &currGraph;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Separate single Points - can happen only when a single node gets stored in a SkeletonGraph.
Toshihiro Shimizu 890ddd
		if (currGraph.getNodesCount() == 1) {
Toshihiro Shimizu 890ddd
			globals->singlePoints.push_back(*currGraph.getNode(0));
Toshihiro Shimizu 890ddd
			++counter;
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Discriminate between graphs, two-endpoint single sequences, and circular ones
Toshihiro Shimizu 890ddd
		bool has1DegreePoint = 0;
Toshihiro Shimizu 890ddd
		for (i = 0; i < currGraph.getNodesCount(); ++i)
Toshihiro Shimizu 890ddd
			if (currGraph.getNode(i).degree() != 2)
Toshihiro Shimizu 890ddd
				if (currGraph.getNode(i).degree() == 1)
Toshihiro Shimizu 890ddd
					has1DegreePoint = 1;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					goto _graph;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (has1DegreePoint)
Toshihiro Shimizu 890ddd
			goto _two_endpoint;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			goto _circulars;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	_two_endpoint : {
Toshihiro Shimizu 890ddd
		//Find head
Toshihiro Shimizu 890ddd
		for (i = 0; currGraph.getNode(i).degree() != 1; ++i)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		currSequence.m_head = i;
Toshihiro Shimizu 890ddd
		currSequence.m_headLink = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Find tail
Toshihiro Shimizu 890ddd
		for (++i; i < currGraph.getNodesCount() &&
Toshihiro Shimizu 890ddd
				  currGraph.getNode(i).degree() == 2;
Toshihiro Shimizu 890ddd
			 ++i)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
		currSequence.m_tail = i;
Toshihiro Shimizu 890ddd
		currSequence.m_tailLink = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		globals->singleSequences.push_back(currSequence);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		++counter;
Toshihiro Shimizu 890ddd
		continue;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	_graph : {
Toshihiro Shimizu 890ddd
		//Organize Graph-like part
Toshihiro Shimizu 890ddd
		globals->organizedGraphs.push_back(JointSequenceGraph());
Toshihiro Shimizu 890ddd
		JointSequenceGraph &JSGraph = globals->organizedGraphs.back();
Toshihiro Shimizu 890ddd
		contourFamilyOfOrganized.push_back(counter);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		jointsMap.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Gather all sequence extremities
Toshihiro Shimizu 890ddd
		for (i = 0; i < currGraph.getNodesCount(); ++i) {
Toshihiro Shimizu 890ddd
			if (currGraph.getNode(i).degree() != 2) {
Toshihiro Shimizu 890ddd
				j = JSGraph.newNode(i);
Toshihiro Shimizu 890ddd
				//Using a map to keep one-to-one relation between j and i
Toshihiro Shimizu 890ddd
				jointsMap.insert(uintMap::value_type(i, j));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Extract Sequences
Toshihiro Shimizu 890ddd
		for (i = 0; i < JSGraph.getNodesCount(); ++i) {
Toshihiro Shimizu 890ddd
			UINT joint = *JSGraph.getNode(i);
Toshihiro Shimizu 890ddd
			for (j = 0; j < currGraph.getNode(joint).getLinksCount(); ++j) {
Toshihiro Shimizu 890ddd
				currSequence.m_head = joint;
Toshihiro Shimizu 890ddd
				currSequence.m_headLink = j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Seek tail
Toshihiro Shimizu 890ddd
				UINT oldNode = joint, thisNode = currGraph.getNode(joint).getLink(j).getNext();
Toshihiro Shimizu 890ddd
				while (currGraph.getNode(thisNode).degree() == 2) {
Toshihiro Shimizu 890ddd
					currGraph.node(thisNode).setAttribute(ORGANIZEGRAPHS_SIGN); //Sign thisNode as part of a JSGraph
Toshihiro Shimizu 890ddd
					currSequence.advance(oldNode, thisNode);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				currSequence.m_tail = thisNode;
Toshihiro Shimizu 890ddd
				currSequence.m_tailLink = currGraph.getNode(thisNode).linkOfNode(oldNode);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				JSGraph.newLink(i, jointsMap.find(thisNode)->second, currSequence);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NOTE: The following may seem uncommon - you must observe that, *WHEN maxThickness
Toshihiro Shimizu 890ddd
	//      more isolated sequence groups may arise in the SAME SkeletonGraph; so, an organized
Toshihiro Shimizu 890ddd
	//      graph may contain different unconnected basic graph-structures.
Toshihiro Shimizu 890ddd
	//      Further, remaining circular sequences may still exist. Therefore:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Proceed with remaining circulars extraction
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	_circulars : {
Toshihiro Shimizu 890ddd
		//Extract all circular sequences
Toshihiro Shimizu 890ddd
		//Find a sequence point
Toshihiro Shimizu 890ddd
		for (i = 0; i < currGraph.getNodesCount(); ++i) {
Toshihiro Shimizu 890ddd
			if (!currGraph.getNode(i).hasAttribute(ORGANIZEGRAPHS_SIGN) && currGraph.getNode(i).degree() == 2) {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				unsigned int curr = i, currLink = 0;
Toshihiro Shimizu 890ddd
				currSequence.next(curr, currLink);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (; curr != i; currSequence.next(curr, currLink))
Toshihiro Shimizu 890ddd
					currGraph.node(curr).setAttribute(ORGANIZEGRAPHS_SIGN);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Add sequence
Toshihiro Shimizu 890ddd
				currSequence.m_head = currSequence.m_tail = i;
Toshihiro Shimizu 890ddd
				currSequence.m_headLink = 0;
Toshihiro Shimizu 890ddd
				currSequence.m_tailLink = 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				globals->singleSequences.push_back(currSequence);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************
Toshihiro Shimizu 890ddd
//       Junction Recovery
Toshihiro Shimizu 890ddd
//******************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: Junction recovery attempts to reshape skeleton junctions when
Toshihiro Shimizu 890ddd
//  possible. The original polygons shape must not be exceedingly broken, and
Toshihiro Shimizu 890ddd
//  no visible shape alteration must found.
Toshihiro Shimizu 890ddd
//WARNING: Currently not working together with globals->currConfig->m_maxThickness
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------
Toshihiro Shimizu 890ddd
//    Globals
Toshihiro Shimizu 890ddd
//------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
const double roadsMaxSlope = 0.3;
Toshihiro Shimizu 890ddd
const double shapeDistMul = 1;
Toshihiro Shimizu 890ddd
const double hDiffMul = 0.3;
Toshihiro Shimizu 890ddd
const double lineDistMul = 1;
Toshihiro Shimizu 890ddd
const double pullBackMul = 0.2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------
Toshihiro Shimizu 890ddd
//    Roads Extraction
Toshihiro Shimizu 890ddd
//-------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//SMALL ISSUE: The following is currently done for both side
Toshihiro Shimizu 890ddd
//of a sequence...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void findRoads(const Sequence &s)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int curr, currLink, next;
Toshihiro Shimizu 890ddd
	unsigned int roadStart, roadStartLink;
Toshihiro Shimizu 890ddd
	double d, hMax, length;
Toshihiro Shimizu 890ddd
	bool lowSlope, roadOn = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	curr = s.m_head;
Toshihiro Shimizu 890ddd
	currLink = s.m_headLink;
Toshihiro Shimizu 890ddd
	for (; curr != s.m_tail; s.next(curr, currLink)) {
Toshihiro Shimizu 890ddd
		next = s.m_graphHolder->getNode(curr).getLink(currLink).getNext();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		d = planeDistance(*s.m_graphHolder->getNode(curr), *s.m_graphHolder->getNode(next));
Toshihiro Shimizu 890ddd
		lowSlope = fabs(s.m_graphHolder->getNode(curr).getLink(currLink)->getSlope()) < roadsMaxSlope ? 1 : 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Entering event in a *possibile* road axis
Toshihiro Shimizu 890ddd
		if (!roadOn && lowSlope) {
Toshihiro Shimizu 890ddd
			length = 0;
Toshihiro Shimizu 890ddd
			hMax = s.m_graphHolder->getNode(curr)->z;
Toshihiro Shimizu 890ddd
			roadStart = curr;
Toshihiro Shimizu 890ddd
			roadStartLink = currLink;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Exit event from a          """
Toshihiro Shimizu 890ddd
		else if (roadOn && !lowSlope && (length > hMax))
Toshihiro Shimizu 890ddd
			//Then sign ROAD the sequence from roadStart to curr.
Toshihiro Shimizu 890ddd
			for (; roadStart != curr; s.next(roadStart, roadStartLink))
Toshihiro Shimizu 890ddd
				s.m_graphHolder->node(roadStart).link(roadStartLink)->setAttribute(SkeletonArc::ROAD);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Now update vars
Toshihiro Shimizu 890ddd
		if (lowSlope) {
Toshihiro Shimizu 890ddd
			length += d;
Toshihiro Shimizu 890ddd
			if (hMax < s.m_graphHolder->getNode(next)->z)
Toshihiro Shimizu 890ddd
				hMax = s.m_graphHolder->getNode(next)->z;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		roadOn = lowSlope;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//At sequence end, force an exit event
Toshihiro Shimizu 890ddd
	if (roadOn && (length > hMax))
Toshihiro Shimizu 890ddd
		for (; roadStart != curr; s.next(roadStart, roadStartLink))
Toshihiro Shimizu 890ddd
			s.m_graphHolder->node(roadStart).link(roadStartLink)->setAttribute(SkeletonArc::ROAD);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Find the 'roads' of the current Graph.
Toshihiro Shimizu 890ddd
void findRoads(const JointSequenceGraph &JSGraph)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For all Sequence of currGraph, extract roads
Toshihiro Shimizu 890ddd
	for (i = 0; i < JSGraph.getNodesCount(); ++i) {
Toshihiro Shimizu 890ddd
		for (j = 0; j < JSGraph.getNode(i).getLinksCount(); ++j)
Toshihiro Shimizu 890ddd
			//if(JSGraph.getNode(i).getLink(j)->isForward())
Toshihiro Shimizu 890ddd
			findRoads(*JSGraph.getNode(i).getLink(j));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------
Toshihiro Shimizu 890ddd
//    Junction Recovery Classes
Toshihiro Shimizu 890ddd
//----------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Entering point of a Sequence inside a Junction Area
Toshihiro Shimizu 890ddd
class EnteringSequence : public Sequence
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TPointD m_direction; //In this case, we keep
Toshihiro Shimizu 890ddd
	double m_height;	 //separated (x,y) and z coords.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Also store indices toward the next (outer) joint
Toshihiro Shimizu 890ddd
	unsigned int m_initialJoint;
Toshihiro Shimizu 890ddd
	unsigned int m_outerLink;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	EnteringSequence() {}
Toshihiro Shimizu 890ddd
	EnteringSequence(const Sequence &s) : Sequence(s) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class JunctionArea
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	vector<enteringsequence> m_enteringSequences;</enteringsequence>
Toshihiro Shimizu 890ddd
	vector<unsigned int=""> m_jointsAbsorbed;</unsigned>
Toshihiro Shimizu 890ddd
	TPointD m_newJointPosition;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	JunctionArea() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Initialize Junction Area
Toshihiro Shimizu 890ddd
	void expandArea(unsigned int initial);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate and evaluate area
Toshihiro Shimizu 890ddd
	bool checkShape();
Toshihiro Shimizu 890ddd
	bool solveJunctionPosition();
Toshihiro Shimizu 890ddd
	bool makeHeights();
Toshihiro Shimizu 890ddd
	bool calculateReconstruction();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Substitute area over old configuration
Toshihiro Shimizu 890ddd
	bool sequencesPullBack();
Toshihiro Shimizu 890ddd
	void apply();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------
Toshihiro Shimizu 890ddd
//    Expansion Procedure
Toshihiro Shimizu 890ddd
//----------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Junction Area expansion procedure
Toshihiro Shimizu 890ddd
inline void JunctionArea::expandArea(unsigned int initial)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int a;
Toshihiro Shimizu 890ddd
	unsigned int curr, currLink;
Toshihiro Shimizu 890ddd
	unsigned int i, iLink, iNext;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_jointsAbsorbed.push_back(initial);
Toshihiro Shimizu 890ddd
	currJSGraph->node(initial).setAttribute(JointSequenceGraph::REACHED); //Nodes absorbed gets signed
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (a = 0; a < m_jointsAbsorbed.size(); ++a) {
Toshihiro Shimizu 890ddd
		//Extract a joint from vector
Toshihiro Shimizu 890ddd
		curr = m_jointsAbsorbed[a];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (currLink = 0; currLink < currJSGraph->getNode(curr).getLinksCount(); ++currLink) {
Toshihiro Shimizu 890ddd
			Sequence &s = *currJSGraph->node(curr).link(currLink);
Toshihiro Shimizu 890ddd
			if (s.m_graphHolder->getNode(s.m_head).getLink(s.m_headLink).getAccess()) {
Toshihiro Shimizu 890ddd
				//Expand into all nearby sequences, until a ROAD is found
Toshihiro Shimizu 890ddd
				i = s.m_head;
Toshihiro Shimizu 890ddd
				iLink = s.m_headLink;
Toshihiro Shimizu 890ddd
				for (; i != s.m_tail && !s.m_graphHolder->getNode(i).getLink(iLink)->hasAttribute(SkeletonArc::ROAD);
Toshihiro Shimizu 890ddd
					 s.next(i, iLink))
Toshihiro Shimizu 890ddd
					;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//If the sequence has been completely run, include next joint in the
Toshihiro Shimizu 890ddd
				//expansion procedure AND sign it as 'REACHED'
Toshihiro Shimizu 890ddd
				if (i == s.m_tail) {
Toshihiro Shimizu 890ddd
					iNext = currJSGraph->getNode(curr).getLink(currLink).getNext();
Toshihiro Shimizu 890ddd
					if (!currJSGraph->node(iNext).hasAttribute(JointSequenceGraph::REACHED)) {
Toshihiro Shimizu 890ddd
						currJSGraph->node(iNext).setAttribute(JointSequenceGraph::REACHED);
Toshihiro Shimizu 890ddd
						m_jointsAbsorbed.push_back(iNext);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
					//Negate access to this sequence
Toshihiro Shimizu 890ddd
					s.m_graphHolder->node(s.m_tail).link(s.m_tailLink).setAccess(0);
Toshihiro Shimizu 890ddd
					s.m_graphHolder->node(s.m_head).link(s.m_headLink).setAccess(0);
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					//Initialize and copy the entering sequence found
Toshihiro Shimizu 890ddd
					m_enteringSequences.push_back(EnteringSequence(s));
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_head = i;
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_headLink = iLink;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					//Initialize entering directions
Toshihiro Shimizu 890ddd
					iNext = s.m_graphHolder->getNode(i).getLink(iLink).getNext();
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_direction =
Toshihiro Shimizu 890ddd
						planeProjection(*s.m_graphHolder->getNode(i) - *s.m_graphHolder->getNode(iNext));
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_direction =
Toshihiro Shimizu 890ddd
						m_enteringSequences.back().m_direction * (1 / norm(m_enteringSequences.back().m_direction));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					//Initialize entering height / slope
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_height = s.m_graphHolder->getNode(i)->z;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					//Also store pointer to link toward the joint at the end of sequence
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_initialJoint = curr;
Toshihiro Shimizu 890ddd
					m_enteringSequences.back().m_outerLink = currLink;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------
Toshihiro Shimizu 890ddd
//    Area Shape Test
Toshihiro Shimizu 890ddd
//-----------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool JunctionArea::checkShape()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<enteringsequence>::iterator a, b;</enteringsequence>
Toshihiro Shimizu 890ddd
	unsigned int node, contour, first, last, n;
Toshihiro Shimizu 890ddd
	TPointD A, A1, B, B1, P, P1;
Toshihiro Shimizu 890ddd
	bool result = 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First, sign all outgoing arcs' m_leftGeneratingNode as end of
Toshihiro Shimizu 890ddd
	//control procedure
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		node = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getLeftGenerator();
Toshihiro Shimizu 890ddd
		contour = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getLeftContour();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		(*currContourFamily)[contour][node].setAttribute(ContourNode::JR_RESERVED);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, check shape
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(), b = m_enteringSequences.end() - 1;
Toshihiro Shimizu 890ddd
		 a != m_enteringSequences.end(); b = a, ++a) {
Toshihiro Shimizu 890ddd
		//Initialize contour check
Toshihiro Shimizu 890ddd
		first = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getRightGenerator();
Toshihiro Shimizu 890ddd
		//last= b->m_graphHolder->getNode(b->m_head).getLink(b->m_headLink)
Toshihiro Shimizu 890ddd
		//  ->getLeftGenerator();
Toshihiro Shimizu 890ddd
		contour = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getRightContour();
Toshihiro Shimizu 890ddd
		n = (*currContourFamily)[contour].size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Better this effective way to find the last
Toshihiro Shimizu 890ddd
		unsigned int numChecked = 0;
Toshihiro Shimizu 890ddd
		for (last = first; !(*currContourFamily)[contour][last].hasAttribute(ContourNode::JR_RESERVED) && numChecked < n; last = (last + 1) % n, ++numChecked)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Security check
Toshihiro Shimizu 890ddd
		if (numChecked == n)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		A = planeProjection((*currContourFamily)[contour][first].m_position);
Toshihiro Shimizu 890ddd
		A1 = planeProjection((*currContourFamily)[contour][(first + 1) % n].m_position);
Toshihiro Shimizu 890ddd
		B = planeProjection((*currContourFamily)[contour][last].m_position);
Toshihiro Shimizu 890ddd
		B1 = planeProjection((*currContourFamily)[contour][(last + 1) % n].m_position);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (node = first; !(*currContourFamily)[contour][node].hasAttribute(ContourNode::JR_RESERVED);
Toshihiro Shimizu 890ddd
			 node = (node + 1) % n) {
Toshihiro Shimizu 890ddd
			P = planeProjection((*currContourFamily)[contour][node].m_position);
Toshihiro Shimizu 890ddd
			P1 = planeProjection((*currContourFamily)[contour][(node + 1) % n].m_position);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//EXPLANATION:
Toshihiro Shimizu 890ddd
			//Segment P-P1  must be included in fat lines passing for A-A1 or B-B1
Toshihiro Shimizu 890ddd
			result &=
Toshihiro Shimizu 890ddd
				(fabs(cross(P - A, normalize(A1 - A))) < a->m_height * shapeDistMul &&
Toshihiro Shimizu 890ddd
				 fabs(cross(P1 - A, normalize(A1 - A))) < a->m_height * shapeDistMul)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				||
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				(fabs(cross(P - B, normalize(B1 - B))) < b->m_height * shapeDistMul &&
Toshihiro Shimizu 890ddd
				 fabs(cross(P1 - B, normalize(B1 - B))) < b->m_height * shapeDistMul);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, restore nodes attributes
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		node = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getLeftGenerator();
Toshihiro Shimizu 890ddd
		contour = a->m_graphHolder->getNode(a->m_head).getLink(a->m_headLink)->getLeftContour();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		(*currContourFamily)[contour][node].clearAttribute(ContourNode::JR_RESERVED);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------
Toshihiro Shimizu 890ddd
//    Solve new junction position problem
Toshihiro Shimizu 890ddd
//--------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool JunctionArea::solveJunctionPosition()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<enteringsequence>::iterator a;</enteringsequence>
Toshihiro Shimizu 890ddd
	double Sx2 = 0, Sy2 = 0, Sxy = 0;
Toshihiro Shimizu 890ddd
	TPointD P, v, b;
Toshihiro Shimizu 890ddd
	double h;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build preliminary sums for the linear system
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		h = a->m_height;
Toshihiro Shimizu 890ddd
		v = a->m_direction;
Toshihiro Shimizu 890ddd
		P = planeProjection(*a->m_graphHolder->getNode(a->m_head));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Height-weighted problem
Toshihiro Shimizu 890ddd
		Sx2 += sq(v.x) * h;
Toshihiro Shimizu 890ddd
		Sy2 += sq(v.y) * h;
Toshihiro Shimizu 890ddd
		Sxy += v.x * v.y * h;
Toshihiro Shimizu 890ddd
		b.x += h * (sq(v.y) * P.x - (v.x * v.y * P.y));
Toshihiro Shimizu 890ddd
		b.y += h * (sq(v.x) * P.y - (v.x * v.y * P.x));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First check problem determinant
Toshihiro Shimizu 890ddd
	double det = Sx2 * Sy2 - sq(Sxy);
Toshihiro Shimizu 890ddd
	if (fabs(det) < 0.1)
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now construct linear system
Toshihiro Shimizu 890ddd
	TAffine M(Sx2 / det, Sxy / det, 0, Sxy / det, Sy2 / det, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_newJointPosition = M * b;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, check if J is too far from the line extensions of the entering
Toshihiro Shimizu 890ddd
	//sequences
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		P = planeProjection(*a->m_graphHolder->getNode(a->m_head));
Toshihiro Shimizu 890ddd
		if (tdistance(m_newJointPosition, a->m_direction, P) > a->m_height * lineDistMul)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------
Toshihiro Shimizu 890ddd
//    Calculate optimal joint heights
Toshihiro Shimizu 890ddd
//---------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Globals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
const std::vector<enteringsequence> *currEnterings;</enteringsequence>
Toshihiro Shimizu 890ddd
const std::vector<unsigned int=""> *heightIndicesPtr;</unsigned>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::vector<double> *optHeights;</double>
Toshihiro Shimizu 890ddd
double optMeanError;
Toshihiro Shimizu 890ddd
double hMax;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool checkCircles(std::vector<double> &heights)</double>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
	double cos, sin, frac;
Toshihiro Shimizu 890ddd
	TPointD vi, vj;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Execute test on angle-consecutive EnteringSequences couples
Toshihiro Shimizu 890ddd
	for (j = 0, i = currEnterings->size() - 1; j < currEnterings->size(); i = j, ++j) {
Toshihiro Shimizu 890ddd
		vi = (*currEnterings)[i].m_direction;
Toshihiro Shimizu 890ddd
		vj = (*currEnterings)[j].m_direction;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		sin = cross(vi, vj);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (heights[i] == heights[j])
Toshihiro Shimizu 890ddd
			goto test_against_max_height;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		frac = heights[i] / heights[j];
Toshihiro Shimizu 890ddd
		if (sin < 0)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
		cos = vi * vj;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (cos < 0 && (frac < -cos || frac > (-1 / cos)))
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	test_against_max_height:
Toshihiro Shimizu 890ddd
		//Reusing cos
Toshihiro Shimizu 890ddd
		cos = (sin < 0.1) ? tmax(heights[i], heights[j]) : norm((vi * (heights[j] / sin)) + (vj * (heights[i] / sin)));
Toshihiro Shimizu 890ddd
		if (cos < hMax)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void tryConfiguration(const std::vector<unsigned int=""> &bounds)</unsigned>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<double> currHeights(currEnterings->size());</double>
Toshihiro Shimizu 890ddd
	double mean, currMeanError = 0;
Toshihiro Shimizu 890ddd
	unsigned int i, j, first, end;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0, first = 0; i <= bounds.size(); first = end, ++i) {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		end = i < bounds.size() ? end = bounds[i] + 1 : currEnterings->size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Calculate mean from first (included) to end (not included)
Toshihiro Shimizu 890ddd
		for (j = first, mean = 0; j < end; ++j)
Toshihiro Shimizu 890ddd
			mean += (*currEnterings)[(*heightIndicesPtr)[j]].m_height;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		mean /= end - first;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Check if the distance from extremities to mean is tolerable
Toshihiro Shimizu 890ddd
		if (tmax((*currEnterings)[(*heightIndicesPtr)[end - 1]].m_height - mean,
Toshihiro Shimizu 890ddd
				 mean - (*currEnterings)[(*heightIndicesPtr)[first]].m_height) > hDiffMul * mean)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Calculate squared error to mean
Toshihiro Shimizu 890ddd
		for (j = first; j < end; ++j)
Toshihiro Shimizu 890ddd
			currMeanError +=
Toshihiro Shimizu 890ddd
				sq((*currEnterings)[(*heightIndicesPtr)[j]].m_height - mean);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Set calculated currHeights
Toshihiro Shimizu 890ddd
		for (j = first; j < end; ++j)
Toshihiro Shimizu 890ddd
			currHeights[(*heightIndicesPtr)[j]] = mean;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Update current maximum height
Toshihiro Shimizu 890ddd
	hMax = mean; //Global
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If this configuration could be better than current, launch circle test
Toshihiro Shimizu 890ddd
	if (optHeights->empty() || currMeanError < optMeanError) {
Toshihiro Shimizu 890ddd
		if (checkCircles(currHeights)) {
Toshihiro Shimizu 890ddd
			(*optHeights) = currHeights;
Toshihiro Shimizu 890ddd
			optMeanError = currMeanError;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class hLess
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	std::vector<enteringsequence> &m_entSequences;</enteringsequence>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	hLess(std::vector<enteringsequence> &v) : m_entSequences(v) {}</enteringsequence>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline bool operator()(unsigned int a, unsigned int b)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_entSequences[a].m_height < m_entSequences[b].m_height;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: We build intervals on which height means are done.
Toshihiro Shimizu 890ddd
//Their right Interval Bounds are supposed INCLUDED.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Example: heights[]= {1, 2, 3, 4}; rightIntervalBounds[]={0, 2};
Toshihiro Shimizu 890ddd
//  =>  do height means on: {1}, {2,3}, {4}. (*)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//After means are calculated, a test on the obtained configuration is
Toshihiro Shimizu 890ddd
//performed. Among those configurations which pass the test, the one
Toshihiro Shimizu 890ddd
//with rightIntervalBounds.size()->min and, on same sizes,
Toshihiro Shimizu 890ddd
//currMeanError->min is the 'best' configuration possible.
Toshihiro Shimizu 890ddd
//If no height configuration pass the test, reconstruction fails.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//(*) NOTE: The right Interval Bounds will never include index n-1, which
Toshihiro Shimizu 890ddd
//interferes with push_backs.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool JunctionArea::makeHeights()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<unsigned int=""> heightOrderedIndices;</unsigned>
Toshihiro Shimizu 890ddd
	std::vector<unsigned int=""> rightIntervalBounds;</unsigned>
Toshihiro Shimizu 890ddd
	std::vector<double> optimalHeights;</double>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, n, m;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Sort entering sequences' indices for increasing height/thickness
Toshihiro Shimizu 890ddd
	heightOrderedIndices.resize(m_enteringSequences.size());
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_enteringSequences.size(); ++i)
Toshihiro Shimizu 890ddd
		heightOrderedIndices[i] = i;
Toshihiro Shimizu 890ddd
	sort(heightOrderedIndices.begin(), heightOrderedIndices.end(),
Toshihiro Shimizu 890ddd
		 hLess(m_enteringSequences));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Initialize globals/references
Toshihiro Shimizu 890ddd
	currEnterings = &m_enteringSequences;
Toshihiro Shimizu 890ddd
	heightIndicesPtr = &heightOrderedIndices;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	optMeanError = 0;
Toshihiro Shimizu 890ddd
	optHeights = &optimalHeights;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now build height-mean configurations and launch their tests
Toshihiro Shimizu 890ddd
	n = m_enteringSequences.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//The m=0 case is done first, apart
Toshihiro Shimizu 890ddd
	rightIntervalBounds.resize(0);
Toshihiro Shimizu 890ddd
	tryConfiguration(rightIntervalBounds);
Toshihiro Shimizu 890ddd
	for (m = 1; m < n && optimalHeights.empty(); ++m) {
Toshihiro Shimizu 890ddd
		//Initialize bounds
Toshihiro Shimizu 890ddd
		rightIntervalBounds.resize(1);
Toshihiro Shimizu 890ddd
		rightIntervalBounds[0] = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (!rightIntervalBounds.empty()) {
Toshihiro Shimizu 890ddd
			//Fill bounds if necessary
Toshihiro Shimizu 890ddd
			while (rightIntervalBounds.size() < m)
Toshihiro Shimizu 890ddd
				rightIntervalBounds.push_back(rightIntervalBounds.back() + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			tryConfiguration(rightIntervalBounds);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//'Advance' configuration: increment last index and pop those
Toshihiro Shimizu 890ddd
			//exceeding valid size. If bounds gets empty, done all configs
Toshihiro Shimizu 890ddd
			//with m+1 intervals.
Toshihiro Shimizu 890ddd
			while ((++rightIntervalBounds.back(),
Toshihiro Shimizu 890ddd
					rightIntervalBounds.back() < n - 1 - (m - rightIntervalBounds.size()) ? 0 : (rightIntervalBounds.pop_back(),
Toshihiro Shimizu 890ddd
																								 !rightIntervalBounds.empty())))
Toshihiro Shimizu 890ddd
				;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!optimalHeights.empty()) {
Toshihiro Shimizu 890ddd
		for (i = 0; i < n; ++i)
Toshihiro Shimizu 890ddd
			m_enteringSequences[i].m_height = optimalHeights[i];
Toshihiro Shimizu 890ddd
		return 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
//    Area Calculation Main
Toshihiro Shimizu 890ddd
//------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class EntSequenceLess
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	EntSequenceLess() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	inline bool operator()(const EnteringSequence &a, const EnteringSequence &b)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//m_direction is normalized, therefore:
Toshihiro Shimizu 890ddd
		return a.m_direction.y >= 0 ? b.m_direction.y >= 0 ? a.m_direction.x > b.m_direction.x : 1 : b.m_direction.y < 0 ? a.m_direction.x < b.m_direction.x : 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool JunctionArea::calculateReconstruction()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_enteringSequences.size() == 0)
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Apply preliminary tests for this Junction Area
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// a) Check if endpoints got absorbed by the expansion process
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_jointsAbsorbed.size(); ++i)
Toshihiro Shimizu 890ddd
		if (currJSGraph->getNode(m_jointsAbsorbed[i]).degree() == 1)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// b) Check if the contours shape resembles that of a crossing
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	sort(m_enteringSequences.begin(), m_enteringSequences.end(),
Toshihiro Shimizu 890ddd
		 EntSequenceLess());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!checkShape())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// c) Build the new junction Point plane position
Toshihiro Shimizu 890ddd
	if (!solveJunctionPosition())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// d) Build joint optimal heights (each for entering sequence...)
Toshihiro Shimizu 890ddd
	if (!makeHeights())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
//    Sequences Pull Back
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: We have to insure that connecting entering sequences to the
Toshihiro Shimizu 890ddd
//new junction point happens *smoothly*. In order to do this, wh withdraw
Toshihiro Shimizu 890ddd
//entering sequences along the enterin road, until the angle given by the
Toshihiro Shimizu 890ddd
//connecting line and the entering direction is small.
Toshihiro Shimizu 890ddd
//However, sequence pull back can be done only under some constraints:
Toshihiro Shimizu 890ddd
//  * we have to remain inside a road axis
Toshihiro Shimizu 890ddd
//  * ........................ a given fat line around the entering direction
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool JunctionArea::sequencesPullBack()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<enteringsequence>::iterator a;</enteringsequence>
Toshihiro Shimizu 890ddd
	double alongLinePosition, distanceFromLine;
Toshihiro Shimizu 890ddd
	unsigned int i, iLink, tail;
Toshihiro Shimizu 890ddd
	TPointD P;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		i = a->m_head;
Toshihiro Shimizu 890ddd
		iLink = a->m_headLink;
Toshihiro Shimizu 890ddd
		//NOTE: updated tails are stored this way, *DONT* look in a->m_tail
Toshihiro Shimizu 890ddd
		//because these typically store old infos
Toshihiro Shimizu 890ddd
		tail = currJSGraph->getNode(a->m_initialJoint).getLink(a->m_outerLink)->m_tail;
Toshihiro Shimizu 890ddd
		P = planeProjection(*a->m_graphHolder->getNode(a->m_head));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (i != tail) {
Toshihiro Shimizu 890ddd
			alongLinePosition = a->m_direction * (m_newJointPosition - P);
Toshihiro Shimizu 890ddd
			distanceFromLine = tdistance(m_newJointPosition, a->m_direction, P);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (alongLinePosition >= 0 && (distanceFromLine / alongLinePosition) <= 0.5)
Toshihiro Shimizu 890ddd
				goto found_pull_back;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//We then take the next arc and check it
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!a->m_graphHolder->getNode(i).getLink(iLink)->hasAttribute(SkeletonArc::ROAD))
Toshihiro Shimizu 890ddd
				return 0; //Pull back failed
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a->next(i, iLink);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			P = planeProjection(*a->m_graphHolder->getNode(i));
Toshihiro Shimizu 890ddd
			if (tdistance(P, a->m_direction, m_newJointPosition) >
Toshihiro Shimizu 890ddd
				tmax(pullBackMul * a->m_height, 1.0))
Toshihiro Shimizu 890ddd
				return 0; //Pull back failed
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Now checking opposite sequence extremity
Toshihiro Shimizu 890ddd
		if (alongLinePosition < 0 || (distanceFromLine / alongLinePosition) > 0.5)
Toshihiro Shimizu 890ddd
			return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	found_pull_back:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		a->m_head = i;
Toshihiro Shimizu 890ddd
		a->m_headLink = iLink;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------
Toshihiro Shimizu 890ddd
//    Substitute new junction configuration
Toshihiro Shimizu 890ddd
//----------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void JunctionArea::apply()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<enteringsequence>::iterator a;</enteringsequence>
Toshihiro Shimizu 890ddd
	unsigned int newJoint, newSkeletonNode;
Toshihiro Shimizu 890ddd
	unsigned int head, headLink, tail, tailLink;
Toshihiro Shimizu 890ddd
	unsigned int outerJoint, outerLink;
Toshihiro Shimizu 890ddd
	unsigned int i, next, nextLink;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First, check if Entering Sequences pullback is possible
Toshihiro Shimizu 890ddd
	if (!sequencesPullBack())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, we can substitute the old configuration
Toshihiro Shimizu 890ddd
	//First, sign as 'ELIMINATED' all absorbed joints
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_jointsAbsorbed.size(); ++i)
Toshihiro Shimizu 890ddd
		currJSGraph->node(m_jointsAbsorbed[i]).setAttribute(JointSequenceGraph::ELIMINATED);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	newJoint = currJSGraph->newNode();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (a = m_enteringSequences.begin(); a != m_enteringSequences.end(); ++a) {
Toshihiro Shimizu 890ddd
		//Initialize infos
Toshihiro Shimizu 890ddd
		newSkeletonNode = a->m_graphHolder
Toshihiro Shimizu 890ddd
							  ->newNode(T3DPointD(m_newJointPosition, a->m_height));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Retrieve sequence infos to substitute
Toshihiro Shimizu 890ddd
		//NOTE: We update *tail* infos in currJSGraph sequences after each "apply"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const JointSequenceGraph::Link &tempLink =
Toshihiro Shimizu 890ddd
			currJSGraph->getNode(a->m_initialJoint).getLink(a->m_outerLink);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		head = tempLink->m_head;
Toshihiro Shimizu 890ddd
		headLink = tempLink->m_headLink;
Toshihiro Shimizu 890ddd
		tail = tempLink->m_tail;
Toshihiro Shimizu 890ddd
		tailLink = tempLink->m_tailLink;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		outerJoint = tempLink.getNext();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Find outerLink - from outerJoint to a->m_initialJoint
Toshihiro Shimizu 890ddd
		for (i = 0; (currJSGraph->getNode(outerJoint).getLink(i)->m_tail != head) ||
Toshihiro Shimizu 890ddd
					(currJSGraph->getNode(outerJoint).getLink(i)->m_tailLink != headLink);
Toshihiro Shimizu 890ddd
			 ++i)
Toshihiro Shimizu 890ddd
			;
Toshihiro Shimizu 890ddd
		outerLink = i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Now, provide skeleton linkages
Toshihiro Shimizu 890ddd
		//NOTE: Discriminate between the following cases
Toshihiro Shimizu 890ddd
		// a) m_head->degree == 2
Toshihiro Shimizu 890ddd
		// b) m_head == m_tail
Toshihiro Shimizu 890ddd
		// c) m_head == original m_head - or, (m_head!=m_tail && m_head->deg>2)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (a->m_graphHolder->getNode(a->m_head).degree() == 2) {
Toshihiro Shimizu 890ddd
			a->m_graphHolder->newLink(newSkeletonNode, a->m_head);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a->m_graphHolder->node(a->m_head).link(!a->m_headLink).setNext(newSkeletonNode);
Toshihiro Shimizu 890ddd
			a->m_graphHolder->node(a->m_head).link(!a->m_headLink)->setAttribute(SkeletonArc::ROAD);
Toshihiro Shimizu 890ddd
			//Better clear road attribute or set it?
Toshihiro Shimizu 890ddd
		} else if (a->m_head == tail) {
Toshihiro Shimizu 890ddd
			a->m_graphHolder->newLink(newSkeletonNode, tail);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a->m_graphHolder->node(tail).link(tailLink).setNext(newSkeletonNode);
Toshihiro Shimizu 890ddd
			a->m_graphHolder->node(tail).link(tailLink)->setAttribute(SkeletonArc::ROAD);
Toshihiro Shimizu 890ddd
		} else //(a->m_head == head)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			//In this case, better introduce further a new substitute of head
Toshihiro Shimizu 890ddd
			unsigned int newHead = a->m_graphHolder
Toshihiro Shimizu 890ddd
									   ->newNode(T3DPointD(*a->m_graphHolder->getNode(a->m_head)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a->m_graphHolder->newLink(newSkeletonNode, newHead);
Toshihiro Shimizu 890ddd
			a->m_graphHolder->newLink(newHead, newSkeletonNode);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Link newHead on the other side
Toshihiro Shimizu 890ddd
			next = a->m_graphHolder
Toshihiro Shimizu 890ddd
					   ->getNode(head)
Toshihiro Shimizu 890ddd
					   .getLink(headLink)
Toshihiro Shimizu 890ddd
					   .getNext();
Toshihiro Shimizu 890ddd
			nextLink = a->m_graphHolder->getNode(next).linkOfNode(head);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			a->m_graphHolder->newLink(newHead, next);
Toshihiro Shimizu 890ddd
			a->m_graphHolder->node(next).link(nextLink).setNext(newHead);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Finally, update joint linkings and sequence tails.
Toshihiro Shimizu 890ddd
		Sequence newSequence;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newSequence.m_graphHolder = a->m_graphHolder;
Toshihiro Shimizu 890ddd
		newSequence.m_head = newSkeletonNode;
Toshihiro Shimizu 890ddd
		newSequence.m_headLink = 0;
Toshihiro Shimizu 890ddd
		newSequence.m_tail = tail;
Toshihiro Shimizu 890ddd
		newSequence.m_tailLink = tailLink;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		currJSGraph->node(outerJoint).link(outerLink).setNext(newJoint);
Toshihiro Shimizu 890ddd
		currJSGraph->node(outerJoint).link(outerLink)->m_tail = newSkeletonNode;
Toshihiro Shimizu 890ddd
		currJSGraph->node(outerJoint).link(outerLink)->m_tailLink = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		currJSGraph->newLink(newJoint, outerJoint, newSequence);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------
Toshihiro Shimizu 890ddd
//    Junction Recovery Main
Toshihiro Shimizu 890ddd
//-------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//EXPLANATION: Junction Recovery attempts reconstruction of badly-behaved
Toshihiro Shimizu 890ddd
//crossings in the raw skeleton of the image.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//void inline junctionRecovery(Contours* polygons)
Toshihiro Shimizu 890ddd
void junctionRecovery(Contours *polygons, VectorizerCoreGlobals &g)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	globals = &g;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
	std::vector<junctionarea> junctionAreasList;</junctionarea>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For all joints not processed by the Recoverer, launch a new junction
Toshihiro Shimizu 890ddd
	//area reconstruction
Toshihiro Shimizu 890ddd
	for (i = 0; i < globals->organizedGraphs.size(); ++i) {
Toshihiro Shimizu 890ddd
		currJSGraph = &globals->organizedGraphs[i];
Toshihiro Shimizu 890ddd
		currContourFamily = &(*polygons)[contourFamilyOfOrganized[i]];
Toshihiro Shimizu 890ddd
		junctionAreasList.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//First, graph roads are found and signed on the skeleton
Toshihiro Shimizu 890ddd
		findRoads(*currJSGraph);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Then, junction areas are identified and reconstructions are calculated
Toshihiro Shimizu 890ddd
		for (j = 0; j < currJSGraph->getNodesCount(); ++j)
Toshihiro Shimizu 890ddd
			if (!currJSGraph->getNode(j).hasAttribute(JointSequenceGraph::REACHED)) {
Toshihiro Shimizu 890ddd
				junctionAreasList.push_back(JunctionArea());
Toshihiro Shimizu 890ddd
				junctionAreasList.back().expandArea(j);
Toshihiro Shimizu 890ddd
				if (!junctionAreasList.back().calculateReconstruction())
Toshihiro Shimizu 890ddd
					junctionAreasList.pop_back();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Finally, reconstructions are substituted inside the skeleton
Toshihiro Shimizu 890ddd
		for (j = 0; j < junctionAreasList.size(); ++j)
Toshihiro Shimizu 890ddd
			junctionAreasList[j].apply();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}