//////////////////////////////////////////////////////////////////////////////
//const double xmax = (m_pWnd->xmax() - m_pWnd->xmin()) + xmin;
//const double ymax = (m_pWnd->ymax() - m_pWnd->ymin()) + ymin;
//////////////////////////////////////////////////////////////////////////////
	for (rowIt = m_dags.begin(); rowIt != m_dags.end(); )
	{
		for (/*rowIt = m_dags.begin(),*/ i = 0; rowIt != m_dags.end(); rowIt++, i++)
		{
			for (colIt = rowIt->begin(), j = 0; colIt != rowIt->end(); colIt++, j++)
			{
				dagMat[i][j] = (const DAG*) *colIt;
			}
		}
	}
//////////////////////////////////////////////////////////////////////////////
/*const SmartArray<T>& row = this->operator[](nRow);
		int size = row.Size();
		T sum = 0;

		for (int i = 0; i < size; i++)
			sum += row[i];

		return sum;*/
//////////////////////////////////////////////////////////////////////////////
/*!
	@brief Creates a window to display the information stored in two DAG side by side.

	In order to position the window on the top right, set xpos and ypos to -1.

	Call SetMatchMap() to assign and display node correspondeces between the two DAGs.

	@return false if the 'Esc'-key-press is the last event and true otherwise.
*/
bool DAGView::Create(const DAG* pSG1, const DAG* pSG2, int xpos, int ypos)
{
	ASSERT(pSG1 && pSG2);

	// Set min and max window coordinates
	double xmin = 0;
	double xmax = SW_LEFT_MARGIN + SW_CENTER_MARGIN + SW_RIGHT_MARGIN;
	double ymin = 0;
	double ymax = SW_BOTTOM_MARGIN + SW_TOP_MARGIN;

	xmax += pSG1->Width() + pSG2->Width();
	ymax += (pSG1->Height() > pSG2->Height()) ? pSG1->Height():pSG2->Height();

	// Compute scaling factor
	double width = xmax;
	double height = (ymax - ymin) * width / (xmax - xmin);
	
	double delta_x, delta_y, reflex_y;
	
	// Set SG position info
	delta_x = pSG1->xmin() - SW_LEFT_MARGIN;
	delta_y = pSG1->ymin() - SW_BOTTOM_MARGIN;
	reflex_y = pSG1->ymax() + pSG1->ymin();

	m_pImageInfo1 = new ImageInfo(pSG1, delta_x, delta_y, reflex_y);

	delta_x = pSG2->xmin() - (SW_LEFT_MARGIN + pSG1->Width() + SW_CENTER_MARGIN);
	delta_y = pSG2->ymin() - SW_BOTTOM_MARGIN;
	reflex_y = pSG2->ymax() + pSG2->ymin();
	
	m_pImageInfo2 = new ImageInfo(pSG2, delta_x, delta_y, reflex_y);

	// Create a window of the desired size
	m_pWnd = new Wnd((int) width, (int) height, MakeWinTitle(), this);

	m_pWnd->init(xmin, xmax, ymin);

	//m_pWnd->set_show_coordinates(m_bShowCoords);

	return Display(xpos, ypos);
}

//////////////////////////////////////////////////////////////////////////////
class SGPiecewiseSimilarityMeasurer: public SGSimilarityMeasurer
{	
	virtual double ComputeNodeDistance(leda::node v1, leda::node v2,
		const ParamIndices& parInds, double* pSimilarity = NULL) const;

	virtual double ComputeNodeSimilarity(leda::node v1, leda::node v2,
		const ParamIndices& parInds) const
	{
		return 1 - ComputeNodeDistance(v1, v2, ParamIndices(0));
	}

	virtual double ComputeNodeSimilarity(leda::node v1, leda::node v2,
		NodeMatchInfoPtr ptrMatchInfo) const
	{
		return 1 - ComputeNodeDistance(v1, v2, ParamIndices(0));
	}

	virtual double ComputeEdgeSimilarity(leda::edge e1, leda::edge e2, 
		const ParamIndices& parInds) const
	{
		return 1;
	}
};

/*!
	@brief 
*/
double BGSimilarityMeasurer::ComputeNodeDistance(leda::node v1, leda::node v2, 
												 const ParamIndices& parInds, 
												 double* pSimilarity) const
{
	if (!DAGMatcher::GetMatchParams().nCompareNodes)
	{
		*pSimilarity = 1;
		return 0;
	}

	const BGNode* pNode1 = m_pG1->GetBGNode(v1);
	const BGNode* pNode2 = m_pG2->GetBGNode(v2);
	double areaDiff;

	if (pNode1->Type() == ROOT || 
		pNode2->Type() == ROOT)
	{
		if (pNode1->Type() != ROOT)
		{
			areaDiff = XORIntegral::FunctionArea(pNode1->GetRadiusFunction());
			
			if (pSimilarity)
				*pSimilarity = 0;
		}
		else if (pNode2->Type() != ROOT)
		{
			areaDiff = XORIntegral::FunctionArea(pNode2->GetRadiusFunction());

			if (pSimilarity)
				*pSimilarity = 0;
		}
		else
		{
			areaDiff = 0;
			
			if (pSimilarity)
				*pSimilarity = 1;
		}
	}
	else if (bCornerBone1 != bCornerBone2)
	{
		areaDiff = XORIntegral::FunctionArea(pNode1->GetRadiusFunction()) +
				XORIntegral::FunctionArea(pNode2->GetRadiusFunction());

		if (pSimilarity)
			*pSimilarity = 0;
	}
	else
	{
		const NodeParams params = GetNodeParams(parInds);

		XORIntegral xi(pNode1->GetRadiusFunction(params.bFlipPosition), 
			pNode2->GetRadiusFunction());

		areaDiff = xi.XORArea();

		*pSimilarity = xi.FunctionSimilarity();

		if (params.bFlipPosition)
		{
			XORIntegral xi2(pNode1->GetRadiusFunction(), 
				pNode2->GetRadiusFunction(true));

			double sim2 = xi2.FunctionSimilarity();

			if (*pSimilarity < sim2)
			{
				*pSimilarity = sim2;
				areaDiff = xi2.XORArea();
			}
		}

		// Correct rounding errors
		if (*pSimilarity < 0 && *pSimilarity > -0.00001)
			*pSimilarity = 0;
		else if (*pSimilarity > 1 && *pSimilarity < 1.00001)
			*pSimilarity = 1;

		ASSERT_UNIT_INTERVAL(*pSimilarity);
	}

	return areaDiff;
}
//////////////////////////////////////////////////////////////////////////////
	int maxParam;

	if (m_pG1->GetNodeLevel(v1) == 1 || m_pG2->GetNodeLevel(v2) == 1)
		maxParam = 4;
	else
		maxParam = 2;

	double sim, bestSim = 0;

	for (int i = 0; i < 4; i++)
	{
		sim = ComputeNodeSimilarity(v1, v2, ptrMatchInfo, i);

		if (sim > bestSim)
		{
			bestSim = sim;
			ptrMatchInfo->SetParameterIndex(i);
		}
	}

	return bestSim;
//////////////////////////////////////////////////////////////////////////////
// Save the node similarity so that we don't have to recompute it later
	if (!ptrMatchInfo->HasNodeSimilarity())
	{
		ASSERT(outParamIdx >= 0);

		ParamIndices parInds(1, outParamIdx);

		ptrMatchInfo->SetNodeSimilarity(
			BGSimilarityMeasurer::ComputeNodeSimilarity(v1, v2, parInds));
	}
///////////////////////////////////////////////////////////////////////////////
 == "=>" || buf == "<=>" ||
			buf == "^>" || buf == "<^>" ||
			buf == "$>" || buf == "<$>"
///////////////////////////////////////////////////////////////////////////////
bool CmdLineParser::Parse(int argc, char** argv)
{
	if (argc == 3 && !strcmp(argv[1], "-file"))
	{
		CmdLineParams paramList;

		std::ifstream is(argv[2]);
		
		// Read the first list of arguments found in the file
		if (is) 
		{
			std::string curPat, nextPat, cmdLine;

			// Find the first pattern
			curPat = ReadPatternDelimitedSection(is, cmdLine);
			
			while (!curPat.empty())
			{
				nextPat = ReadPatternDelimitedSection(is, cmdLine);

				if (curPat == "=>")
				{
					paramList.push_back(cmdLine);
				}
				else if (curPat == "^>")
				{
				}
				else if (curPat == "$>")
				{
				}
				else
				{
					// ignore comments
				}

				curPat = nextPat;
			}

			do {
			} while (cmdLine.empty());

			std::string buf;
			bool readingArguments = false;

			// '=>' signals the beginning of arguments
			// '<=>' signals the beginning of a commented out list of arguments, which is ignored.
			while (is >> buf)
			{
				if (buf == "=>")
				{
					readingArguments = true; // start reading arguments

					// Start new parameter set by adding an empty string
					paramList.push_back(std::string()); 
				}
				else if (readingArguments && buf == "<=>")
				{
					readingArguments = false; // stop reading arguments
				}
				else if (readingArguments)
				{
					m_tokensFromFile.push_back(buf);

					paramList.back() += buf + " ";
				}
			}

			is.close();
		}
		else 
		{
			std::cerr << "Error: Cannot open command-line argument file '" 
				<< argv[2] << "'" << std::endl;

			return false;
		}

		if (paramList.size() > 0)
		{
			CmdLineParams::iterator it;

			for (it = paramList.begin(); it != paramList.end(); it++)
			{
				if (!CreateProcessAndWait(argv[0], it->c_str()))
				{
					std::cerr << "Error: Cannot create new process '" <<
						argv[0] <<"' with command-line arguments: " << *it 
						<< std::endl;

					TCHAR szDirectory[MAX_PATH] = "";

					GetCurrentDirectory(sizeof(szDirectory) - 1, szDirectory);

					std::cerr << "\nCurrent directory is: " << szDirectory << std::endl;

					return false;
				}

			}

			// Return false to signal that there are no params to process
			return false;
		}
		else
		{
			char* argv0 = argv[0];

			argc = m_tokensFromFile.size() + 1;
			argv = new char*[argc];
			argv[0] = argv0;

			for (int i = 1; i < argc; i++)
			{
				argv[i] = (char*) m_tokensFromFile[i - 1].c_str();
			}
		}
	}

	/*std::cerr << "\n\nInput parameters: ";

	for (int i = 1; i < argc; i++)
		std::cerr << argv[i] << " "; 
	
	std::cerr << std::endl;*/
	
	return ParseArguments(argc, argv);
}
///////////////////////////////////////////////////////////////////////////////
// Add the app name as the first param surrounded by quotes
					std::string appName("\"");
					appName += argv[0];
					appName += "\" "; // leave space at the end
///////////////////////////////////////////////////////////////////////////////
		for (int i = 1; i < argc; i++)
		{
			std::cerr << argv[i] << " " << std::flush;
		}
		return true;
///////////////////////////////////////////////////////////////////////////////
	/*if (posDiff == 0)
		return 1;
	else if (posDiff == 1)
		return 0;
	else
	{
		double n = 1 - log(pow(posDiff, 3) + 1);

		return n / log(2.0);
	}*/

///////////////////////////////////////////////////////////////////////////////
//double NodeAttributeSimilarity(leda::node v1, leda::node v2) const;

double BGCSM::NodeAttributeSimilarity(leda::node v1, leda::node v2) const
{
	// Make sure that the dummy root only compares well with another root
	if (indeg(v1) == 0 || indeg(v2) == 0)
		return (indeg(v1) == indeg(v2)) ? 1 : 0;

	DBG_M_LOG("Comparing nodes " << m_pG1->GetNodeDFSLbl(v1) 
		<< " and " << m_pG2->GetNodeDFSLbl(v2))

	const BGNode* pNode1 = m_pG1->GetBGNode(v1);
	const BGNode* pNode2 = m_pG2->GetBGNode(v2);

	XORIntegral xi(pNode1->GetRadiusFunction(), pNode2->GetRadiusFunction());

	double a1 = xi.FunctionArea(0);
	double a2 = xi.FunctionArea(1);

	double xorArea = xi.XORArea();

	double normalizedXORArea = xorArea / (a1 + a2);

	ASSERT(normalizedXORArea >= 0 && normalizedXORArea <= 1);

	//DBG_PRINT1(normalizedXORArea)
	
	return 1 - normalizedXORArea;
}
///////////////////////////////////////////////////////////////////////////////

static double TotalSaliency(const BoneGraph* pBG, leda::node v);

/*static*/ 
double BGCSM::TotalSaliency(const BoneGraph* pBG, leda::node v)
{
	leda::edge e;
	double totalSaliency = 0;

	forall_out_edges(e, v)
	{
		totalSaliency += pBG->GetBGEdge(e)->Saliency();
	}

	return totalSaliency;
}
///////////////////////////////////////////////////////////////////////////////
	std::list<std::string> classes;
	classes.push_back(className0);
	
	os << endl << "List of exemplars: " << endl;

	std::list<std::string>::iterator itClass;

	for (itClass = classes.begin(); itClass != classes.end(); itClass++)
	{
		os << *itClass << "\n";
	}
///////////////////////////////////////////////////////////////////////////////
// Check if the query and teh model belong to the same class
			if (strcmp(queryClass, modelClass) == 0)
			{
				// If it's also the same exemplare, exclude it
				if (pQueryDag->GetObjName() == pModelDag->GetObjName())
				{
					m_dbDagPresence[i][j] = false;
				}
				else if (experimentId == 1)
				{
					if (!combs.HasElement(queryIdx, param, modelIdx))
						m_dbDagPresence[i][j] = false;
				}
			}
///////////////////////////////////////////////////////////////////////////////
const unsigned int N = size();
		unsigned int i, j;

		m_dbDagPresence.resize(N);

		// Make sure that each row is of the righ size
		// and the initialize it to true (resize init only works
		// if a resize is neede, so init must be done explicitly).
		for (i = 0; i < N; i++)
		{
			m_dbDagPresence[i].resize(N);

			for (j = 0; j < N; j++)
				m_dbDagPresence[i][j] = true;
		}
///////////////////////////////////////////////////////////////////////////////
/*for (j = 0; j < combs.size(); j++)
		{
			std::cout << "\nNew set:" << std::endl;

			IntListVector& v = combs[j];

			for (i = 0; i < v.size(); i++)
			{
				std::cout << std::endl;

				for (IntList::iterator it = v[i].begin(); it != v[i].end(); it++)
				{
					std::cout << *it << ", ";
				}
			}
		}*/
///////////////////////////////////////////////////////////////////////////////
if (m_dbDagPresence[i][j] == false)
				{
					std::cout << "Excluding " << i << ", " << j << std::endl;
				}
///////////////////////////////////////////////////////////////////////////////
IntListVector v;
		IntList set;

		set.push_back(1);
		set.push_back(2);
		set.push_back(3);
		set.push_back(4);
		set.push_back(5);

		NChooseK(v, IntList(), 3, set.begin(), set.end());

		for (i = 0; i < v.size(); i++)
		{
			std::cout << std::endl;

			for (IntList::iterator it = v[i].begin(); it != v[i].end(); it++)
			{
				std::cout << *it << ", ";
			}
		}

		/*const int n = 5;
		int stepNum = 0;

		for (i = 0; i < n - 2; i++)
			for (j = i + 1; j < n - 1; j++)
				for (k = j + 1; k < n; k++, stepNum++);

		exemplars[i] = true;
		exemplars[j] = true;
		exemplars[k] = true;*/
///////////////////////////////////////////////////////////////////////////////
void NChooseK(IntListVector& v, const IntList& prefix, int k, 
			  IntList::iterator first, IntList::iterator last)
{
	if (k == 0)
		v.push_back(prefix);
	else
	{
		for (IntList::iterator it = first; it != last; )
		{
			IntList newPrefix = prefix;

			newPrefix.push_back(*it);

			NChooseK(v, newPrefix, k - 1, ++it, last);
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
for (i = 0; i < n - 2; i++)
		{
			for (j = i + 1; j < n - 1; j++)
			{
				for (k = j + 1; k < n; k++, stepNum++)
				{
					std::cout << "\n [" << stepNum << "]: " 
						<< i << ", " << j << ", " << k << std::flush;
				}
			}
		}
///////////////////////////////////////////////////////////////////////////////
bool ShapeMatcher::DoExperiment()
{
	/*ShowStatus("Loading all DAGs to memory...");

	const int numDags = m_dagDB.GetDAGCount();
	std::vector<DAGPtr> dags(numDags);
	
	for (int i = 0; i < numDags; i++)
		dags[i] = m_dagDB.ReadDAG(i, true);*/

	return false;
}
///////////////////////////////////////////////////////////////////////////////
/*static*/
bool BGSimilarityMeasurer::IsCornerBone(const BoneGraph* pBG, leda::node v)
{
	if (outdeg(v) > 0 || indeg(v) != 1 || pBG->GetNodeLevel(v) < 2)
		return false;

	leda::edge e = pBG->first_in_edge(v);

	if (!pBG->GetBGEdge(e)->IsEmpty())
		return false;

	const BGNode* pNode = pBG->GetBGNode(v);

	if (pNode->GetRadiusFunction().Size() != 1)
		return false;

	if (pNode->GetRadiusFunction().GetHead().m >= 0)
		return false;

	if (pNode->Length() >= 2 * pNode->FirstShockPoint().radius)
		return false;

	return true;
}
///////////////////////////////////////////////////////////////////////////////
void BoneGraph::ComputeDerivedValues()
{
	DAG::ComputeDerivedValues();

	leda::node v;
	//leda::edge e;

	// Find corner bones
	forall_nodes(v, *this)
	{
		if (outdeg(v) == 0 && indeg(v) == 1 && GetNodeLevel(v) >= 2)
		{
			const BGNode* pParent = GetBGNode(source(first_in_edge(v)));
			//e = first_in_edge(v);

			// It should NOT have ligature points
			if (GetBGEdge(e)->IsEmpty())
			{
				BGNode* pNode = UnsafeGetBGNode(v);

				// Must have a single decreasing radius segment
				if (pNode->GetRadiusFunction().Size() == 1 && 
					pNode->GetRadiusFunction().GetHead().m < 0)
				{
					// Cannot be too long
					if (pNode->Length() < 2 * pNode->FirstShockPoint().radius)
					{
						pNode->SetType(BGElement::CORNER_BONE);
					}
				}
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
	BGElement::ElementType edgeType; 

	if (m_genSkelGraph.GetNodeType(t) == GSG_JUNCTION)
		edgeType = BGElement::JUNCTION;
	else
		edgeType = BGElement::LIGAMENT;
///////////////////////////////////////////////////////////////////////////////
double sqDist, minSqDist = m_shocks.GetHead().pt.SqDist(pt);
		int i = 0;

		do {
			sqDist = m_shocks[i++].pt.SqDist(pt);
		} while (i < m_shocks.Size());

		for (int i = 1; i < m_shocks.Size(); i++)
		{
			sqDist = m_shocks[i].pt.SqDist(pt);

			if (sqDist < minSqDist)
				minSqDist = sqDist;
		}

		return minSqDist;
///////////////////////////////////////////////////////////////////////////////
{
		double w, a, b, areaDiff, sim, totalSimilarity = 0;
		double m0, m1, dm, area, areaSum, slopeSim, sigma;

		const double L = MAX(m_pts0.back().x, m_pts1.back().x) 
			- MIN(m_pts0.front().x, m_pts1.front().x);

		ASSERT(L > 0);

		const_iterator itB = begin();
		const_iterator itA = itB++;

		for (; itB != end(); itA++, itB++)
		{
			w = itB->x - itA->x;
			a = itA->Dy(*itB); // get hight wrt next side
			b = itB->Dy(*itA); // get hight wrt previous side

			ASSERT(w >= 0 && a >= 0 && b >= 0);

			// Compute the area of the DIFF trapezoid
			areaDiff = w * (a + b) / 2;

			if (HasFunctionOverlap(*itA, *itB))
			{
				// Sum the areas of each function's trapezoid
				areaSum = (w / 2) * (itA->y0 + itB->y0 + itA->y1 + itB->y1);

				m0 = (itB->y0 - itA->y0) / w;
				m1 = (itB->y1 - itA->y1) / w;

				dm = fabs(m0 - m1);

				if ((m0 >=0 && m1 >= 0) || (m0 <= 0 && m1 <= 0))
				{
					sigma = 0.5;
					slopeSim = exp(-(dm * dm) / sigma);
				}
				else
				{
					slopeSim = 0;
				}

				area = slopeSim * areaDiff + (1 - slopeSim) * areaSum;

				sim = 1 - area / areaSum;

				totalSimilarity += sim * w / L;
			}
		}

		return totalSimilarity;
	}

///////////////////////////////////////////////////////////////////////////////
	unsigned int m_curRoot[2];
	
double DAGMatcherAdaptive::AvgNodeLevel(const NodeAssignmentPtr& ptrNA) const
{
	return (ptrNA->Graph(0)->GetNodeLevel(ptrNA->Node(0)) + 
		ptrNA->Graph(1)->GetNodeLevel(ptrNA->Node(1))) / 2.0;
}

///////////////////////////////////////////////////////////////////////////////
if (edgeSim > 0)
			{
				nodeParInds = edgeParInds;
				nodeParInds[0] = 0;

				ptrChildNodeAss = new NodeAssignment(v0, v1, nodeParInds, e0, e1);

				ComputeRootedTreeDistance(ptrChildNodeAss);
				
				maxCost = ptrChildNodeAss->Graph(0)->GetSubtreeCost(v0) + 
					ptrChildNodeAss->Graph(1)->GetSubtreeCost(v1);

				// Convex sum of match and missmatch distances
				assDist = edgeSim * ptrChildNodeAss->Distance() + 
					(1 - edgeSim) * maxCost;

				ptrChildNodeAss->SetWeightedDistance(assDist);

				//ptrChildNodeAss->SetInEdgeSimilarity(edgeSim);
				ptrChildNodeAss->SetSimilarity(ptrChildNodeAss->Similarity() * edgeSim);

				g.AddEdge(it0, it1, ptrChildNodeAss);

				if (assDist > maxAssDist)
					maxAssDist = assDist;
			}
///////////////////////////////////////////////////////////////////////////////
	inline double GetInvertedCost(leda::node v, int dagId) const;
	
double DAGMatcherAdaptive::GetInvertedCost(leda::node v, int dagId) const
{
	forall( shared nodes)
	{
		if (pDag->IsAncestor(v, s))
		{
			cost += complement of shared node;
		}
	}

	ASSERT(dagId == 0 || dagId == 1);

	const unsigned int numRoots = m_roots[dagId].size();
	
	if (numRoots == 1)
	{
		return 0;
	}
	else
	{
		const DAG* pDag = (dagId == 0) ? m_pDag1 : m_pDag2;
		double cost = 0;
		leda::node r;

		for (unsigned int i = 0; i < numRoots; i++)
		{
			r = m_roots[dagId][i];

			if (i != m_curRoot[dagId] && pDag->IsAncestor(r, v))
			{
				cost += pDag->GetSubtreeCost(r) - pDag->GetSubtreeCost(v);
			}
		}

		return cost;
	}
}
///////////////////////////////////////////////////////////////////////////////

const char* szPar0 = szEdgeParam0[m_matchMap[v].params[0]];

if (skip == 0 && invert == 0)
						sprintf(szSimVal, "%s", szPar0);
					else
						sprintf(szSimVal, "%s %s", szPar0, (skip == 1) ? "*" : "**");
///////////////////////////////////////////////////////////////////////////////
//edgeParInds[1] = ep0.param;
			//edgeParInds[2] = ep1.param;

			//int dfsIdx0 = ptrNodeAss->Graph(0)->GetNodeDFSIndex(v0);
			//int dfsIdx1 = ptrNodeAss->Graph(1)->GetNodeDFSIndex(v1);
///////////////////////////////////////////////////////////////////////////////
int dfsIdx0 = Graph(0)->GetNodeDFSIndex(Node(0));
		int dfsIdx1 = Graph(1)->GetNodeDFSIndex(Node(1));

		int dfsIdx01 = (nodeMap[Node(0)].node == nil) ? 
			-1 : Graph(1)->GetNodeDFSIndex(nodeMap[Node(0)].node);

		ASSERT(Distance() >= 0);

		ASSERT(nodeMap[Node(0)].node == nil || indeg(Node(0)) == 2 
			|| indeg(nodeMap[Node(0)].node) == 2);
///////////////////////////////////////////////////////////////////////////////
// Free up all the memory use to store node assignments before leaving
	m_subtreeAssigns.Clear();

	ASSERT(minDist >= 0);

	//return exp(-minDist / 1000.0);

	return GetGraphSimilarity();

	//DBG_PRINT1(AvgNodeLevel(m_ptrRootAssignment))
	
	//DBG_PRINT1(m_ptrRootAssignment->Graph(0)->GetNodeDFSLbl(m_ptrRootAssignment->Node(0)))
	//DBG_PRINT1(m_ptrRootAssignment->Graph(1)->GetNodeDFSLbl(m_ptrRootAssignment->Node(1)))

	/*v0 = m_ptrRootAssignment->Node(0);
	v1 = m_ptrRootAssignment->Node(1);

	ptrNodeAss = new NodeAssignment(v0, v1, parIdx);
	dist = GraphDistance(ptrNodeAss);*/

	double cost0 = g0.GetDAGCost();
	double cost1 = g1.GetDAGCost();
	double normDist = minDist / (cost0 + cost1);

	//DBG_PRINT1(normDist)

	DBG_M_LOG("\nMatching " << g0.GetDAGLbl() << " against " << g1.GetDAGLbl() << std::endl)
	DBG_M_LOG_ONLY(m_ptrRootAssignment->Print(g_dagMatchingLog))
	DBG_M_LOG("\nGraph costs: g0 = " << cost0 << ", g1 = " << cost1 << 
		", sum = " << cost0 + cost1)
	DBG_M_LOG("\nMinimum distance found is: absolute = " << minDist 
		<< ", normalized = " << normDist)

	return (normDist < 1) ? (1 - normDist) : 0;
///////////////////////////////////////////////////////////////////////////////
NodeAssignmentPtr DAGMatcherTopological::GetNodeAssignment(
	leda::node v0, leda::node v1, const ParamIndices& parInds)
{
	/*int idx0 = m_pDag1->GetNodeDFSIndex(v0); 
	int idx1 = m_pDag2->GetNodeDFSIndex(v1);

	ASSERT(parInds[0] == 0);

	NodeAssignmentPtr& ptr = m_subtreeAssigns[idx0][idx1];
	
	if (ptr.IsNull())
	{
		ptr = new NodeAssignment(v0, v1, parInds);
	}

	return ptr;*/

	return NodeAssignmentPtr(new NodeAssignment(v0, v1, parInds));
}
///////////////////////////////////////////////////////////////////////////////
inline double AvgNodeLevel(const NodeAssignmentPtr& ptrNA)
{
	return (ptrNA->Graph(0)->GetNodeLevel(ptrNA->Node(0)) + 
		ptrNA->Graph(1)->GetNodeLevel(ptrNA->Node(1))) / 2.0;
}

const BGNode* GetBGNode(leda::node v, const DAG& g)
{
	try {
		const BoneGraph& bg = dynamic_cast<const BoneGraph&>(g);

		return bg.GetBGNode(v);
	}
    catch(std::bad_cast) {
        ShowError("Can't cast to BoneGraph\n");
		return NULL;
    }
}

double TotalLength(const DAG& g)
{
	leda::node v;
	double totLen = 0;

	forall_nodes(v, g)
	{
		totLen += GetBGNode(v, g)->Length();
	}

	return totLen;
}

double MaxLength(const DAG& g)
{
	leda::node v;
	double len, maxLen = 0;

	forall_nodes(v, g)
	{
		len = GetBGNode(v, g)->Length();

		if (len > maxLen)
			maxLen = len;
	}

	return maxLen;
}

///////////////////////////////////////////////////////////////////////////////
struct NodeAndParam
{
	leda::node node;
	int param;

	EdgeAndParam(leda::node v = nil, int param p = 0)
	{
		node = v;
		param = p;
	}
};
///////////////////////////////////////////////////////////////////////////////
int skip0, skip1, merge0, merge1;

	for (skip0 = 0; skip0 < 2; skip0++)
	{
		if (skip0 && !CanSkipEdge(v0, 0, &skipEdge0))
				continue;

		for (skip1 = 0; skip1 < 2; skip1++)
		{
			if (skip1 && !CanSkipEdge(v1, 1, &skipEdge1))
				continue;

			for (merge0 = 0; merge0 < 2; merge0++)
			{
				if (merge0 && !CanMergeNode(v0))
					continue;

				skipNodes[0].push_back(EdgeAndParam(skipEdge0, merge0));

				for (merge1 = 0; merge1 < 2; merge1++)
				{
					if (merge1 && !CanMergeNode(v1))
						continue;

					ASSERT(!skipNodes[0].empty() || !skipNodes[1].empty());

					skipNodes[1].push_back(EdgeAndParam(skipEdge1, merge1));

					ptrAuxNodeAss = GetNodeAssignment(v0, v1, nodeParInds);

					childDist = ComputeRootedTreeDistance(ptrAuxNodeAss, skipNodes);
				}
			}
		}
	}
///////////////////////////////////////////////////////////////////////////////
void BGC::PartitionGSGBranchIntoBones(leda::node v)
{
	LigatureSegmentList lsl;

	BoneArray& ba    = m_gsgNodeToBones[v];
	GSGNode& gsgnode = m_genSkelGraph.GetNode(v);

	const BranchSegment& nodeBS = gsgnode.GetBonePart();

	DBG_C_LOG_BEGIN_GROUP
	DBG_C_LOG(DBG_VAL(nodeBS.First()) << DBG_VAL(nodeBS.Last()) << DBG_VAL(nodeBS.Size()))
	DBG_C_LOG_IF(DBG_VAL(nodeBS[nodeBS.First()].p) << DBG_VAL(nodeBS[nodeBS.Last()].p), nodeBS.Size() > 0)

	// Find all ligature segments in the branch segment
	lsl.FindLigatureSegments(nodeBS);

	BoneLigamentList bll(lsl, nodeBS);

	bll.RemoveCornerSegments(m_params);

	bll.SubpartitionBones(m_params);

	// Remove the ligature segments that are considered perceptually irrelevant
	//FilterLigatureSegments(lsl, nodeBS);

	// Partition the branch segment into bones and ligaments
	if (/*lsl.empty()*/ bll.empty())
	{
		AddBGNode(nodeBS, ba);
	}
	else
	{
		/*BoneLigamentList bll(lsl, nodeBS);

		bll.RemoveCornerSegments(m_params);

		bll.SubpartitionBones(m_params);*/

		BoneLigamentList::iterator it = bll.begin();

		// If the list begins with ligature (has empty first bone),
		// extend the existing ligature in the GSG edge
		if (it->boneSegment.IsEmpty())
		{
			if (m_genSkelGraph.ExtendRootedLigature(v, it->ligamentSegment))
			{
				it++; // Skip this ligature segment
			}
			else //mmmh, rooted ligature that wasn't detected in the GSGS...
			{
				DBG_C_LOG("unexpected rooted ligature. ignoring first lig segment")

				it = bll.RemoveLigature(it);
			}
		}

		// If the list ends with ligature, extend the existing ligature in the GSG edge
		if (it != bll.end() && !bll.back().ligamentSegment.IsEmpty())
		{
			bool bSuccess = m_genSkelGraph.ExtendRootedLigature(v, 
				bll.back().ligamentSegment);

			if (!bSuccess)
				bll.RemoveLigature(--bll.end());
		}

		ASSERT(!bll.empty());

		// Make sure that if the last bone is empty, it isn't added
		BoneLigamentList::iterator endIt = bll.end();

		if (bll.back().boneSegment.IsEmpty())
			endIt--;

		for (BoneLigamentList::iterator it0 = it; it != endIt; it++)
		{
			ASSERT(!it->boneSegment.IsEmpty());

			// Add one or more entries to the mapping between branch and bones
			it->bgNode = AddBGNode(it->boneSegment, ba);

			BGNode* pNode = m_pBoneGraph->UnsafeGetBGNode(it->bgNode);

			pNode->m_axisFunction = it->axisFunction;
			pNode->m_radiusFunction = it->radiusFunction;

			// If there is a prior bone, connect it to the current bone
			if (it0 != it)
			{
				if (it0->ligamentSegment.DecreasesForward())
				{
					AddBGEdge(it0->bgNode, it->bgNode, it0->ligamentSegment, 
						it0->boneSegment.Size() - 1, BGElement::LIGAMENT);
				}
				else
				{
					AddBGEdge(it->bgNode, it0->bgNode, it0->ligamentSegment, 
						0, BGElement::LIGAMENT);
				}

				// Save the current bone as the previous bone
				it0 = it;
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
void BGC::GetAttachmentPositions(leda::node u)
{
	leda::edge e, ee;
	leda::node v;

	forall_out_edges(e, u)
	{
		v = target(e);

		if (m_genSkelGraph.GetNodeType(v) != GSG_ATTACHMENT)
		{
			forall_out_edges(ee, v)
			{
				DBG_PRINT1(m_genSkelGraph.GetEdge(ee).m_position)
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
void DAGMatcherTopological::ComputeRootedTreeDistance(NodeAssignmentPtr ptrNodeAss)
{
	splitPar0 = GetSplitParams(v0);
	splitPar1 = GetSplitParams(v1);

	contPar0 = GetContractionParams(v0);
	contPar1 = GetContractionParams(v1);

	for (splitPar0)
	{
		for (splitPar1)
		{
			for (contPar0)
			{
				for (contPar1)
				{
					ptrNodeAss2 = new X;

					dist = ComputeRootedTreeDistance(ptrNodeAss2);

					if (dist < minDist)
					{
						minDist = dist;
						ptrNodeAss = ?;
					}
				}
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
	/*if (paramIdx != 0)
	{
		return NodeAssignmentPtr(new NodeAssignment(v0, v1, parInds));
	}*/
///////////////////////////////////////////////////////////////////////////////
class ParamIndices
{
	int m_indices;
	int m_size;

public:
	ParamIndices(int sz = 0) 
	{ 
		m_indices = (sz > 0) ? new int[sz] : NULL; 
		m_size = sz;
	}

	~ParamIndices()
	{
		delete[] m_indices;
	}

	int& operator[](int i) const
	{
		return m_indices[i];
	}

	int operator[](int i)
	{
		return m_indices[i];
	}
};
///////////////////////////////////////////////////////////////////////////////
	int NodeDFSIndex(int i) const
	{
		return Graph(i)->GetNodeDFSIndex(Node(i));
	}
///////////////////////////////////////////////////////////////////////////////			
			sc0 = g0.GetSplitCount(v0);
			sc1 = g1.GetSplitCount(v1);

			for (splitIdx0 = 0; splitIdx0 < sc0; splitIdx0++)
			{
				for (splitIdx1 = 0; splitIdx1 < sc1; splitIdx1++)
				{
				}
			}
///////////////////////////////////////////////////////////////////////////////
	int nodeIdx0 = ptrNodeAss->NodeDFSIndex(0); 
	int nodeIdx1 = ptrNodeAss->NodeDFSIndex(1);

	m_subtreeAssigns[nodeIdx0][nodeIdx1] = ptrNodeAss;
///////////////////////////////////////////////////////////////////////////////
	for (int j = 0; j < segments.GetSize(); j++)
	{
		leda::point pt0 = ReMapPt(segments[j].GetP0(), ii);
		leda::point pt1 = ReMapPt(segments[j].GetP1(), ii);

		DBG_PRINT4(segments[j].GetP0(), segments[j].GetP1(), pt0, pt1)

		m_pWnd->draw_segment(pt0, pt1, c);
	}
///////////////////////////////////////////////////////////////////////////////
const POINT endPts[2] = {vertices[0], vertices[n - 1]};
	const POINT* givenPts = vertices;
	const int M = n;
///////////////////////////////////////////////////////////////////////////////
/*const DAG& dag1 = *m_ptrRootAssignment->Graph(1);
	NodeAssignmentPtr ptrNodeAss;
	leda::node v0;
	double nodeCost0, nodeCost1, dist, ndist, nodeSim,  avgSal, nodeSal0, nodeSal1;

	double graphSim = 0;

	const double N0 = dag0.GetNodeCount();
	const double N1 = dag1.GetNodeCount();

	forall_nodes(v0, dag0)
	{
		NodeMatchCodomain& nmc = nodeMap[v0];

		if (!nmc.IsEmpty())
		{
			nodeCost0 = dag0.GetNodeCost(v0);
			nodeCost1 = dag0.GetNodeCost(nmc.node);

			ptrNodeAss = new NodeAssignment(v0, nmc.node, nmc.paramIndex);

			dist = ComputeNodeDistance(ptrNodeAss);

			ndist = dist / (nodeCost0 + nodeCost1);

			ASSERT_UNIT_INTERVAL(ndist);

			nodeSim = (1 - ndist);
			nodeSal0 = 1 / N0;
			nodeSal1 = 1 / N1;
			avgSal = (nodeSal0 + nodeSal1) / 2;

			graphSim += avgSal * nodeSim;
		}
	}

	if (graphSim > 1 && graphSim < 1.001)
		graphSim = 1;

	ASSERT_UNIT_INTERVAL(graphSim);

	return graphSim;*/	
///////////////////////////////////////////////////////////////////////////////
double dist, minDist;
	
	minDist = ComputeNodeDistance(v1, v2, 0);

	for(int parIdx = 1; parIdx < 4; parIdx++)
	{
		dist = ComputeNodeDistance(v1, v2, parIdx);

		if (dist < minDist)
			minDist = dist;
	}

	double cost1 = m_pG1->GetDAGCost();
	double cost2 = m_pG2->GetDAGCost();

	double normDist = minDist / (cost1 + cost2);

	ASSERT_UNIT_INTERVAL(normDist);

	return 1 - normDist;
///////////////////////////////////////////////////////////////////////////////
/*double area0= xi.Area();

		LineSegmentArray revRadFunc1 = pNode1->GetRadiusFunction().Reverse();
		const double maxAxisDist = pNode1->Length();

		for (int i = 0; i < revRadFunc1.Size(); i++)
			revRadFunc1[i].Reverse(maxAxisDist);

		XORIntegral xi2(revRadFunc1, pNode2->GetRadiusFunction());

		double area2 = xi2.Area();

		return MIN(area0, area2);*/
///////////////////////////////////////////////////////////////////////////////
	double area0 = w * (itA->y0 + itB->y0) / 2;
				double area1 = w * (itA->y1 + itB->y1) / 2;
				area = MAX(area0, area1);
///////////////////////////////////////////////////////////////////////////////
// If there is only one axis segment, it can only be that the whole 
			// bone is a corner...
			if (it0->axisFunction.Size() == 1)
			{
				// ... as long as the segment is not longer than the radius at the source
				dist2 = it0->boneSegment.FirstPtCoord().sqDist(
					it0->boneSegment.LastPtCoord());

				rad = it0->boneSegment.FirstPoint().radius();
				
				if (dist2 > (rad * rad))
					continue;

				//... and that it starts at the beginning of a branch that is
				// incident on a juncion point
				pJoint = GetFirstJoint(it0->boneSegment.m_pBranch);

				if (it0->boneSegment.First() != it0->boneSegment.BranchFirst() ||
					pJoint->degree() == 1)
					continue;

				// the radius function function must have a sigle segment with negative slope
				if (it0->radiusFunction.Size() == 1 && 
					it0->radiusFunction.GetHead().m < -0.05)
				{
					it0->ligamentSegment.ExtendSegment(it0->boneSegment);
					it0->ligamentSegment.m_pJoint = pJoint;
				}
			}
			else
			{
			}
		}
		else // ligature decreases backwards (it1 may have the corner)
		{
			rad = it1->boneSegment.LastPoint().radius();

			it1->SetAxisAndRadiusFunctions(params);

			if (it1->axisFunction.Size() == 1)
			{
				// ... as long as the segment is not longer than the radius at the source
				dist2 = it1->boneSegment.FirstPtCoord().sqDist(
					it1->boneSegment.LastPtCoord());

				rad = it1->boneSegment.LastPoint().radius();
				
				if (dist2 > (rad * rad))
					continue;

				pJoint = GetLastJoint(it1->boneSegment.m_pBranch)

				//... and that it starts at the beginning of a branch that is
				// incident on a juncion point
				pJoint = GetFirstJoint(it0->boneSegment.m_pBranch);

				if (it0->boneSegment.First() != it0->boneSegment.BranchFirst() ||
					pJoint->degree() == 1)
					continue;

				// the radius function function must have a sigle segment with negative slope
				if (it0->radiusFunction.Size() == 1 && 
					it0->radiusFunction.GetHead().m < -0.05)
				{
					it0->ligamentSegment.ExtendSegment(it0->boneSegment);
					it0->ligamentSegment.m_pJoint = pJoint;
				}
			}
		}

		// The straight length between the (Sub)bunoe
		if (dist2 > (rad * rad))
			continue;

		// Only evaluate parent bones
		if (it0->ligamentSegment.DecreasesForward())
		{
			rad = it0->boneSegment.FirstPoint().radius();
			

			if (dist2 <= (rad * rad))
			{
				it0->SetAxisAndRadiusFunctions(params);

				if (it0->axisFunction.Size() == 1 && it0->radiusFunction.Size() == 1)
				{
					if (it0->radiusFunction.GetHead().m < -0.05)
					{
						it0->ligamentSegment.ExtendSegment(it0->boneSegment);

						// Set rooted ligature info
						if (it0->ligamentSegment.First() == it0->ligamentSegment.BranchFirst())
							it0->ligamentSegment.m_pJoint = GetFirstJoint(it0->ligamentSegment.m_pBranch);

						//.m_pJoint = GetLastJoint(bs.m_pBranch);

						//it0->ligamentSegment.SetLimits(
						//	it0->boneSegment.First(), it0->ligamentSegment.Last());

						it0->boneSegment.SetEmpty();
					}
				}
			}
		}
///////////////////////////////////////////////////////////////////////////////
/*!
	Removes corner bones
*/
void BGC::RemoveCornerBones()
{
	BGNode* pNode;
	const BGEdge* pEdge;
	leda::node v;
	leda::edge e, inEdge;
	int attPtIdx, endPtIdx, numPts;
	double endPtRad, attPtRad;

	forall_nodes(v, *m_pBoneGraph)
	{
		if (indeg(v) == 1 && outdeg(v) >= 1)
		{
			inEdge = m_pBoneGraph->first_in_edge(v);

			if (!m_pBoneGraph->GetBGEdge(inEdge)->IsEmpty())
				continue;

			hasOutLigEdge = false;
			
			forall_out_edges(e, v)
			{
				if (!m_pBoneGraph->GetBGEdge(e)->IsEmpty())
				outLigEdge = Find;
			}
		}
	}

	forall_nodes(v, *m_pBoneGraph)
	{
		pNode = m_pBoneGraph->UnsafeGetBGNode(v);
		numPts = pNode->NumPoints();

		forall_out_edges(e, v)
		{
			pEdge = m_pBoneGraph->GetBGEdge(e);

			if (!pEdge->IsEmpty())
			{
				attPtIdx = pEdge->GetSourcePointIndex();

				ASSERT(attPtIdx >= 0 && attPtIdx < numPts);

				// See if it's an end-to-end attachment
				if (attPtIdx == 0 || attPtIdx == numPts - 1)
				{
					// See if both axis and radius function have only one segment
					// and that the radius decreases towards the attachment point
					// and that there is a parent bone
					if (pNode->m_axisFunction.Size() == 1 &&
						pNode->m_radiusFunction.Size() == 1 &&
						indeg(v) == 1)
					{
						endPtIdx = (attPtIdx == 0) ? numPts - 1 : 0;

						attPtRad = pNode->GetShockPoint(attPtIdx).radius;
						endPtRad = pNode->GetShockPoint(endPtIdx).radius;

						if (endPtRad > attPtRad && 
							endPtRad >= pNode->m_axisFunction.GetHead().GetLen())
						{
							//DBG_MSG2("Found it", pNode->FirstShockPoint().pt)
							leda::edge ee;
							leda::node u = source(m_pBoneGraph.first_in_edge(v));

							forall_out_edges(ee, v)
							{
								move_edge(e, u, target(ee));
							}
						}
					}
					else if (pNode->m_axisFunction.Size() > 1)
					{
					}
				}
			}
		}
	}
}
///////////////////////////////////////////////////////////////////////////////
/*LigatureSegmentList::iterator it, it0;
	unsigned int endPt0, endPt1;
	bool bCanBeWhole;

	BranchSegment cornerBS(nodeBS); // init the branch info of the corner
	BranchSegment bone(nodeBS);    // init the branch info of the bone

	for (it = lsl.begin(); it != lsl.end(); it++)
	{
		it0 = it;

		if (it->DecreasesForward())
		{
			// If rooted/terminal ligature, then there is no parent bone to check
			if (it->First() != nodeBS.First())
			{
				endPt0 = (it == lsl.begin()) ? nodeBS.First() : (--it0)->Last() + 1;
				endPt1 = it->First() - 1;

				bCanBeWhole = (nodeBS.First() == endPt0);

				bone.SetLimits(endPt0, endPt1);

				if (GetCornerSegment(BranchWalkInfo(bone, true), bCanBeWhole, &cornerBS))
				{
					it->SetLimits(cornerBS.First(), it->Last());
				}
			}
		}
		else // decreases backwards
		{
			// If rooted/terminal ligature, then there is no parent bone to check
			if (it->Last() != nodeBS.Last())
			{
				++it0;

				endPt0 = (it0 == lsl.end()) ? nodeBS.Last() : it0->First() - 1;
				endPt1 = it->Last() + 1;

				bCanBeWhole = (endPt0 == nodeBS.Last());

				bone.SetLimits(endPt0, endPt1);

				if (GetCornerSegment(BranchWalkInfo(bone, true), bCanBeWhole, &cornerBS))
				{
					it->SetLimits(it->First(), cornerBS.Last());
				}
			}
		}
	}	*/
///////////////////////////////////////////////////////////////////////////////
		// If the list begins with ligature, subtract it from the branch
		if (lsl.front().First() == nodeBS.First())
		{
			if (m_genSkelGraph.ExtendRootedLigature(v, lsl.front()))
				firstPt = lsl.front().Last() + 1;
			else
			{
				//mmmh, rooted ligature that wasn't detected in the GSGS...
				firstPt = nodeBS.First(); // ignore first lig segment
				DBG_C_LOG("unexpected rooted ligature. ignoring first lig segment")
			}

			lsl.pop_front();
		}
		else
		{
			firstPt = nodeBS.First();
		}

		// If the list ends with ligature, subtract it from the branch
		if (!lsl.empty() && lsl.back().Last() == nodeBS.Last())
		{
			if (m_genSkelGraph.ExtendRootedLigature(v, lsl.back()))
				lastPt = lsl.back().First() - 1;
			else
			{
				lastPt = nodeBS.Last(); // ignore last lig segment
				DBG_C_LOG("unexpected rooted ligature. ignoring last lig segment")
			}

			lsl.pop_back();
		}
		else
		{
			lastPt = nodeBS.Last();
		}

		BranchSegment bs0 = nodeBS; // init bs0 with valid branch info

		// If the non-ligature segement is empty, add a zero-length bone
		if (m_params.nSubtractLigatureFromJunctions && firstPt > lastPt)
		{
			WARNING(true, "Adding empty bone!!!");
			ASSERT(lsl.empty());
			bs0.SetEmpty();
			AddBGNode(bs0, ba);
		}
		else
		{
			ASSERT(firstPt <= lastPt);

			LigatureSegmentList::iterator it0, it;
			unsigned int i, j, sz0;
			leda::node u, v;
			
			ba.reserve(lsl.size() + 1);

			it = lsl.begin();
			i = firstPt;
			u = nil;

			while (true)
			{
				j = (it == lsl.end()) ? lastPt : it->First() - 1;

				bs0.SetLimits(i, j);
				ASSERT(!bs0.IsEmpty());
				
				// Add one or more entries to the mapping between branch and bones
				v = AddBGNode(bs0, ba);

				// If we partitioned a prior bone, connect it to v
				if (u != nil)
				{
					if (bs0[it0->First()].radius() > bs0[it0->Last()].radius())
						AddBGEdge(u, v, *it0, sz0 - 1, BGElement::LIGAMENT);
					else
						AddBGEdge(v, u, *it0, 0, BGElement::LIGAMENT);
				}

				// Stop if there are no more ligature segments
				if (it == lsl.end())
					break;

				u   = ba.back().first;
				sz0 = ba.back().second.Size();
				i   = it->Last() + 1;
				it0 = it++;

				ASSERT(sz0 > 0);
			}
			
		}
///////////////////////////////////////////////////////////////////////////////		
/*!
	@brief Computes the radius function for the shock points in the bone.

	Note: it is not needed if bone specialization is used.
*/
void BGC::ComputeRadiusFunction(BGNode* pBGNode)
{
	if (pBGNode->NumPoints() > 1)
	{
		POINTS dataPts = pBGNode->GetVelocityRadiusArray();
		
		ASSERT(!dataPts.IsEmpty());

		// Approximate the radius function along the skeleton
		const double dMinError = dataPts.GetSize() / m_params.dMinErrorRate;

		PolyLineApprox polyLA(dMinError, m_params.dMinSlope, 
			MAX_NUM_RADIUS_FUNC_SEGMENTS, m_params.dMaxYDiff);

		//polyLA.SetDbgMode(true);

		polyLA.Fit(dataPts);

		// Copy the radius function approximation
		pBGNode->m_radiusFunction.Resize(polyLA.m_knots.GetSize());

		for (int i = 0; i < polyLA.m_knots.GetSize(); i++)
			pBGNode->m_radiusFunction[i] = polyLA.m_knots[i].seg;
	}
	else if (pBGNode->NumPoints() == 1)// there is only one point
	{
		// Define a line segment of length one
		pBGNode->m_radiusFunction.Resize(1);

		double r = pBGNode->FirstShockPoint().radius;

		// Add a line segment with 0 slope, r y-intercept
		pBGNode->m_radiusFunction[0].Set(0, r, POINT(0, r), POINT(1, r));
	}
	else // degenerate case of emtpy bone
	{
		pBGNode->m_radiusFunction.Resize(1);
		pBGNode->m_radiusFunction[0].Set(0, 0, POINT(0, 0), POINT(1, 0));
	}
}
///////////////////////////////////////////////////////////////////////////////		
/*!
	@brief Computes the axis function for the shock points in the bone.
*/
void BGC::ComputeAxisFunction(POINTS data, BGElement::AxisFunction& axisFunction)
{
	if (shockPts.Size() > 3)
	{	
		POINTS data(shockPts.Size());
		int i;
		
		for (i = 0; i < data.GetSize(); i++)
			data[i] = shockPts[i].pt;
		
		PolyLineTLSApprox poly(data.GetSize() / m_params.dMinErrorRate, 
			MAX_NUM_AXIS_FUNC_SEGMENTS);
		
		poly.Fit(data);
		
		// Copy all the line segments
		axisFunction.Resize(poly.m_knots.GetSize());
		
		for (i = 0; i < poly.m_knots.GetSize(); i++)
			axisFunction[i] = poly.m_knots[i].seg;
	}
	else if (shockPts.Size() > 0)
	{
		// Define a line segment of length one
		axisFunction.Resize(1);

		axisFunction[0].p0 = shockPts.GetHead().pt;
		axisFunction[0].p1 = shockPts.GetTail().pt;
	}
	else // degenerate case of emtpy bone
	{
		axisFunction.Clear();
	}
}
///////////////////////////////////////////////////////////////////////////////		
	static int CompareDescending(const MatchInfo& a, const MatchInfo& b);
	static int CompareAscending(const MatchInfo& a, const MatchInfo& b);

/*!
	Compares the similarity value of each MatchInfo in descending order.
	If both objects have equal similarity, then their offset position
	in the database file is used to sort them (in ascending order), so
	that the results are deterministic and clear.
*/
/*static*/ 
int MatchInfo::CompareDescending(const MatchInfo& a, const MatchInfo& b)
{
	if (a.dSimilarity > b.dSimilarity)
		return -1;
	else if(a.dSimilarity < b.dSimilarity)
		return 1;
	else if (a.nDAGOffset < b.nDAGOffset)
		return -1;
	else if (a.nDAGOffset > b.nDAGOffset)
		return 1;
	else
		return 0;
}

/*!
	Compares the similarity value of each MatchInfo in ascending order.
	If both objects have equal similarity, then their offset position
	in the database file is used to sort them (in ascending order), so
	that the results are deterministic and clear.
*/
/*static */
int MatchInfo::CompareAscending(const MatchInfo& a, const MatchInfo& b)
{
	if (a.dSimilarity < b.dSimilarity)
		return -1;
	else if(a.dSimilarity > b.dSimilarity)
		return 1;
	else if (a.nDAGOffset < b.nDAGOffset)
		return -1;
	else if (a.nDAGOffset > b.nDAGOffset)
		return 1;
	else
		return 0;
}

class MatchInfoList : public leda_array<MatchInfo>
	{
		void sort() { /* forbid the call to this function*/ }

	public:
		void Sort(bool bDescending)
		{
			if (bDescending)
				leda_array<MatchInfo>::sort(MatchInfo::CompareDescending);
			else
				leda_array<MatchInfo>::sort(MatchInfo::CompareAscending);
		}
	};
	
	MatchInfoList matchList;
	
		/*!
		It is true if the similarity values decrease as DAGs become dissimilar. In 
		such a case, the similarity values are in the interval [0, 1]. Otherwise, 
		the similarity values behave as a distance function, and are in the interval 
		[0, infinity] (+INF is a valid return value in this case).
	*/
	virtual bool SimilarityOrder() const
	{
		return true;
	}
	
		/*!
		It is true if the similarity values decrease for shapes as
		DAGs become dissimilar. In this case, the similarity values are in the interval
		[0, 1]. Otherwise, the similarity values behave as a distance function and 
		are defined in the interval [0, infinity] (yes, closed interval because infinity 
		can be returned).
	*/
	bool SimilarityOrder() const
	{
		return GetMatchingAlgorithm()->SimilarityOrder();
	}
	
		//! The similarity values behave as distances
	virtual bool SimilarityOrder() const;
	{
		return true;
	}
///////////////////////////////////////////////////////////////////////////////		
// Function definitions
int CompareSimilarityAsDistance(const dml::MatchInfo& a, const dml::MatchInfo& b)
{
	int val = leda::compare(a, b);

	return (val == 0) ? 0 : -val;
}
///////////////////////////////////////////////////////////////////////////////		
	// Remove current object from list
	leda_array<MatchInfo> newMatchList(matchList.size());
	int numModels = 0;
	
	for (int i = 0; i < matchList.size(); i++)
	{
		pModelDag = matchList[i].ptrDAG;

		if (pModelDag != NULL && pQueryDag->GetObjName() != pModelDag->GetObjName())
		{
			newMatchList[numModels++] = matchList[i];
		}
	}

	
	matchList
///////////////////////////////////////////////////////////////////////////////		
const double minDist = m_ptrRootAssignment->Distance();

	const DAG& dag0 = *m_ptrRootAssignment->Graph(0);
	const DAG& dag1 = *m_ptrRootAssignment->Graph(1);
	leda::node v;

	double graphSim0 = 0;
	double graphSim1 = 0;

	double cost0 = dag0.GetDAGCost();
	double cost1 = dag1.GetDAGCost();

	forall_nodes(v, dag0)
	{
		NodeMatchCodomain& nmc = nodeMap[v];

		if (!nmc.IsEmpty())
		{
			graphSim0 += nmc.similarity;// * GetBGNode(v, dag0)->Length();
			
			graphSim1 += nmc.similarity;// * GetBGNode(nmc.node, dag1)->Length();
		}
	}

	//ASSERT_UNIT_INTERVAL(graphSim0);

	return 1 - (graphSim0 / (cost0 + cost1));

	/*graphSim0 /= TotalLength(dag0);
	graphSim1 /= TotalLength(dag1);

	return (graphSim0 + graphSim1) / 2;*/

///////////////////////////////////////////////////////////////////////////////		
double BGCSM::ComputeNodeDistance(leda::node v1, leda::node v2, int parmIdx) const
{
	const BGNode* pNode1 = m_pG1->GetBGNode(v1);
	const BGNode* pNode2 = m_pG2->GetBGNode(v2);

	// Make sure that the dummy root only compares well with another root
	//if (indeg(v1) == 0 || indeg(v2) == 0)
	//	return (indeg(v1) == indeg(v2)) ? 1 : 0;

	//DBG_M_LOG("Comparing nodes " << m_pG1->GetNodeDFSLbl(v1) 
	//	<< " and " << m_pG2->GetNodeDFSLbl(v2))
	
	/*if (pNode1->IsEmpty() || pNode2->IsEmpty())
	{
		if (!pNode1->IsEmpty())
			return XORIntegral::FunctionArea(pNode1->RadiusFunction()); 
		else if (!pNode2->IsEmpty())
			return XORIntegral::FunctionArea(pNode2->RadiusFunction()); 
		else
			return 0;
	}*/
	if (pNode1->Type() == BGElement::BACK_BONE || pNode2->Type() == BGElement::BACK_BONE)
	{
		if (pNode1->Type() != BGElement::BACK_BONE)
			return XORIntegral::FunctionArea(pNode1->RadiusFunction());
		else if (pNode2->Type() != BGElement::BACK_BONE)
			return XORIntegral::FunctionArea(pNode2->RadiusFunction());
		else
			return 0;
	}
	else
	{
		XORIntegral xi(pNode1->RadiusFunction(), pNode2->RadiusFunction());

		return xi.Area();
	}
}

/*!
	@brief 
*/
double BGCSM::ComputeEdgeSimilarity(leda::edge e1, leda::edge e2, 
									int paramIdx) const
{
	const BGEdge* pEdge1 = m_pG1->GetBGEdge(e1);
	const BGEdge* pEdge2 = m_pG2->GetBGEdge(e2);

	const NodeParams params = GetNodeParams(paramIdx);

	const double angle1 = pEdge1->Angle(params.bFlipSide);
	const double angle2 = pEdge2->Angle();

	if (angle1 != 0 && angle2 != 0 && SIGN(angle1) != SIGN(angle2))
		return 0;

	//DBG_PRINT_IF("Yes", params.bFlipPosition)

	return 1 - fabs(pEdge1->Position(params.bFlipPosition) - pEdge2->Position());


	// TODO: edges need to know their cumulative mass => saliency

	//double avgSal = (pEdge1->Saliency() + pEdge2->Saliency()) / 2.0;

	/*double position1 = pEdge1->Position();
	double angle1    = pEdge1->Angle();

	const NodeParams params = GetNodeParams(paramIdx);

	if (params.bFlipPosition) 
		position1 = 1 - position1;

	if (params.bFlipSide)
		angle1 = -angle1;

	double position2 = pEdge2->Position();
	double angle2    = pEdge2->Angle();

	// TODO: get a valid similarity measure
	double positionDiff = fabs(position1 - position2);
	//double angleDiff    = fabs(angle1 - pEdge2->Angle()) / M_PI;

	double angleDiff;
	
	if (SIGN(angle1) == SIGN(angle2))
	{
		angleDiff = 0;
	}
	else
	{
		angleDiff = fabs(angle1 - pEdge2->Angle()) / M_PI;

		if (angleDiff < 0 || angleDiff > 1)
		{
			WARNING(true, "Wrong angle difference");
			angleDiff = 1;
		}
	}

	ASSERT_UNIT_INTERVAL(positionDiff);
	ASSERT_UNIT_INTERVAL(angleDiff);

	const double& posWeight = DAGMatcher::GetMatchParams().dDiffAttachPosWeight;	
	ASSERT_UNIT_INTERVAL(posWeight);

	return 1 - (posWeight * positionDiff + (1 - posWeight) * angleDiff);*/
}
///////////////////////////////////////////////////////////////////////////////		
	char szLogFileName[MAX_PATH_SIZE];
	DirWalker::CreateUniqueFileName(".", "error_report", "log", szLogFileName);

	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, hLogFile);
///////////////////////////////////////////////////////////////////////////////		
/*!
	@brief Uses the file path to extract the object name and view
	number.
*/
void DAG::SetObjectNameAndViewNumber(const String& path)
{
	int i, j, k/*, lastFileSep*/;
	String viewName;
	const int nLen = path.Len();
	
	strObjectName.Clear();
	
	// Find last FILE_SEP in the path
	for (i = nLen - 1; i >= 0 && path[i] != FILE_SEP; i--);
	
	bool bHasDirName = (i > 1 || (i == 1 && path[0] != '.'));
	
	// If i is greater than zero, we have a string with format '/ObjName/prefixNNN.ext'
	if (bHasDirName && s_constructParams.nUseDirNameAsObjName != 0) 
	{
		// Search for next '/'
		for (j = i - 1; j >= 0 && path[j] != FILE_SEP; j--);
		
		// j point to the second '/'
		strObjectName.Resize(i - j);
		
		for (j++, k = 0;  j < i; j++, k++)
			strObjectName[k] = path[j];
		
		strObjectName[k] = '\0';
		
		// Find beginning of view number
		for (i++; i < nLen && !isdigit(path[i]); i++);
	}
	else // we have a string with format 'ObjNameNNN.ext'
	{
		ASSERT(i >= -1);

		const int first = (i == -1 || path[i] == FILE_SEP) ? i + 1 : i;

		// Find beginning of view number
		for (i = first; i < nLen && !isdigit(path[i]) && path[i] != '.'; i++);
		
		// Copy obj name
		
		strObjectName.Resize(i + 1 - first);
		
		for (j = first; j < i; j++)
			strObjectName[j - first] = path[j];
		
		strObjectName[j - first] = '\0';
	}
	
	// Find view number
	viewName.Resize(nLen - i + 1);
	
	for (k = 0; i <= nLen; i++, k++)
		viewName[k] = path[i];
	
	nViewNumber = (viewName[0] != '\0') ? atoi(viewName):1;
}

///////////////////////////////////////////////////////////////////////////////		
_RPT1(_CRT_WARN, "Recomputing DAG %d... ", i);
if (exitCode == 0)
			{
				_RPT0(_CRT_WARN, "done!\n");
			}
			else
			{
				_RPT0(_CRT_WARN, "there were errors\n\n");
			}
///////////////////////////////////////////////////////////////////////////////		
class DAGSimilarityMemory : SmartMatrix<Matrix>
{
	bool m_bIsDiagonal;

public:

	Matrix& operator()(int i, int j)
	{
		return (m_bIsDiagonal) ? (*this)[0][j] : (*this)[i][j];
	}

	double& operator()(int i, int j, int si, int sj)
	{
		return (*this)(i, j)(si + 1, sj + 1);
	}

	bool IsDiagonal() const
	{
		return m_bIsDiagonal;
	}

	DAGSimilarityMemory(int n, int subRows, int subCols)
	{
		m_bIsDiagonal = true;

		Resize(1, n);

		for (int j = 0; j < n; j++)
		{
			Matrix& simMat = (*this)(1, j);

			simMat.ReSize(subRows, subCols); 
			simMat = -1;
		}
	}

	DAGSimilarityMemory(int rows, int cols, int subRows, int subCols)
	{
		m_bIsDiagonal = false;

		int i, j;

		Resize(rows, cols);

		for (i = 0; i < rows; i++)
		{
			for (j = 0; j < cols; j++)
			{
				Matrix& simMat = (*this)(i, j);

				simMat.ReSize(subRows, subCols); 
				simMat = -1;
			}
		}
	}
};
///////////////////////////////////////////////////////////////////////////////		
bool ShapeMatcher::ReadDAGsToMemory(const char* szDBName, DAGArray& memoryDB)
{
	if (!m_dagDB.Open(szDBName))
	{
		ShowOpenFileError(szDBName);
		return false;
	}

	const int N = m_dagDB.GetDAGCount();

	memoryDB.reserve(N);

	for (int id = 0; id < N; id++)
	{
		memoryDB.push_back(m_dagDB.ReadDAG(id, true));
	}

	m_dagDB.Close();

	return true;
}
///////////////////////////////////////////////////////////////////////////////		
	//////
	const SkelJoint* pJoint = GetCommonSkelJoint(pBranch0, pBranch1);
	std::pair<char,char> sides = GetSidesOfSharedBndryPt(pBranch0, pBranch1, pJoint);

	// Set the interval defined by the two branches
	firstSideInt.Set(bndryLength, extPt0.first.index, extPt1.first.index);
	secondSideInt.Set(bndryLength, extPt0.second.index, extPt1.second.index);
	/////
///////////////////////////////////////////////////////////////////////////////		
// If all bones have ligature points, then we consider all of them as
	// possible parents
	//if (areas.empty())
	//	areas = allAreas;

	//DBG_PRINT1(jointPt)
	//ASSERT(!areas.empty());

	std::vector< std::pair<double, leda::edge> > areaDiffs;

	if (!areas.empty())
	{
		unsigned int i, j;
		double diff, minDiff;

		// Find the min difference assoc with each area. If there is only one area,
		// then the min difference is set to 1 and will be chosen as the parent bone.
		for (i = 0; i < areas.size(); i++)
		{
			// Init the nomalized minDiff to its maximum possible value
			minDiff = 1;
			area = areas[i].first;

			for (j = 0; j < areas.size(); j++)
			{
				if (i != j)
				{
					diff = (area - areas[j].first) / MAX(area, areas[j].first);

					if (diff < minDiff)
						minDiff = diff;
				}
			}

			areaDiffs.push_back(std::make_pair(minDiff, areas[i].second));
		}

		std::sort(areaDiffs.begin(), areaDiffs.end());

		//DBG_PRINT3(jointPt, areaDiffs.back().first, areaDiffs.front().first)
	}

	if (!areaDiffs.empty() && areaDiffs.back().first > 0.5)
	{
		leda::node parentBone = PromoteGSGNodeAtJunctionToParentRole(areaDiffs.back().second);
	}
	else
	{
		leda::node r = m_genSkelGraph.AddRootBranchNodeToJunctionNode(t);
		GSGNode& gsgnode = m_genSkelGraph.GetNode(r);

		// Define a new entry in the gsgnode-bone map, and create a new bone node
		AddBGNode(gsgnode.GetBonePart(), m_gsgNodeToBones[r], BGElement::SIMPLE_ROOT_BONE);
	}
///////////////////////////////////////////////////////////////////////////////		
if (!IsValidAssignemt(v0, v1))
				continue;
///////////////////////////////////////////////////////////////////////////////		

	//! If there is a child assignment, it returns its distance. Otherwise, it returns zero.
	double GetGivenChildAssignmentWeightedDistance() const
	{
		ASSERT(HasGivenChildAssignment());

		return ;
	}
	
// At most, we can be given a parent or a child assignment
		ASSERT(pParentAssignment == NULL || pChildAssignment == NULL);
		
double DAGMatcherTopological::ComputeRootedTreeDistance(NodeAssignmentPtr ptrNodeAss) const
{
	double nodeAttDist = ComputeNodeDistance(ptrNodeAss);

	// Create BipGraph G. Exclude edges whose target is any of the known nodes
	EdgeAssignmentGraph g;
	leda::node v;
	leda::edge e;

	for (int setId = 0; setId <= 1; setId++)
	{
		v = ptrNodeAss->Node(setId);

		forall_adj_edges(e, v)
		{
			if (!ptrNodeAss->IsGivenChildAssignment(setId, target(e)))
			{
				g.AddNode(e, setId);
			}
		}
	}

	//DBG_PRINT2(g.number_of_nodes(), g.number_of_edges())
	const int nodeCount = g.number_of_nodes();

	EdgeAssignmentGraph::NodeSetIterator it0, it1;
	NodeAssignmentPtr ptrChildNodeAss;
	double edgeSim, treeDist, maxCost, assDist, maxAssDist = 0;
	leda::node v0, v1;
	leda::edge e0, e1;

	int parIdx = 0; //ptrNodeAss->ParamIndex();

	for (it0 = g.FirstNode(0); it0 != nil; it0 = g.NextNode(0, it0))
	{
		e0 = g.NodeAttribute(0, it0);
		v0 = target(e0);

		for (it1 = g.FirstNode(1); it1 != nil; it1 = g.NextNode(1, it1))
		{
			e1 = g.NodeAttribute(1, it1);
			v1 = target(e1);

			edgeSim = ComputeEdgeSimilarity(e0, e1, parIdx);

			if (edgeSim > 0)
			{
				ptrChildNodeAss = new NodeAssignment(v0, v1, parIdx, ptrNodeAss, NULL);

				treeDist = ComputeRootedTreeDistance(ptrChildNodeAss);

				maxCost = ptrChildNodeAss->Graph(0)->GetSubtreeCost(v0) + 
					ptrChildNodeAss->Graph(1)->GetSubtreeCost(v1);

				// Convex sum of match and missmatch distances
				assDist = edgeSim * treeDist + (1 - edgeSim) * maxCost;

				if (assDist > maxAssDist)
					maxAssDist = assDist;

				ptrChildNodeAss->SetDistance(assDist);

				g.AddEdge(it0, it1, ptrChildNodeAss);
			}
		}
	}

	NodeAssigmentList nodeAssigments;
	EdgeValueArray edgeValues(g);

	//DBG_PRINT2(g.number_of_nodes(), g.number_of_edges())
	maxAssDist++;

	forall_edges(e, g)
	{
		edgeValues[e] = maxAssDist - g.inf(e)->Distance();
	}

	g.SolveMaxWeightAssignment(edgeValues, &nodeAssigments);

	ASSERT(g.number_of_edges() == 0 || nodeAssigments.size() > 0);

	leda::node_array<bool> matchedNodes(g, false);

	// Init the sum of child distances to that of the given child assignment,
	// which is zero if there is not known child assignment
	double childDist = GetGivenChildAssignmentDistance();

	// Add children assignments to ptrNodeAss
	forall(e, nodeAssigments) 
	{
		matchedNodes[source(e)] = true;
		matchedNodes[target(e)] = true;

		ptrNodeAss->AddChildAssignment(g.inf(e));

		childDist += g.inf(e)->Distance();
	}

	leda::edge dagEdge;
	leda::node dagNode;
	const DAG* pDag;

	forall_nodes(v, g)
	{
		if (!matchedNodes[v])
		{
			dagEdge = g.inf(v);
			dagNode = target(dagEdge);

			pDag = (const DAG*) graph_of(dagEdge);

			childDist += pDag->GetSubtreeCost(dagNode);
		}
	}

	ptrNodeAss->SetDistance(nodeAttDist + childDist);

	return ptrNodeAss->Distance();
}

///////////////////////////////////////////////////////////////////////////////		
, treeDist, parentDist, assDist

				/*// Sum of ancestors' distances
				parentDist = ComputeParentsDistance(ptrNodeAss);

				// Convex sum of match and missmatch distances
				assDist = edgeSim * (treeDist + parentDist) + (1 - edgeSim) * maxCost;

				ptrNodeAss->SetDistance(assDist);*/
///////////////////////////////////////////////////////////////////////////////		
double DAGMatcherTopological::ComputeParentsDistance(NodeAssignmentPtr ptrChildNodeAss) const
{
	EdgeAssignmentGraph g;
	leda::node v;
	leda::edge e;

	for (int setId = 0; setId <= 1; setId++)
	{
		v = ptrChildNodeAss->Node(setId);

		forall_in_edges(e, v)
			g.AddNode(e, setId);
	}

	const double node0ParentCost = 
		ptrChildNodeAss->Graph(0)->GetSubtreeComplementCost(ptrChildNodeAss->Node(0));

	const double node1ParentCost = 
		ptrChildNodeAss->Graph(1)->GetSubtreeComplementCost(ptrChildNodeAss->Node(1));

	const double maxCost = node0ParentCost + node1ParentCost;
		

	EdgeAssignmentGraph::NodeSetIterator it0, it1;
	NodeAssignmentPtr ptrNodeAss;
	double edgeSim, treeDist, parentDist, assDist;
	leda::node v0, v1;
	leda::edge e0, e1;

	// Determine parIdx from ptrChildNodeAss
	int parIdx = 0; //ptrChildNodeAss->ParamIndex();

	for (it0 = g.FirstNode(0); it0 != nil; it0 = g.NextNode(0, it0))
	{
		e0 = g.NodeAttribute(0, it0);
		v0 = source(e0);

		for (it1 = g.FirstNode(1); it1 != nil; it1 = g.NextNode(1, it1))
		{
			e1 = g.NodeAttribute(1, it1);
			v1 = source(e1);

			edgeSim = ComputeEdgeSimilarity(e0, e1, parIdx);

			if (edgeSim > 0)
			{
				ptrNodeAss = new NodeAssignment(v0, v1, parIdx, NULL, ptrChildNodeAss);

				// Sum of parent and siblings' distances (not including this subtree)
				treeDist = ComputeRootedTreeDistance(ptrNodeAss);

				// Sum of ancestors' distances
				parentDist = ComputeParentsDistance(ptrNodeAss);

				// Convex sum of match and missmatch distances
				assDist = edgeSim * (treeDist + parentDist) + (1 - edgeSim) * maxCost;

				ptrNodeAss->SetDistance(assDist);

				g.AddEdge(it0, it1, ptrNodeAss);
			}
		}
	}

	double minDist = 0;

	if (g.number_of_edges() > 0)
	{
		leda::edge minEdge = nil;
		double dist;

		forall_edges(e, g)
		{
			dist = g.inf(e)->Distance();

			if (minEdge == nil || dist < minDist)
			{
				minEdge = e;
				minDist = dist;
			}
		}

		ptrChildNodeAss->AddParentAssignment(g.inf(minEdge));
	}
	else
	{
		if (!ptrChildNodeAss->IsRoot(0))
			minDist += node0ParentCost;

		if (!ptrChildNodeAss->IsRoot(1))
			minDist += node1ParentCost;
	}

	return minDist;
}

///////////////////////////////////////////////////////////////////////////////		
double GetRootedTreeCost(const DAG* pDag, leda::node v) const;

double GetParentCost(const DAG* pDag, leda::node v) const;
	
double DAGMatcherTopological::GetRootedTreeCost(const DAG* pDag, leda::node v) const
{
	leda::edge e;
	double cost = pDag->GetNodeCost(v);
	
	forall_adj_edges(e, v)
	{
		cost += GetRootedTreeCost(pDag, target(e));
	}

	return cost;
}

double DAGMatcherTopological::GetParentCost(const DAG* pDag, leda::node v) const
{
	ASSERT(indeg(v) > 0);

	leda::node p = source(pDag->first_in_edge(v));
	leda::edge e;

	double cost = pDag->GetNodeCost(p);

	forall_adj_edges(e, p)
	{
		if (target(e) != v)
			cost += GetRootedTreeCost(pDag, target(e));
	}

	if (indeg(p) > 0)
		cost += GetParentCost(pDag, p);

	return cost;
}
///////////////////////////////////////////////////////////////////////////////		
const V* GetNode1(leda::node v) const 
	 {
		 return dynamic_cast<const V*>((const DAGNode*) m_pG1->GetNode(v));
	 }

	 const V* GetNode2(leda::node v) const 
	 {
		 return dynamic_cast<const V*>((const DAGNode*) m_pG2->GetNode(v));
	 }

	 const E* GetEdge1(leda::edge e) const 
	 {
		 return dynamic_cast<const E*>((const DAGEdge*) m_pG1->GetEdge(e));
	 }

	 const E* GetEdge2(leda::edge e) const 
	 {
		 return dynamic_cast<const E*>((const DAGEdge*) m_pG2->GetEdge(e));
	 }
///////////////////////////////////////////////////////////////////////////////		
double BGContextualSimilarityMeasurer::NodeDistance(const BGElement* pNode1, const BGElement* pNode2) const
{
	int n1Type = pG1->NodeType(v1);
	int n2Type = pG2->NodeType(v2);
		
	// If label is different, do not compare nodes	
	if (n1Type != n2Type)
	{
		DBG_M_LOG("Node types are different")
		return MAXDIST;	
	}
	else if (n1Type == BGNode::BACK_BONE || n2Type == BGNode::BACK_BONE)
	{
		DBG_M_LOG("At least one node is backbone")
		return n1Type == n2Type ? MINDIST:MAXDIST;
	}
	else if (pNode1->NumPoints() == 1 && pNode2->NumPoints() == 1)
	{
		double r1 = pNode1->FirstShockPoint().radius;
		double r2 = pNode2->FirstShockPoint().radius;
		
		DBG_M_LOG("Both nodes have one single point")

		return 1 - MIN(r1, r2) / MAX(r1, r2);
	}
	else if (pNode1->NumPoints() == 1 || pNode2->NumPoints() == 1)
	{
		if (pNode1->NumPoints() > 4 || pNode2->NumPoints() > 4)
		{
			DBG_M_LOG("One node has 1 point and the other has more than 4")

			return MAXDIST; // if it is too long, it's unlikely that they are the same
		}

		DBG_M_LOG("One node has 1 point and the other has 4 or less")
			
		double r1 = pNode1->AvgRadius();
		double r2 = pNode2->AvgRadius();
		double l1 = pNode1->Length();
		double l2 = pNode2->Length();
		
		double rdiff = 1 - MIN(r1, r2) / MAX(r1, r2);
		double lendiff = 1 - MIN(l1, l2) / MAX(l1, l2);
				
		return 0.85 * rdiff + 0.15 * lendiff;
	}
	else if (pNode1->NumPoints() == 0 || pNode2->NumPoints() == 0)
	{
		DBG_M_LOG("At least one node is empty")

		return MAXDIST;
	}
	
	ASSERT(pNode1->RadiusFunction().GetSize() > 0 && pNode2->RadiusFunction().GetSize() > 0);
	
	// We are dealing with same label, non-root nodes, with more that 1 shock point
	// so...
	leda_node par1 = pG1->GetFirstParent(v1);
	leda_node par2 = pG2->GetFirstParent(v2);
	int n1Dir, n2Dir;
	
	if (pG1->NodeType(par1) != BGNode::BACK_BONE && pG2->NodeType(par2) != BGNode::BACK_BONE)
	{
		n1Dir = pG1->GetSlopeDir(v1, par1);
		n2Dir = pG2->GetSlopeDir(v2, par2);
	
		// If the nodes' directions wrt their parents differ,
		// we can say they directions don't match
		if (n1Dir != n2Dir)
		{
			DBG_M_LOG("The node directions wrt their parents don't match")

			return MAXDIST;
		}
	}
	
	// Now, given that their directions match, we need to make
	// sure that we get them right. The may go from 0 to N or form N to 0.
	n1Dir = pNode1->SlopeDir(false);
	n2Dir = pNode2->SlopeDir(false);
	bool bReverseOrder = ( n1Dir != n2Dir );
	
	// what if dir == 0 but there is a slope? We should still reverse it.
	// THIS IS A TO DO
	
	//int d0, dN;
	POINTS g1Pts = pNode1->GetVelocityRadiusArray(/*d0, dN,*/ bReverseOrder);
	POINTS g2Pts = pNode2->GetVelocityRadiusArray(/*d0, dN,*/ bReverseOrder);
	
	// Let's fit the model of node one to the data of node 2 and viceversa
	ModelFit m1(2), m2(2); // 2 is max diff in lenght
	
	double e1 = m1.Fit(g1Pts, pNode2->RadiusFunction());
	
	if (e1 >= INFINITY)
	{
		DBG_M_LOG("Fitting error of node one is infinity")
		return MAXDIST;
	}
	
	double e2 = m2.Fit(g2Pts, pNode1->RadiusFunction());
	
	if (e2 >= INFINITY)
	{
		DBG_M_LOG("Fitting error of node two is infinity")
		return MAXDIST;
	}
		
	ASSERT(pNode1->AvgRadius() > 0 && pNode2->AvgRadius() > 0);
	ASSERT(pNode1->Length() > 0 && pNode2->Length() > 0);

	//if (DAG::IsDbgMode())
	//	LogResults(m1, m2, g1Pts, g2Pts, bReverseOrder);
	
	// We have non-infinite errors, so we must normalize them
	double avge1 = (e1 / g1Pts.GetSize()) / pNode1->AvgRadius();
	double avge2 = (e2 / g2Pts.GetSize()) / pNode2->AvgRadius();
	double error = (avge1 + avge2) / 2.0;
	
	if (error >= MAXDIST)
	{
		DBG_M_LOG("Average fitting error is too large")
		return MAXDIST;
	}
	
	double minL = MIN(pNode1->Length(), pNode2->Length());
	double maxL = MAX(pNode1->Length(), pNode2->Length());

	DBG_M_LOG("Node distance is a convex sum of error " << error
		<< " and length difference " << (1 - minL / maxL))
		
	return 0.85 * error + 0.15 * (1 - minL / maxL);
}
///////////////////////////////////////////////////////////////////////////////		
	if (ptrChildNodeAss->IsRoot(0) || ptrChildNodeAss->IsRoot(1))
	{
		if (!ptrChildNodeAss->IsRoot(0))
		{
			return GetParentCost(ptrChildNodeAss->Graph(0), ptrChildNodeAss->Node(0));
		}
		else if (!ptrChildNodeAss->IsRoot(1))
		{
			return GetParentCost(ptrChildNodeAss->Graph(1), ptrChildNodeAss->Node(1));
		}
		else
		{
			return 0;
		}
	}

///////////////////////////////////////////////////////////////////////////////	
	
	void SolveMinWeightAssignment(NodeAssigmentList* pNodeAssigments)
	{
		EdgeValueArray edgeValues(*this);
		leda::edge e;

		// Assign weights to edges
		forall_edges(e, *this)
			edgeValues[e] = -(double)inf(e);

		SolveMaxWeightAssignment(edgeValues, pNodeAssigments);
	}
	
	leda::edge FindMinWeightAssignment() const
	{
		leda::edge e, minEdge = nil;
		double minVal;

		forall_edges(e, *this)
		{
			val = inf(e);

			if (minEdge == nil || val < minVal)
			{
				minEdge = e;
				minVal = val;
			}
		}

		return minEdge;
	}
///////////////////////////////////////////////////////////////////////////////	
double DAGMatcherTopological::Match(const DAG& g0, const DAG& g1)
{
	std::list<ptrNodeAss> bestMatches;
	NodeAssignmentPtr ptrNodeAss;
	double dist, minDist;
	leda::node v0, v1;

	const bool bIncludeRootNodes = false;

	// Create a graph with n1 + n2 nodes and save the nodes 
	// associated with the g1 and g2 in different sets
	forall_nodes(v0, g0)
	{
		if (!bIncludeRootNodes && g1.IsRootNode(u))
			continue;

		forall_nodes(v1, g1)
		{
			if (!bIncludeRootNodes && g2.IsRootNode(v))
				continue;

			// Try all possible combinations of parameter values
			for(parIdx = 0; parIdx < ptrMatchInfo->ParameterCount(); parIdx++)
			{
				// Create a new match info object
				ptrNodeAss = new NodeAssignment(v0, v1, parIdx, NULL, NULL);

				// Compute node similarity and save it into the match info object
				dist = GraphDistance(ptrNodeAss);

				if (dist < minDist)
				{
					bestMatches.clear();
					bestMatches.push_back(ptrNodeAss);
					minDist = dist;
				}
				else if (dist == minDist)
				{
					bestMatches.push_back(ptrNodeAss);
				}
			}
		}
	}

	m_ptrRootAssignment = bestMatches.front();

	return minDist;
}
///////////////////////////////////////////////////////////////////////////////	
	v0 = ptrNodeAss->Parent(0);
	v1 = ptrNodeAss->Parent(1);

	if (v0 == nil || v1 == nil)
		return 0;
///////////////////////////////////////////////////////////////////////////////	
// build BipGraph with all possible parent assignemt

	//if (ptrNodeAss->HasChildAssignments())

	//if (AreChildNodesUnassigned(u, v))

	if (IsChildNodeAssigned(v0))
		continue;

	if (IsChildNodeAssigned(v1))
		continue;

	// Create a new match info object
		

	foreach(e, G)
	{
		// this gives us side, position, and scale
		u = parent(ptrMatchInfo->GetNode(0));
		v = parent(ptrMatchInfo->GetNode(1));

		params = function(ptrMatchInfo->Params());

		parentDist = ComputeParentsDistance(u, v, params);

		treeDist = ComputeRootedTreeDistance(u, v, params, ptrNodeAss);

		value[e] = treeDist + parentDist;
	}

	double parentDist = G.Solve();

	// Add parent assignments to ptrNodeAss

	return parentDist;
///////////////////////////////////////////////////////////////////////////////	
	leda::node v0 = ptrNodeAss->Node(0);
	leda::node v1 = ptrNodeAss->Node(1);
	
	forall_adj_edges(e0, v0)
	{
		if (!ptrNodeAss->IsGivenChildAssignment(0, target(e0))	
			g.AddNode(e0, 0);
	}

	forall_adj_edges(e1, v1)
	{
		if (!ptrNodeAss->IsGivenChildAssignment(1, target(e1))
			g.AddNode(e1, 1);
	}
	
	if (indeg(v0) > 1 || indeg(v1) > 1) 
			pVisitedNodes->push_back(std::make_pair(v0, v1));
///////////////////////////////////////////////////////////////////////////////	
double DAGMatcherTopological::ComputeRootedTreeDistance(NodeAssignmentPtr ptrNodeAss,
														VisitedNodeList* pVisitedNodes)
{
	leda::node v0 = ptrNodeAss->Node(0);
	leda::node v1 = ptrNodeAss->Node(1);

	ASSERT(indeg(v0) <= 1 || !pVisitedNodes->Visited(0, v0));
	ASSERT(indeg(v1) <= 1 || !pVisitedNodes->Visited(1, v1));

	// ptrMatchInfo gives us side and position orientation, but not scale
	//
	
	
	//this gives us side, position, and scale
	// we are given orientation of relative position and scale
	// but not side. Then, side must be all equal or all different.

	// Assuming all equal sides
	// Build BiPGraph of all edge combinations of equal side
	// Set the weight of each assignment as the result of a rooted tree distance.
	// the roots are given by each edge target being matched

	nodeAttDist = ComputeNodeAttributeDistance(ptrNodeAss);

	// Create BipGraph G. If !ptrKnownChildMatch->IsNull(), exclude
	// edges whose target is any of the known nodes
	EdgeAssignmentGraph g;
	leda::node childNode;

	forall_adj_edges(e0, v0)
	{
		childNode = target(e0);

		if (indeg(childNode) <= 1 || !pVisitedNodes->Visited(0, childNode))
		{
			if (!ptrNodeAss->IsGivenChildAssignment(0, childNode)	
				g.AddNode(e0, 0);
		}
	}

	forall_adj_edges(e1, v1)
	{
		childNode = target(e1);

		if (indeg(childNode) <= 1 || !pVisitedNodes->Visited(1, childNode))
		{
			if (!ptrNodeAss->IsGivenChildAssignment(1, childNode)
				g.AddNode(e1, 1);
		}
	}

	NodeSetIterator it0, it1;

	for (it0 = g.FirstNode(0); it0 != nil; it0 = g.NextNode(it0))
	{
		e0 = g.NodeAttribute(0, it0);
		v0 = target(e0);

		for (it1 = g.FirstNode(1); it1 != nil; it1 = g.NextNode(it1))
		{
			e1 = g.NodeAttribute(1, it1);
			v1 = target(e1);

			ptrChildNodeAss = new NodeAssignment(v0, v1, ptrNodeAss, NULL);

			edgeDist = ComputeEdgeDistance(e0, e1);
			treeDist = ComputeRootedTreeDistance(ptrChildNodeAss);

			ptrChildNodeAss->SetDistance(edgeDist + treeDist);

			g.AddEdge(it0, it1, ptrChildNodeAss);
		}
	}

	NodeAssigmentList nodeAssigments;

	double childDist = g.SolveMinWeightAssignment(&nodeAssigments);

	leda::edge assEdge;

	// Add children assignments to ptrNodeAss
	forall(assEdge, nodeAssigments) 
	{
		ptrNodeAss->AddChildAssignment(g.Inf(assEdge));

		if (indeg(v0) > 1 || indeg(v1) > 1) 
			pVisitedNodes->push_back(std::make_pair(v0, v1));
	}

	return nodeAttDist + childDist;
}

///////////////////////////////////////////////////////////////////////////////	
class VisitedNodeList : std::list< std::pair<leda::node, leda::node> > 
	{
	public:
		bool Visited(int i, leda::node v) const
		{
			ASSERT(i == 0 || i == 1);

			if (i == 0)
			{
				for (iterator it = begin(); it != end(); it++)
					if (it->first == v)
						return true;
			}
			else
			{
				for (iterator it = begin(); it != end(); it++)
					if (it->second == v)
						return true;
			}

			return false;
		}
	};
///////////////////////////////////////////////////////////////////////////////	

	bool IsChildUnassigned(int i, leda::node v, const NodeAssignmentPtr& ptrNodeAss, 
		const VisitedNodeList& visitedNodes) const
	{
		if (indeg(v) > 1 && 
		return !IsGivenChildAssignment(0, v) && 
	}
///////////////////////////////////////////////////////////////////////////////	
		bool Visited(leda::node v0, leda::node v1) const
		{
			for (iterator it = begin(); it != end(); it++)
					if (it->first == v0 || it->second == v1)
						return true;

			return false;
		}
		
bool Visited(int i, leda::node v) const
		{
			ASSERT(i == 0 || i == 1);

			iterator it;

			if (i == 0)
			{
				for (it = begin(); it != end(); it++)
					if (it->first == v)
						return true;
			}
			else
			{
				for (it = begin(); it != end(); it++)
					if (it->second == v)
						return true;
			}

			return false;
		}
///////////////////////////////////////////////////////////////////////////////	
//edgeValues[assEdge] = edgeDist + treeDist;
EdgeValueArray edgeValues(g);
	

	// fill in the values of each candidate assignment
	forall_defined(assEdge, edgeValues)
	{
		e0 = g(assEdge, 0);
		e1 = g(assEdge, 1);

		v0 = target(e0);
		v1 = target(e1);

		ptrChildNodeAss = new NodeAssignment(v0, v1, ptrNodeAss, NULL);

		edgeDist = ComputeEdgeDistance(e0, e1);
		treeDist = ComputeRootedTreeDistance(ptrChildNodeAss);

		edgeValues[assEdge] = edgeDist + treeDist;
	}

	g.SolveMinWeightAssignment(edgeValues, &nodeAssigments);

	foreach(e, G)
	{
		e0 = inf(source(e));
		e1 = inf(target(e));

		v0 = target(e0);
		v1 = target(e1);

		ptrChildNodeAss = new NodeAssignment(v0, v1, ptrNodeAss, NULL);

		edgeDist = ComputeEdgeDistance(e0, e1);
		treeDist = ComputeRootedTreeDistance(ptrChildNodeAss);

		value[e] = edgeDist + treeDist;
	}

	double childDist = G.Solve();
///////////////////////////////////////////////////////////////////////////////	
	void SetGivenParentAssignment(const NodeAssignment* pNA)
	{
		ASSERT(m_pGivenParentAssignment == NULL);
		ASSERT(m_pGivenChildAssignment == NULL);

		m_pGivenParentAssignment = pNA;
	}

	void SetGivenChildAssignment(const NodeAssignment* pNA)
	{
		ASSERT(m_pGivenParentAssignment == NULL);
		ASSERT(m_pGivenChildAssignment == NULL);

		m_pGivenChildAssignment = pNA;
	}
///////////////////////////////////////////////////////////////////////////////	
for (int n = g_counter; n > 0; n /= 10)
		std::cout << char(8);

	std::cout << g_counter++ << std::flush;
///////////////////////////////////////////////////////////////////////////////	
bool ShapeMatcher::OpenAssociateDatabase(const DAGDatabase& srcDB, DAGDatabase& tgtDB)
{
	std::string fileName = DirWalker::AppendToExtension(srcDB.GetFileName(), 
			m_matchInfo.matchingDBIdx);

	ShowMsg("Opening associate database: " + fileName);

	if (!tgtDB.Open(fileName.c_str()))
	{
		ShowOpenFileError(fileName);
		return false;
	}

	return true;
}
///////////////////////////////////////////////////////////////////////////////	
void BoundaryPointFinder::GetBranchBoundaryInterval(const SkelBranch* pBranch, 
													const SkelJoint* pJoint, 
													BoundaryInterval* pBndryInt)
{
	// Get the index of the joint point on the branch
	SkelPtIndex idx = GetEndpointIndex(pBranch, pJoint);

	const sg::BoundaryInfo& bi = pBranch->getBoundaryInfo(idx);

	if (bi.first.index == -1 || bi.second.index == -1)
	{
		pBndryInt->Set(m_origBndryPts.Size(), 0, m_origBndryPts.Size() - 1);
	}
	else
	{
		sg::Point succPt;

		pBndryInt->Set(m_origBndryPts.Size(), bi.first.index, bi.second.index);

		m_origBndryPts.GetDataPoint(pBndryInt->Succ(bi.first.index), succPt.x, succPt.y);

		sg::Vector tangent;

		GetEndpointForwardTangent(pBranch, idx, &tangent);

		
		
	}

}
///////////////////////////////////////////////////////////////////////////////	
void BoundaryPointFinder::SetBoundaryInfoAtTerminal(const sg::FluxPoint& fp0, sg::Vector tangent, 
													bool bDecreasingRadius, const sg::FluxPoint& fp1,
													const sg::BoundaryInfo& oppEndPt,
													sg::BoundaryInfo& bi0)
{
	double alpha, dist0, dist1;
	double epsilon = INIT_EPSILON;
	double* annPt;
	int i, n;

	ASSERT((oppEndPt.first.index == -1 && oppEndPt.second.index == -1) ||
		   (oppEndPt.first.index != -1 && oppEndPt.second.index != -1));

	bool bCheckOtherEndpt = (oppEndPt.first.index != -1 && oppEndPt.second.index != -1);
	bool bMakeIndicesEqual = false;

	// Use the un-smooth (original) points to find the pair of external bounadry points
	// in order to avoid strange effects due to false distance between true centers and bndry pts.
	//KDTree& bndryPts = m_origBndryPts;
	KDTree& bndryPts = m_smoothBndryPts;

	// The tangent is given in the forward direction, as is needed for knowing the
	// "sides". However, we ALSO need it expressed in the direction of decreassing radius
	if (!bDecreasingRadius)
		tangent.scale(-1);

	// Boundary point indices should be initialized already
	ASSERT(bi0.first.index == -1 && bi0.second.index == -1);

	i = 0;       // init outside loop so that each NN is check only once

	do {
		n = bndryPts.RangeSearch(fp0.p.x, fp0.p.y, fabs(fp0.dist), &epsilon, 
			EPSILON_INC, MIN_PTS_RETURNED); //epsilon is updated here

		for (; i < n; i++)
		{
			annPt = bndryPts.GetNNPoint(i);
			alpha = ComputeAlphaAngle(fp0, annPt, tangent);

			// Get distance from fp0 to boundary points
			dist0 = bndryPts.GetNNDistance(i);

			/*if (bCheckOtherEndpt)
			{
				int index = bndryPts.GetNNIndex(i);

				if (index == oppEndPt.first.index || index == oppEndPt.second.index)
				{
					bMakeIndicesEqual = true;
					continue;
				}
			}*/

			// There are some incorrect cases in which the skeletal point
			// is basically touching the boundary. In this case, the object
			// angle is unreliable and is better to skep the point.
			//if (dist0 <= 0.5)
			//	continue;
			if (dist0 < 1 || bMakeIndicesEqual)
			{
				bi0.first.index = bndryPts.GetNNIndex(i);
				bi0.second.index = bndryPts.GetNNIndex(i);

				bndryPts.GetDataPoint(bi0.first.index, bi0.first.pt.x, bi0.first.pt.y);
				bndryPts.GetDataPoint(bi0.second.index, bi0.second.pt.x, bi0.second.pt.y);

				return;
			}

			// Compute distance from fp1 to boundary point
			dist1 = sg::Vector(annPt[0] - fp1.p.x, annPt[1] - fp1.p.y).norm();

			// The object angle should be smaller or equal to pi/2 and, as an extra
			// precaution, we make sure that dist0 is smaller than dist1 before skipping 
			// Also, make sure that the point is not on the boundary (dist >= 1)
			if (fabs(alpha) > M_PI_2 && dist0 < dist1 /*&& dist0 >= 1*/)
				continue;

			// Make the sign of alpha be expressed wrt the original tangent direction
			if (!bDecreasingRadius)
				alpha = -alpha;

			// Choose the closest to both fp0 and fp1 on each side
			if (alpha >= 0 && bi0.first.index == -1)
			{
				// get the point's index in the boundary curve
				bi0.first.index = bndryPts.GetNNIndex(i);

				// copy the point's coordinates
				bndryPts.GetDataPoint(bi0.first.index, bi0.first.pt.x, bi0.first.pt.y);
				
				if (bi0.second.index != -1)
					return; // we are done
			}
			else if (alpha < 0 && bi0.second.index == -1)
			{
				// get the point's index in the boundary curve
				bi0.second.index = bndryPts.GetNNIndex(i);

				// copy the point's coordinates
				bndryPts.GetDataPoint(bi0.second.index, bi0.second.pt.x, bi0.second.pt.y);

				if (bi0.first.index != -1)
					return; // we are done
			}
		}
	} while (n < bndryPts.Size());

	ASSERT(false);
}
///////////////////////////////////////////////////////////////////////////////	
bool BoundaryPointFinder::TestBoundaryPointReplacement(SkelJoint* pJoint, 
						             const sg::BoundaryPoint& newBndryPt,
									 SkelBranch* pParBranch)
{
	if (!pParBranch)
		return true;

	return !DoBranchSpokeIntersect(pParBranch, pJoint->fp.p, newBndryPt.pt);
}

/*!
	@brief Checks that replacing 'oldBndryPt' on each spoke incident on 
	the given junction with the new value 'newBndryPt' yields a valid MAT.

	\image html TestBoundaryPointReplacement.gif
*/
bool BoundaryPointFinder::TestBoundaryPointReplacement(SkelJoint* pJoint, 
						             const sg::BoundaryPoint& oldBndryPt,
						             const sg::BoundaryPoint& newBndryPt)
{
	SkelBranch* pBranch;
	SkelPtIndex idx0, idx1;
	int innerIndices[2], outerIndices[2], i = 0;

	// Find the branches incident on the given joint that
	// have a spoke ending at the 'old' bounadry point.
	// Then, get the endpoints opposite to the given joint and
	// save the boundary points in the same side of the 'old'
	// point (inner side) and the opposite side (outter side)
	// When there are two brances, these bndry points can be used to
	// form an interval that must include the 'new' bndry point
	forall_branches(pBranch, pJoint->getEdges())
	{
		sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();

		idx0 = GetEndpointIndex(pBranch, pJoint);
		idx1 = GetOtherEndpointIndex(pBranch, pJoint);

		// Save the bndry index of the skeletal point on the
		// **opposite** endpoint of the branch that have a
		// spoke ending at the 'old' bndry point
		if (bil[idx0].first.pt == oldBndryPt.pt) // '1' is the inner side
		{
			innerIndices[i] = bil[idx1].first.index;
			outerIndices[i] = bil[idx1].second.index;
			i++;
		}
		else if (bil[idx0].second.pt == oldBndryPt.pt) // '2' is the inner side
		{
			innerIndices[i] = bil[idx1].second.index;
			outerIndices[i] = bil[idx1].first.index;
			i++;
		}

		// If we found the two branches, then we can apply the
		// boundary interval test
		if (i == 2) 
		{
			return TestBoundaryInterval(innerIndices[0], innerIndices[1],
				outerIndices[0], outerIndices[1], newBndryPt.index);
		}
	}

	WARNING(i > 0 && i < 2, "Cannot validate point replacement");

	return true;
}

/*!
	@brief Replaces the endpoints equal to 'oldBndryPt' of each spoke incident on 
	the given junction with the new value 'newBndryPt'.

	Note that oldBndryPt cannot be a reference, because it is being changed!!!!!
*/
void BoundaryPointFinder::ReplaceBoundaryPoint(SkelJoint* pJoint, 
		                             sg::BoundaryPoint oldBndryPt /*must be a copy!*/,
						             const sg::BoundaryPoint& newBndryPt)
{
	SkelBranch* pBranch;
	SkelPtIndex idx;

	forall_branches(pBranch, pJoint->getEdges())
	{
		idx = GetEndpointIndex(pBranch, pJoint);

		sg::BoundaryInfo& bi = pBranch->getBoundaryInfoList()[idx];

		// Cumulative boundary distance should not be set already for any branch
		ASSERT(bi.first.cumBndryDist == -1 && bi.second.cumBndryDist == -1);

		if (bi.first.pt == oldBndryPt.pt)
			bi.first = newBndryPt;

		if (bi.second.pt == oldBndryPt.pt)
			bi.second = newBndryPt;
	}
}
///////////////////////////////////////////////////////////////////////////////	
	const sg::BoundaryInfo& GetTargetBoundaryInfo() const
	{
		ASSERT(m_pBranch != NULL);

		SkelPtIndex idx = GetOtherEndpointIndex(m_pBranch, m_pSrcJoint);

		return m_pBranch->getBoundaryInfo(idx);
	}

	int GetTargetBoundaryIndex() const
	{
		return GetTargetBoundaryInfo()[m_side].index;
	}

	void GetTargetBoundaryIndices(int* pInnerIdx, int* pOuterIdx) const
	{
		const sg::BoundaryInfo& bi = GetTargetBoundaryInfo();
		
		ASSERT(m_side == '1' || m_side == '2');

		*pInnerIdx = bi[m_side].index;
		*pOuterIdx = bi[GetOtherSide(m_side)].index;
	}
	
		static ReplaceBoundaryPoint(SkelBranch* pBranch, SkelJoint* pJoint, 
		char side, const sg::BoundaryPoint& newBndryPt)
	{
		SkelPtIndex i = GetEndpointIndex(pBranch, pJoint);

		sg::BoundaryInfo& bi = pBranch->getBoundaryInfo()[i];

		// Cumulative boundary distance should not be set already for any branch
		ASSERT(bi.first.cumBndryDist == -1 && bi.second.cumBndryDist == -1);

		bi[side] = newBndryPt;
	}
///////////////////////////////////////////////////////////////////////////////
		SkelBranch* pTgtBrranch;

		forall_branches(pTgtBrranch, pJoint->edges)
		{
			i = GetEndpointIndex(pTgtBrranch, pJoint);

			const sg::BoundaryInfo& bi = pTgtBrranch->getBoundaryInfo(i);

			if (bi.first.pt == bp.pt) 
			{
				Set(pTgtBrranch, pJoint, '1');
				return true;
			}
			else if (bi.second.pt == bp.pt)
			{
				Set(pTgtBrranch, pJoint, '2');
				return true;
			}
		}

		return false;
///////////////////////////////////////////////////////////////////////////////
/*SkelJoint* pJoint; 
				SkelBranch* pParBranch;

				pJoint = GetLastJoint(pBranch);
				pParBranch = FindPartnerBranch(pBranch, pJoint, side);
				bool testBP0 = TestBoundaryPointReplacement(pJoint, bp0, pParBranch);

				pJoint = GetFirstJoint(pBranch);
				pParBranch = FindPartnerBranch(pBranch, pJoint, side);
				bool testBP1 = TestBoundaryPointReplacement(pJoint, bp1, pParBranch);*/


inline PartnerBranch FindPartnerBranch(SkelBranch* pSrcBranch, 
								     SkelJoint* pJoint,
									 char side)
{
	SkelPtIndex i = GetEndpointIndex(pSrcBranch, pJoint);
	const sg::BoundaryPoint& bp = pSrcBranch->getBoundaryInfo(i)[side]; 

	SkelBranch* pTgtBrranch;

	forall_branches(pTgtBrranch, pJoint->edges)
	{
		i = GetEndpointIndex(pTgtBrranch, pJoint);

		const sg::BoundaryInfo& bi = pTgtBrranch->getBoundaryInfo(i);

		if (bi.first.pt == bp.pt) 
			return PartnerBranch(pTgtBrranch, '1', pJoint);
		else if (bi.second.pt == bp.pt)
			return PartnerBranch(pTgtBrranch, '2');
	}

	return PartnerBranch(NULL, 0);
}
///////////////////////////////////////////////////////////////////////////////
//! Returns the endpoint of pBranch that corresponds to the first flux point
inline SkelJoint* GetFirstEndpoint(SkelBranch* pBranch)
{
	ASSERT(pBranch->getFirstXYPoint() == pBranch->n1->fp.p ||
		   pBranch->getFirstXYPoint() == pBranch->n2->fp.p);

	return (pBranch->getFirstXYPoint() == pBranch->n1->fp.p) 
		? pBranch->n1 : pBranch->n2;
}

//! Returns the endpoint of pBranch that corresponds to the last flux point
inline SkelJoint* GetLastEndpoint(SkelBranch* pBranch)
{
	ASSERT(pBranch->getLastXYPoint() == pBranch->n1->fp.p ||
		   pBranch->getLastXYPoint() == pBranch->n2->fp.p);

	return (pBranch->getLastXYPoint() == pBranch->n1->fp.p) 
		? pBranch->n1 : pBranch->n2;
}

///////////////////////////////////////////////////////////////////////////////
		else if ((first == outPtIdx0 || first == outPtIdx1) || 
			     (last  == outPtIdx0 || last  == outPtIdx1))
		{
			if (outPtIdx0 != outPtIdx1)
			{
				
			}
			else
			{
				sg::Point succPt, predPt;

				m_bndryPts.GetDataPoint(pBndryInt->Succ(first), succPt.x, succPt.y);
				m_bndryPts.GetDataPoint(pBndryInt->Pred(last), predPt.x, predPt.y);

				const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();

				// If moving CW, it should be true that the successor of first
				// and the predecessor of last are endpoints of crossing spokes
				*pMoveClockwise = DoSpokesIntersect(fpl.front().p, succPt, 
					fpl.back().p, predPt);
			}
		}
		else if (pBndryInt->Inside(outPtIdx0) || pBndryInt->Inside(outPtIdx1))
		{
			pBndryInt->Swap();
			*pMoveClockwise = false;

			if (pBndryInt->Inside(outPtIdx0) || pBndryInt->Inside(outPtIdx1))
				return false;
		}
		else
		{
			*pMoveClockwise = true;
		}


///////////////////////////////////////////////////////////////////////////////
DoSegmentsIntersect();

*pMoveClockwise = !DoSpokesIntersect(fpl.front().p, predPt, fpl.back().p, succPt);

//ASSERT(!pBndryInt->Inside(outPtIdx0) && !pBndryInt->Inside(outPtIdx1));
///////////////////////////////////////////////////////////////////////////////
const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();
			sg::Point succPt, predPt;

			// we want the succesor of the boundary point to be closer to the branch's
			// back point, and the predecessor closer to the branch's front point
			int succIdx = pBndryInt->Succ(last);
			int predIdx = pBndryInt->Pred(first);

			m_bndryPts.GetDataPoint(succIdx, succPt.x, succPt.y);
			m_bndryPts.GetDataPoint(predIdx, predPt.x, predPt.y);

			double dist0a = fpl.front().p.sqDist(predPt);
			double dist1a = fpl.back().p.sqDist(succPt);

			double dist0b = fpl.front().p.sqDist(succPt);
			double dist1b = fpl.back().p.sqDist(predPt);

			if (dist0a < dist0b && dist1a < dist1b)
			{
				*pMoveClockwise = true;
			}
			else if (dist0a > dist0b && dist1a > dist1b)
			{
				*pMoveClockwise = false;
			}
			else
			{
				*pMoveClockwise = true;
				return false;
			}
///////////////////////////////////////////////////////////////////////////////
		else if ((first == outPtIdx0 || first == outPtIdx1) || 
			     (last == outPtIdx0 || last == outPtIdx1))
		{
			int predIdx = m_bndryIntervalSide1.Pred(last);

			BoundaryInterval bi(m_bndryPts.Size(), first, l);

			*pMoveClockwise = bi.Inside(predIdx);
		}
///////////////////////////////////////////////////////////////////////////////
// Evaluate distances to the succesor and predecesor and decide
			// whether the current direction (CW) is right or wrong
			sg::Point succPt, predPt;

			int succIdx = pBndryInt->Succ(last);
			int predIdx = pBndryInt->Pred(first);

			m_bndryPts.GetDataPoint(succIdx, succPt.x, succPt.y);
			m_bndryPts.GetDataPoint(predIdx, predPt.x, predPt.y);

			if (first == outPtIdx0)
			{
				BoundaryInterval bi(m_bndryPts.Size(), predIdx, outPtIdx1);

				*pMoveClockwise = bi.Inside(last);
			}
			else if (first == outPtIdx1)
			{
				BoundaryInterval bi(m_bndryPts.Size(), predIdx, outPtIdx0);

				*pMoveClockwise = bi.Inside(last);
			}
			else
			{
				const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();
				sg::Point succPt, predPt;

				// we want the succesor of the boundary point to be closer to the branch's
				// back point, and the predecessor closer to the branch's front point
				int succIdx = pBndryInt->Succ(last);
				int predIdx = pBndryInt->Pred(first);

				m_bndryPts.GetDataPoint(succIdx, succPt.x, succPt.y);
				m_bndryPts.GetDataPoint(predIdx, predPt.x, predPt.y);

				double dist0a = fpl.front().p.sqDist(predPt);
				double dist1a = fpl.back().p.sqDist(succPt);

				double dist0b = fpl.front().p.sqDist(succPt);
				double dist1b = fpl.back().p.sqDist(predPt);

				if (dist0a < dist0b && dist1a < dist1b)
				{
					*pMoveClockwise = true;
				}
				else if (dist0a > dist0b && dist1a > dist1b)
				{
					*pMoveClockwise = false;
				}
				else
				{
					*pMoveClockwise = true;
					return false;
				}
			}
///////////////////////////////////////////////////////////////////////////////
if (bi.Inside(last))
				{
					*pMoveClockwise = true;
				}
				else
				{
					*pMoveClockwise = false;
				}

				

				m_bndryPts.GetDataPoint(refPtIdx, refPt.x, refPt.y);

				*pMoveClockwise = (refPt.sqDist(succPt) < refPt.sqDist(predPt));
///////////////////////////////////////////////////////////////////////////////
(int)pTerminal->fp.p.x == 263 && (int)pTerminal->fp.p.y == 201

((int)pJoint->fp.p.x == 117 && (int)pJoint->fp.p.y == 116) || ((int)pJoint->fp.p.x == 167 && (int)pJoint->fp.p.y == 138)

///////////////////////////////////////////////////////////////////////////////
	/*if (nonLig.front()[nonLig.front().BranchLast()].p != 
		nonLig.back()[nonLig.back().BranchFirst()].p)
	{
		nonLig.reverse();
	}

	ASSERT(nonLig.front()[nonLig.front().BranchLast()].p == 
		nonLig.back()[nonLig.back().BranchFirst()].p);*/
///////////////////////////////////////////////////////////////////////////////
LigatureSegment& ls0 = testNonLig.front();
			LigatureSegment& ls1 = *ligSegs.FirstDifferentThan(it->m_pBranch, 
				testNonLig.front().m_pBranch);

			if (ls0[ls0.Last()].p == ls1[ls1.First()].p)
			{
				testNonLig.push_back(ls1);
			}
			else
			{
				ASSERT(ls0[ls0.First()].p == ls1[ls1.Last()].p);
				testNonLig.push_front(ls1);
			}
///////////////////////////////////////////////////////////////////////////////
	//BranchSegment bs0 = nonLig.front();
	//BranchSegment bs1 = nonLig.back();


	
//if (nonLig.front()[nonLig.front().BranchFirst()].p != nonLig.back().[nonLig.back().BranchLast()])
	//nonLig.reverse();
///////////////////////////////////////////////////////////////////////////////
if (!ligSegs.empty())
	{
		const LigatureSegment& ls = ligSegs.front();

		std::cout << ls.Size() << std::endl;
	}
///////////////////////////////////////////////////////////////////////////////
   /*WIN32_FIND_DATA   FAR ffd;
   DWORD nGot=0;
   pHelper->ReadDebuggeeMemory(pHelper,dwAddress,sizeof(ffd),&ffd,&nGot);
   wsprintf(pResult,"FindData found file '%s' DBG Process ID = %d",ffd.cFileName, GetCurrentProcessId());
   return S_OK;*/

	// Handle 32bit and 64bit memery addresses by doing this (pHelper->dwVersion >= 0x20000)...
	DWORDLONG qwRealAddress = pHelper->GetRealAddress(pHelper);

	DWORD nGot = 0; // number of bytes read
	
	dml::LigatureSegment ls;

	// Read the debuggee's structure
	pHelper->ReadDebuggeeMemoryEx(pHelper, qwRealAddress, sizeof(ls), &ls, &nGot);

	if (ls.m_pBranch)
	{
		wsprintf(pResult,"has branch x");
	}
	else
	{
		wsprintf(pResult,"empty branch");
	}

///////////////////////////////////////////////////////////////////////////////
/*// Handle 32bit and 64bit memery addresses by doing this (pHelper->dwVersion >= 0x20000)...
	DWORDLONG qwRealAddress = pHelper->GetRealAddress(pHelper);

	DWORD nGot = 0; // number of bytes read
	
	dml::LigatureSegment ls;

	// Read the debuggee's structure
	pHelper->ReadDebuggeeMemoryEx(pHelper, qwRealAddress, sizeof(ls), &ls, &nGot);

	if (ls.m_pBranch)
	{
		sg::FluxPoint fp;
		sg::DiscreteDivergenceSkeletonEdge branch(NULL);
		sg::DiscreteDivergenceSkeletonNode n1(fp);
		sg::DiscreteDivergenceSkeletonNode n2(fp);

		int sz = sizeof(branch);
		DWORD nWant = sizeof(void*) * 3; // sizeof(branch);

		// Read branch
		pHelper->ReadDebuggeeMemoryEx(pHelper, (DWORDLONG)ls.m_pBranch, nWant, &branch, &nGot);

		nWant = sizeof(void*) + sizeof(fp);

		// Read node 1
		pHelper->ReadDebuggeeMemory(pHelper,(DWORD)branch.n1, nWant, &n1, &nGot);

		// Read node 2
		pHelper->ReadDebuggeeMemory(pHelper,(DWORD)branch.n2, nWant, &n2, &nGot);

		wsprintf(pResult,"n1:(%d,%d) n2:(%d,%d)", (int)n1.fp.p.x, (int)n1.fp.p.y, 
			(int)n2.fp.p.x, (int)n2.fp.p.y);
	}
	else
	{
		wsprintf(pResult,"empty branch");
		//return E_FAIL;
	}*/
///////////////////////////////////////////////////////////////////////////////
/*void*& p = n1.pNodeData;
		int offset = (char)&p - (char)&n1;
		int offset2 = sizeof(n1);

		if (offset > 0)
		{
		nWant = sizeof(void*) + sizeof(fp);
		nWant = sizeof(sg::DDSkeleton*) + sizeof(fp) + 12;// + sizeof(std::vector<sg::DDSEdge*>);

		pHelper->ReadDebuggeeMemory(pHelper,(DWORD)branch.n1, nWant, &n1, &nGot); // read node 1
		pHelper->ReadDebuggeeMemory(pHelper,(DWORD)branch.n2, nWant, &n2, &nGot); // read node 2
		
		wsprintf(pResult,"n1:(%d,%d) n2:(%d,%d) %d %d %d %d %d", (int)n1.fp.p.x, (int)n1.fp.p.y, 
			(int)n2.fp.p.x, (int)n2.fp.p.y, nWant, offset, offset2, nBase, bUniStrings);
		}
		else
		{
			wsprintf(pResult,"error");
		}*/
///////////////////////////////////////////////////////////////////////////////
	/*if (!ligSegs.empty() && !semiLigSegs.empty())
	{
		// Check that the semi-ligature branches are really non-ligature. Otherwise,
		// ignore the full ligature branches
		if ((semiLigSegs.size() + nonLig.size() != 2) ||
			(semiLigSegs.size() == 1 && !AreBranchesCollinear(nonLig.front(), semiLigSegs.front())) ||
			(semiLigSegs.size() == 2 && !AreBranchesCollinear(semiLigSegs.front(), semiLigSegs.back())))
		{
			DBG_C_LOG("***ignoring full ligature branch")
			nonLig.splice(nonLig.end(), ligSegs);
		}
	}*/
	
	/*if (semiLigSegs.size() == 2 && nonLig.size() == 1)
	{
		// Test for corner branch
		if (nonLig.front().IsConvexCorner())
		{
			DBG_MSG2("IT'S A CONVEX CORNER", nonLig.front())
			
			std::swap(nonLig, ligSegs);
			bIsAnElbow = true;
		}
	}*/
///////////////////////////////////////////////////////////////////////////////
	// return an unsigned angle
	return ;

	// Since m_last >= m_first, we can get the
	sg::BoundaryInfo lastBI = operator()(m_last);


	

	//sg::BoundaryInfo lastBnryInfo = operator()(m_last);
	//sg::BoundaryInfo tgtBnryInfo = operator()(Target());

	// Init to the sum of the bndry dist on both sides
	double dist = bi.first.cumBndryDist + bi.second.cumBndryDist;




	// Add an approx to the remaining distance
	dist + tgtBnryInfo.first.pt.dist(tgtBnryInfo.second.pt);

	/*BoundaryIntervalWithGaps bi(m_pBranch, s_pBndryPtFinder->GetOriginalPoints());

	bi.SetLimits(m_first, m_last, '1'); // choose any side

	sg::BoundaryInfo bnryInfo = operator()(m_last);

	const SkelPtCoord lastPt = bnryInfo['2'].pt; // choose opposite side

	SkelPtCoord pt0, pt1;
	double maxDist = M_PI * m_dSourceRadius;
	BoundaryIntervalWithGaps::Index idx = bi.Last();

	// Init to the sum of the bndry dist on both sides
	double dist = bnryInfo['1'].cumBndryDist + bnryInfo['2'].cumBndryDist;

	bi.GetBoundaryPoint(idx, &pt0);

	// Add the cum bndry dist from the last point on one side the the last point
	// on the other side
	while (pt0 != lastPt)
	{
		bi.MoveNext(idx);
		bi.GetBoundaryPoint(idx, &pt1);

		dist += pt0.dist(pt1);

		if (dist > maxDist)
			return false;

		pt0 = pt1;
	}

	return true;*/
///////////////////////////////////////////////////////////////////////////////
/*!
	@brief Returns true if the ligature segment forms an ``elbow'' shape
*/
bool LigatureSegment::IsElbowShape() const
{
	if (!m_corner1.m_valid && m_cumBAR1.normal > 1)
	{
		return IsAxisBended(m_corner2.m_pt, '2');
	}
	else if (!m_corner2.m_valid && m_cumBAR2.normal > 1)
	{
		return IsAxisBended(m_corner1.m_pt, '1');
	}

	return false;
}

/*!
	First, we need to find the skeletal poins whose spokes end at
	the corner. However, there may be no spoke endpoint that 
	coincides exactly with the corner, so we search for the spoke
	endpoint that is closest to the corern, and then find ALL
	sekeletal points with that spoke endpoint. The maximum
	bending point is expected to be one of such skeletal points.
*/
bool LigatureSegment::IsAxisBended(const sg::Point& cornerPt, char side) const
{
	if (Size() <= 3)
		return false;

	DBG_MSG2("Testing elbow candidate found at", cornerPt)

	const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();
	double cumAlpha = 0;
	int numAlphas = 0;

	sg::Point p0 = fpl[m_first + 2].p - fpl[m_first].p;
	double p0Norm = p0.norm();

	sg::Point p1;
	double p1Norm;

	for (unsigned int i = m_first + 1; i <= m_last - 2; i++)
	{
		p1 = fpl[i + 2].p - fpl[i].p;
		p1Norm = p1.norm();

		cumAlpha += SignedVectorAngle(p0, p1, p0Norm, p1Norm);
		numAlphas++;

		p0 = p1;
		p0Norm = p1Norm;
	}

	ASSERT(numAlphas > 0);

	double avgAlpha = fabs(cumAlpha) / numAlphas;

	DBG_MSG3("Bending angle is", cumAlpha, avgAlpha)
	
	return (avgAlpha >= MIN_ELBOW_BENDING_AVG_ANGLE);
}

///////////////////////////////////////////////////////////////////////////////
		bool LigatureSegment::IsLigature(char side, bool bNormal) const
		/*if (bNormal)
			return (m_cumBAR1.normal <= s_maxCumulativeBAR &&
					m_corner1.m_cosAngle >= s_minCornerCosAngle &&
					m_corner1.m_valid);
		else // use straight BAR but stricter angle threshold
			return (m_cumBAR1.straight <= s_maxCumulativeBAR &&
					m_corner1.m_cosAngle >= s_dStrictMinCornerCosAngle &&
					m_corner1.m_valid);*/
					
				/*if (bNormal)
			return (m_cumBAR2.normal <= s_maxCumulativeBAR &&
					m_corner2.m_cosAngle >= s_minCornerCosAngle &&
				    m_corner2.m_valid);
		else // use straight BAR but stricter angle threshold
			return (m_cumBAR2.straight <= s_maxCumulativeBAR &&
					m_corner2.m_cosAngle >= s_dStrictMinCornerCosAngle &&
				    m_corner2.m_valid);*/
///////////////////////////////////////////////////////////////////////////////
void FilterNonLigatureSegments(const BranchWalkInfo& wi, iterator first);

	void GetCornerSpokes(const BoundaryCorner& bc, const CornerArea& ca, char side, 
		SkelPtIndex* pFirstSpoke, SkelPtIndex* pLastSpoke, SkelPtIndex* pCornerSpoke)
	{
		*pCornerSpoke = FindClosestPoint(bc.m_pt);

		*pFirstSpoke = FindClosestPoint(ca.first);
		*pLastSpoke  = FindClosestPoint(ca.last);

		if (*pFirstSpoke > *pLastSpoke)
			std::swap(*pFirstSpoke, *pLastSpoke);
	}


//! Finds the iterator of the i'th element in the list
iterator FindElement(unsigned int i)
{
	iterator it;
	int n;

	for (it = begin(), n = 0; it != end(); it++, n++)
	{
		if (n == i)
			break;
	}

	return it;
}

//unsigned int firstPassSize = 0;

// Reverse direction if it's the first pass or finish otherwise
if (bFirstPass)
{
	//FilterNonLigatureSegments(wi, begin());

	//firstPassSize = size();

	wi.ReverseDirection();

	bFirstPass = false;
}
else
{
	//FilterNonLigatureSegments(wi, FindElement(firstPassSize));

	break;
}
/*!
*/
void LigatureSegmentList::FilterNonLigatureSegments(const BranchWalkInfo& wi, 
													LigatureSegmentList::iterator it)
{
	bool side1Lig, side2Lig;

	while (it != end())
	{
		side1Lig = it->HasLigatureLikeAttributes('1');
		side2Lig = it->HasLigatureLikeAttributes('2');

		/*if (side1Lig && side2Lig)
		{
			LigatureSegment ls1(*it), ls2(*it);

			ls1.ShrinkToCorner(wi, '1');
			ls2.ShrinkToCorner(wi, '2');

			*it = (ls1.Size() >= ls2.Size()) ? ls1 : ls2;
		}
		else if (side1Lig)
		{
			it->ShrinkToCorner(wi, '1');
		}
		else if (side2Lig)
		{
			it->ShrinkToCorner(wi, '2');
		}*/

		// Remove segments that are not ligature and move to next
		if (it->Size() >= MIN_LIG_SEGMENT_SIZE && it->IsLigature())
			it++;
		else
			it = erase(it);
	}
}
///////////////////////////////////////////////////////////////////////////////

void ShrinkToCorner(const BranchWalkInfo& wi, char side);

/*!
	Computes boundary corner on given side and shrinks the ligature segment
	so that its first and last spoke mapt to point in the associated corner area.
*/
void LigatureSegment::ShrinkToCorner(const BranchWalkInfo& wi, char side)
{
	BoundaryIntervalWithGaps bi(m_pBranch, s_pBndryPtFinder->GetOriginalPoints());
	CornerArea ca;
	unsigned int firstSpoke, lastSpoke, cornerSpoke;

	BoundaryCorner& bc = GetCornerReference(side);

	bi.SetLimits(m_first, m_last, side);
 
	bc.FindCorner(bi, s_dMinFullLigCornerCosAngle, NULL, &ca);

	if (bc.m_valid)
	{
		GetCornerSpokes(bc, ca, side, &firstSpoke, &lastSpoke, &cornerSpoke);

		bc.m_valid = bc.IsConcaveCorner(GetPtCoord(cornerSpoke));

		/*if (bc.valid)
		{
			ASSERT(firstSpoke <= lastSpoke);

			// If it shrunk too much, don't shrink
			if (firstSpoke < lastSpoke)
			{
				if (DecreasesForward())
					SetAttributes(wi, firstSpoke, lastSpoke);
				else
					SetAttributes(wi, lastSpoke, firstSpoke);
			}
			else
			{
				DBG_MSG1("Can't shrink")
			}
		}*/
	}
}
///////////////////////////////////////////////////////////////////////////////
				/*ASSERT(ls.DecreasesForward() == bestLigSeg.DecreasesForward());

					firstIdx = MIN(ls.m_first, bestLigSeg.m_first);
					lastIdx  = MAX(ls.m_last,  bestLigSeg.m_last);

					// Indices must be given wrt decreasing direction
					if (ls.DecreasesForward())
						mergeLigSeg.SetAttributes(wi, firstIdx, lastIdx);
					else
						mergeLigSeg.SetAttributes(wi, lastIdx, firstIdx);

					if (mergeLigSeg.HasLigatureLikeAttributes())
					{
						DBG_C_LOG("Merging segments")
						bestLigSeg = mergeLigSeg;
					}
					else if (ls.Size() > bestLigSeg.Size())
					{
						DBG_C_LOG("Replacing best segment")
						bestLigSeg = ls;
					}*/
///////////////////////////////////////////////////////////////////////////////
	// Make sure that the ligature segment is not too large. This happens for some
	// inner ligature segments. However, when it's ligature associated with interpolated points,
	// ie, a regularized joint, the length is usually fine
	/*for (iterator it = begin(); it != end(); it++)
	{
		if (!it->HasInterpolatedPoints()) // don't need to shrink if pts come from interpolation
		{
			it->ShrinkToCorner();
		}
	}*/
///////////////////////////////////////////////////////////////////////////////
void GetShrinkToCornerLimits(char side, unsigned int* pFirstIdx, unsigned int* pLastIdx);

/*!
	Get the limits of the ligature segment that most compactly map to
	the detected concave corner on the given side.
*/
void LigatureSegment::GetShrinkToCornerLimits(char side, unsigned int* pFirstIdx, 
											  unsigned int* pLastIdx)
{
	const BoundaryCorner& corner = (side == '1') ? m_corner1 : m_corner2;
	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
	double minDistLeft, minDistRight, distLeft, distRight;
	unsigned int minLeftIdx, minRightIdx, maxLeftIdx, maxRightIdx;

	// Use the minimum arms to define the boundary points on the left
	// and right of the corner point to define a 'corner interval'
	// Only the spokes whose endpoints are within this interval
	// have their origin at ligature points
	const sg::Point leftPt  = corner.minLeftArm + corner.pt;
	const sg::Point rightPt = corner.minRightArm + corner.pt;

	ASSERT(corner.valid);

	// Set the minimum distances to impossible values
	minDistLeft  = -1;
	minDistRight = -1;

	// Find the pair of spokes whose endpoints are closest to
	// the left and right arms of the corner, and that map
	// to skeletal points defininf the longest ligature segment
	for (unsigned int i = m_first; i <= m_last; i++)
	{
		// Get endpoint of i'th spoke
		const sg::Point& pt = bil[i][side].pt;

		// Get distance to the endpoints of the left and right arms
		distLeft  = pt.sqDist(leftPt);
		distRight = pt.sqDist(rightPt);

		// The left and right spoke endpoinst must be different, so we must
		// associated the boundary point with either the left or the right (or none)
		// and then see if it's the closet point to that arm's endpoint
		if (distLeft <= distRight) // the point is closer to the left arm's endpoint
		{
			// See is spoke endpoin is the closest to the left arm's endpoint
			if (minDistLeft == -1 || distLeft < minDistLeft)
			{
				minDistLeft = distLeft;
				minLeftIdx = i; // update the smallest index found...
				maxLeftIdx = i; // and the largest index found
			}
			else if (distLeft == minDistLeft)
			{
				// When there are several 'closest' points, we
				// want the spoke whose origin the skeletal point
				// that is nearest the ligature segment's endpoints
				if (i < minLeftIdx) minLeftIdx = i; // store smallest i'th
				if (i > maxLeftIdx) maxLeftIdx = i; // store largest i'th
			}
		}
		else // the point is closer to the left arm's endpoint
		{
			// See is spoke endpoint is the closest to the right arm's endpoint
			if (minDistRight == -1 || distRight < minDistRight)
			{
				minDistRight = distRight;
				minRightIdx = i; // update the smallest index found...
				maxRightIdx = i; // and the largest index found
			}
			else if (distRight == minDistRight)
			{
				// When there are several 'closest' points, we
				// want the spoke whose origin the skeletal point
				// that is nearest the ligature segment's endpoints
				if (i < minRightIdx) minRightIdx = i; // store smallest i'th
				if (i > maxRightIdx) maxRightIdx = i; // store largest i'th
			}
		}
	}

	// If we have to well-defined spokes whose enpoint are close to
	// the left and the right arm's endpoint, then we use the most compact
	// indices Otherwise, we simply use the original first and last indices.
	if (minDistLeft != -1 && minDistRight != -1)
	{
		// Assign the smallest i'th of a valid spoke to the first index
		// and the largest to the last index
		ASSERT((MAX(maxLeftIdx, maxRightIdx) - MIN(minLeftIdx, minRightIdx) + 1) >= 2);

		*pFirstIdx = MIN(minLeftIdx, minRightIdx);
		*pLastIdx  = MAX(maxLeftIdx, maxRightIdx);
	}
	else
	{
		*pFirstIdx = m_first;
		*pLastIdx  = m_last;
	}
}

/*!
	It happens some times that the ligature segment is too long.
	Originally, it is found without knowledge of the boundary
	corner(s) associated with it, so this problem is har to prevent.
	However, once we've found the corner, it makes sense to
	use the information to correct the legth of the ligature.
*/
void LigatureSegment::ShrinkToCorner()
{
	ASSERT(m_corner1.valid || m_corner2.valid);

	if (m_corner1.valid && m_corner2.valid)
	{
		unsigned int first1, last1, first2, last2;

		GetShrinkToCornerLimits('1', &first1, &last1);
		GetShrinkToCornerLimits('2', &first2, &last2);

		if (last1 - first1 > last2 - first2)
		{
			m_first = first1;
			m_last = last1;
		}
		else
		{
			m_first = first2;
			m_last = last2;
		}
	}
	else
	{
		GetShrinkToCornerLimits((m_corner1.valid) ? '1' : '2', 
			&m_first, &m_last);
	}
}
///////////////////////////////////////////////////////////////////////////////
/*!
	@brief Finds all ligature segments within the given branch segment. A heading
	or trailing ligature segtent is considered to be a "rooted" ligature, and
	so its associated joint is set. Otherwise, this joint is set to NULL.

	@param minLigSegSize minimum size of a ligatiure segment (3 is a good value here)
	@param minNonLigSegSize minimum size of a non-ligature segment (3 is a good value here)
*/
bool LigatureSegmentList::FindLigatureSegments(const BranchSegment& bs)
{
	clear();

	if (bs.Size() < 2 || bs[bs.First()].p.dist(bs[bs.Last()].p) < 1) 
		return false;

	BranchWalkInfo wi(bs, true);
	LigatureSegment ls, bestLigSeg;
	unsigned int i, bestSz;
	bool bOverlappingState/*, bIsSubsegment*/;
	bool bFirstPass = true;

	ls.m_pBranch = bs.m_pBranch;

	DBG_C_LOG_BEGIN_GROUP
	//DBG_C_LOG(DBG_VAL(minLigSegSize) << DBG_VAL(minNonLigSegSize))
	//DBG_PRINT2(ls.m_pBranch->n1->fp.p.x, ls.m_pBranch->n2->fp.p.x)

	while (true)
	{
		// Keep track of the overlaps between ligature segments. If the beggining of 
		// a 'candidate' ligature segment is within the limits of a previously found
		// ligature, then there is overlap bettwen the segments.
		bOverlappingState = false;

		// Eveluate every point in the given branch segment as a potential start of
		// a ligature segment
		for (i = wi.First(); i != wi.Last(); i += wi.Inc())
		{
			// Check for a change in the overlapping state from true to 'outside of range'
			if (bOverlappingState && !bestLigSeg.IsInside(i))
			{
				// Flush current best ligature segment
				if (bestLigSeg.m_dRadiusRatio <= LigatureSegment::s_maxRadiusRatio)
				{
					push_back(bestLigSeg);
					DBG_C_LOG("*** Adding " << DBG_VAL(bestLigSeg.First()) << DBG_VAL(bestLigSeg.Last()))
				}
				else
				{
					DBG_C_LOG("*** Fails radius ratio test" << DBG_VAL(bestLigSeg.m_dRadiusRatio))
				}

				// Update the overlapping state to false
				bOverlappingState = false;
			}

			// Evalueate the ligature segment that begins at point i
			ls.FindLigature(wi, i);

			/*if (bOverlappingState)
				bIsSubsegment = (bestLigSeg.IsInside(ls.First()) && bestLigSeg.IsInside(ls.Last()));
			else
				bIsSubsegment = false;*/
			
			// If ligature overlaps previous one, keep the largest
			if (ls.Size() >= MIN_LIG_SEGMENT_SIZE
				&& (ls.IsFullLigature() || ls.IsSemiLigature())
				&& (!bOverlappingState /*|| ls.Size() > bestSz*/ /*|| bIsSubsegment*/))
			{
				bestLigSeg = ls;
				bestSz = ls.Size();
				bOverlappingState = true;
			}
		}

		// Flush the possibly remaining best segment
		if (bOverlappingState)
		{
			if (bestLigSeg.m_dRadiusRatio <= LigatureSegment::s_maxRadiusRatio)
			{
				push_back(bestLigSeg);
				DBG_C_LOG("*** Adding " << DBG_VAL(bestLigSeg.First()) << DBG_VAL(bestLigSeg.Last()))
			}
			else
			{
				DBG_C_LOG("*** Fails radius ratio test" << DBG_VAL(bestLigSeg.m_dRadiusRatio))
			}
		}

		// Reverse direction if it's the first pass or finish otherwise
		if (bFirstPass)
		{
			wi.ReverseDirection();
			bFirstPass = false;
			DBG_C_LOG("Reversing search direction")
		}
		else
			break;
	}

	// Make sure that the ligature segment is not too large. This happens for some
	// inner ligature segments. However, when it's ligature associated with interpolated points,
	// ie, a regularized joint, the length is usually fine
	/*for (iterator it = begin(); it != end(); it++)
	{
		if (!it->HasInterpolatedPoints()) // don't need to shrink if pts come from interpolation
		{
			it->ShrinkToCorner();
		}
	}*/

	sort(CompareBranchSegment());
	
	//iterator it1 = begin();
	//iterator it0 = it1++;

	// Check for strange overlaps of segments (can happen in some weird cases)
	for (iterator it0, it1 = begin(); it1 != end(); /*it1 is aleary incremented*/)
	{
		it0 = it1++;

		if (it1 != end() && it0->Last() >= it1->First())
		{
			DBG_C_LOG("WARNING: there is a weird overlap of ligature segments")
			erase(it1);
			erase(it0);
			it1 = begin(); // start again
		}
		else if (it1 != end() && it0->Last() + 1 == it1->First())
		{
			DBG_C_LOG("WARNING: ligature segments define an empty bone")
			
			// Define a non-empty bone by shrinking either the non-terminal segment
			// or, if both are non-terminal, the longest one.
			bool terminal0 = (it0->First() == it0->BranchFirst());
			bool terminal1 = (it1->Last() == it1->BranchLast());

			ASSERT(it0->Size() > 1 && it1->Size() > 1);

			if (terminal0 && !terminal1)
				it1->m_first++;
			else if (!terminal0 && terminal1)
				it0->m_last--;
			else if (it0->Size() < it1->Size())
				it1->m_first++;
			else
				it0->m_last--;
		}
	}

	if (!empty())
	{
		// If the first point of the segment is a joint, there may be an instability in the labeling that
		// can be easily corrected by ignoring these labels.
		// First, remove small non-lig segments at the front of the list...
		if (bs.First() == bs.BranchFirst() && front().m_first != bs.BranchFirst() &&
			front().DecreasesForward() && bs.BranchFirstPtDegree() > 1)
		{
			BranchSegment nonLig(bs.m_pBranch, bs.First(), front().m_first - 1);

			if (nonLig.Size() == 1 || nonLig.IsCornerSegment(true))
			{
				front().m_first = bs.First();
				DBG_C_LOG("WARNING: heuristicaly ignoring front non-lig joint point")
			}
		}

		// ...then, remove small non-lig segments at the back of the list
		if (bs.Last() == bs.BranchLast() && back().m_last != bs.BranchLast() &&
			back().DecreasesBackwards() && bs.BranchLastPtDegree() > 1)
		{
			BranchSegment nonLig(bs.m_pBranch, back().m_last + 1, bs.Last());

			if (nonLig.Size() == 1 || nonLig.IsCornerSegment(false))
			{
				back().m_last = bs.Last();
				DBG_C_LOG("WARNING: heuristicaly ignoring back non-lig joint point")
			}
		}

		// Finally, ignore whole ligature branches
		if (front().m_first == bs.First() && front().m_last == bs.Last())
		{
			clear();
			DBG_C_LOG("WARNING: heuristicaly ignoring whole lig branch")
		}
		else if (front().m_first == bs.BranchFirst())
		{
			if (GetFirstJoint(bs.m_pBranch)->degree() > 1)
				front().m_pJoint = GetFirstJoint(bs.m_pBranch); // rooted ligature
			else
				pop_front(); // lig ends at terminal point
		}
		else if (back().m_last == bs.BranchLast())
		{
			if (GetLastJoint(bs.m_pBranch)->degree() > 1)
				back().m_pJoint = GetLastJoint(bs.m_pBranch); // rooted ligature
			else
				pop_back(); // lig ends at terminal point
		}
	}

	DBG_C_LOG(DBG_VAL(size()))

	return !empty();
}
///////////////////////////////////////////////////////////////////////////////
/*!
	@brief Walks along the branch points, starting from 'first' in the direction
	given by 'wi'. It ends the walk at a point that corresponds to the endpoint j
	of a possible ligature segment [first, j]. This segment may or mey not be
	a ligature segment. Call any if the Is(*)Ligature() function to determine
	whether the given segment is ligature.

	The end of the ligature segment must be a point with smaller radius and with a 
	circle that intersects that of the root at pi/2 angle wrt the line conecting the
	center of the circles. We don't need to search through points at distance > r0.
*/
void LigatureSegment::FindLigature(const BranchWalkInfo& wi, unsigned int first)
{
	double r0, r0r0, r1, dist2;
	unsigned int i, j;
	
	ASSERT(first != wi.Last());

	i    = first;
	r0   = wi.Radius(i);
	r0r0 = r0 * r0;

	for (j = i + wi.Inc(); j != wi.Last(); j += wi.Inc())
	{
		r1    = wi.Radius(j + wi.Inc());
		dist2 = wi.SquaredDistance(i, j + wi.Inc());

		// We want a point in which the cos(circle intersection spoke angle) is >= 0
		// since: cosAlpha = (r1 * r1 + dist2 - r0r0) / (2 * r1 * sqrt(dist2));
		// we can simply check whether (r1 * r1 + dist2) >= r0r0.

		// We want the current point j, and not j + inc
		if ((r1 < r0 && (r1 * r1 + dist2) >= r0r0 && (wi.Radius(j) / r0) <= s_maxRadiusRatio) 
			|| dist2 >= r0r0)
		{
			SetLigatureAttributes(wi, i, j);
			break;	
		}
	}

	// If we didn't reach the break, we still need to set the attributes
	if (j == wi.Last())
		SetLigatureAttributes(wi, i, j);

	DBG_C_LOG(DBG_VAL(wi.FirstPtCoord()) << DBG_VAL(wi.LastPtCoord()))
	DBG_C_LOG(DBG_VAL(first) << DBG_VAL(wi.Last()) << DBG_VAL(j))

	bool bFullLigature = IsFullLigature();

	DBG_C_LOG(DBG_VAL(bFullLigature) << 
		DBG_VAL(m_cumBAR1.straight) << DBG_VAL(m_cumBAR2.straight) <<
		DBG_VAL(m_corner1.cosAngle) << DBG_VAL(m_corner2.cosAngle))

	// If we found a full ligature segment, we are done. If not, we need to keep
	// searching for semiligature...

	// ...if we have semi-ligature but don't have a corresponding corner, we try find one
	// while maintaining or reducing the BAR mesure of the semi-ligature
	if (j != wi.Last() && !bFullLigature && 
		(m_cumBAR1.normal <= s_maxCumulativeBAR || m_cumBAR2.normal <= s_maxCumulativeBAR) && 
		(m_corner1.cosAngle < s_dMinSemiLigCornerCosAngle && 
		 m_corner2.cosAngle < s_dMinSemiLigCornerCosAngle))
	{
		LigatureSegment ls = *this;
		double newBAR; //oldBAR; 
		int n = 0;
		
		//oldBAR = MIN(m_cumBAR1.normal, m_cumBAR2.normal);

		DBG_C_LOG("Searching for a valid corner to define semi-ligature...")

		for (unsigned int k = j + wi.Inc(); wi.SizeToLast(k) >= 2; k += wi.Inc())
		{
			ls.SetLigatureAttributes(wi, i, k);
			newBAR = MIN(ls.m_cumBAR1.normal, ls.m_cumBAR2.normal);

			if (n++ >= 5 || newBAR > s_maxCumulativeBAR)
			{
				DBG_C_LOG("Cannot find corner. Max BAR reached " << DBG_VAL(newBAR))
				break;
			}

			//oldBAR = newBAR;

			if (ls.m_corner1.cosAngle >= s_dMinSemiLigCornerCosAngle || 
				ls.m_corner2.cosAngle >= s_dMinSemiLigCornerCosAngle)
			{
				DBG_C_LOG("Valid corner is found")
				*this = ls;
				j = k;
				break;
			}
		}
	}

	// if we have semi-ligature and a valid corner, then we try extending it as much as possible
	if (j != wi.Last() && !bFullLigature && 
		((m_cumBAR1.normal <= s_maxCumulativeBAR && m_corner1.cosAngle >= s_dMinSemiLigCornerCosAngle) || 
		 (m_cumBAR2.normal <= s_maxCumulativeBAR && m_corner2.cosAngle >= s_dMinSemiLigCornerCosAngle)))
	{
		sg::Point pt0, pt1;

		char side = FindBoundaryCut(&pt0, &pt1);

		DBG_C_LOG("Extending possible semiligature related to corner at " DBG_VAL(pt0))

		const unsigned int old_j = j;
		double dist, minDist = wi.Distance(j, pt0) + wi.Distance(j, pt1);

		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

		for (unsigned int k = j + wi.Inc(); wi.SizeToLast(k) >= 2; k += wi.Inc())
		{
			dist = wi.Distance(k, pt0) + wi.Distance(k, pt1);

			if (dist < minDist && bil[k][side].pt.sqDist(pt0) <= bil[j][side].pt.sqDist(pt0))
			{
				j = k;
				minDist = dist;
			}
		}

		// Update attributes if j changed
		if (j != old_j)
			SetLigatureAttributes(wi, i, j);
	}

	DBG_C_LOG(DBG_VAL(i) << DBG_VAL(j))
}
///////////////////////////////////////////////////////////////////////////////
static bool IsConcaveCorner(const BoundaryCorner& bc, const sg::Point& pt);

/*!
	Checks that the given boundary corner 'bc' is concave wrt the 
	given point skeletal point 'skelPt'

	\image html IsConcaveCorner.gif
*/
/*static*/ bool LigatureSegment::IsConcaveCorner(const BoundaryCorner& bc, 
												 const sg::Point& skelPt)
{
	sg::Point intPt;

	int rv = FindLineSegmentIntersection(skelPt, bc.pt, bc.LeftEndpoint(), 
		bc.RightEndpoint(), &intPt);

	// if rv == 2, it means that the segments overlap over several points, which 
	// should not happen
	ASSERT(rv != 2);

	// If both segments intersect (ie, rv == 1), then the corner is NOT concave
	return (rv != 1);
}
///////////////////////////////////////////////////////////////////////////////
/*!
	Get the limits of the ligature segment that most compactly map to
	the detected concave corner on the given side.
*/
void LigatureSegment::GetShrinkToCornerLimits(char side, unsigned int* pFirstIdx, 
											  unsigned int* pLastIdx)
{
	const BoundaryCorner& corner = (side == '1') ? m_corner1 : m_corner2;
	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
	double minDistLeft, minDistRight, distLeft, distRight;
	unsigned int minLeftIdx, minRightIdx, maxLeftIdx, maxRightIdx;

	// Use the minimum arms to define the boundary points on the left
	// and right of the corner point to define a 'corner interval'
	// Only the spokes whose endpoints are within this interval
	// have their origin at ligature points
	const sg::Point leftPt  = corner.minLeftArm + corner.pt;
	const sg::Point rightPt = corner.minRightArm + corner.pt;

	ASSERT(corner.valid);

	// Find the first and last spoke whose endpoint is within
	// the 'corner interval'
	for (unsigned int i = m_first; i <= m_last; i++)
	{
		// Get endpoint of i'th spoke
		const sg::Point& pt = bil[i][side].pt;

		distLeft = pt.sqDist(leftPt);

		if (i == m_first || distLeft < minDistLeft)
		{
			minDistLeft = distLeft;
			minLeftIdx = i;
			maxLeftIdx = i;
		}
		else if (distLeft == minDistLeft)
		{
			if (i < minLeftIdx) minLeftIdx = i;
			if (i > maxLeftIdx) maxLeftIdx = i;
		}

		distRight = pt.sqDist(rightPt);

		if (i == m_first || distRight < minDistRight)
		{
			minDistRight = distRight;
			minRightIdx = i;
			maxRightIdx = i;
		}
		else if (distRight == minDistRight)
		{
			if (i < minRightIdx) minRightIdx = i;
			if (i > maxRightIdx) maxRightIdx = i;
		}
	}

	// Assign pts at the end as ptrs may point to m_first or m_last
	*pFirstIdx = MIN(minLeftIdx, minRightIdx);
	*pLastIdx  = MAX(maxLeftIdx, maxRightIdx);
}
///////////////////////////////////////////////////////////////////////////////
/*!
	@brief Finds the smallest angle with the boundary interval defined by
	the spokes of the given pair of skeletal points. The maximum
	scale of the "corner" is given by the squared distance 'maxSqDist'.

	@return pCornerInfo is filled in with corner attributes.
*/
void BoundaryCorner::FindCorner(const BoundaryIntervalWithGaps& bi,
								const double& minCornerCosAngle)
{
	BoundaryIntervalWithGaps::Index idx, left, right;
	BPList pts;
	BPIterator firstIt, lastIt;
	sg::Point pt;
	unsigned int n, minNumPts, maxNumPts;

	ASSERT(bi.IsValid());

	// Add all pts in bi0 to the list
	bi.GetBoundaryPoints(&pts, bi.First(), bi.Last());

	firstIt = pts.begin();
	lastIt  = pts.end();
	lastIt--;

	minNumPts = MAX(pts.size() * 0.5, 2);
	maxNumPts = pts.size();

	for (idx = bi.Prev(bi.First()), n = 0; /* true */; bi.MovePrev(idx), n++)
	{
		bi.GetBoundaryPoint(idx, &pt);
		pts.push_front(pt);

		// Make sure that we have enough points to define one arm, and if so
		// check that idx is within bnry pts assoc with current branch
		if (n >= minNumPts && n >= maxNumPts)
			break;
	}

	for (idx = bi.Next(bi.Last()), n = 0; /* true */; bi.MoveNext(idx), n++)
	{
		bi.GetBoundaryPoint(idx, &pt);
		pts.push_back(pt);
		
		// Make sure that we have enough points to define one arm, and if so
		// check that idx is within bnry pts assoc with current branch
		if (n >= minNumPts && n >= maxNumPts)
			break;
	}

	FindCorner(pts, firstIt, lastIt, minNumPts * minNumPts,
		maxNumPts * maxNumPts, minCornerCosAngle);
}

/*!
	The problem is to walk along the boundary points. This cannot be done
	by walking along the skeletal points and following their spokes, as
	the endpoints of adjacent spokes need not be adjacent.
*/
void BoundaryCorner::FindCorner(const BoundaryIntervalWithGaps& bi0,
								const BoundaryIntervalWithGaps& bi1,  
								const double& minCornerCosAngle)
{
	BoundaryIntervalWithGaps::Index idx, br0Idx, br1Idx;
	BPList pts;
	BPIterator firstIt, lastIt;
	sg::Point pt;
	unsigned int sz0, sz1, n, minNumPts, maxNumPts;

	ASSERT(bi0.IsValid() && bi1.IsValid());

	//ASSERT(bi0.LastPoint() == bi1.FirstPoint());
	DBG_C_LOG("Searching for corners within " << bi0.FirstPoint() << ", "
		<< bi0.LastPoint() << ", "<< bi1.FirstPoint() << ", " << bi1.LastPoint())

	// Add all pts in bi0 to the list
	bi0.GetBoundaryPoints(&pts, bi0.First(), bi0.Last());
	pts.pop_back();   // remove last point, because will be added again bellow
	sz0 = pts.size(); // get the num of "unique" points

	// Add all pts in bi1 to the list
	bi1.GetBoundaryPoints(&pts, bi1.First(), bi1.Last());
	sz1 = pts.size() - sz0;

	// We can now extend the chain of points to provide room for the sides
	// of the triangle defined inscribed at a corner. First, save the limits
	// of the interval where the corner must be in.
	ASSERT(!pts.empty());
	firstIt = pts.begin();
	lastIt  = pts.end();
	lastIt--;

	minNumPts = 2; //(sz0 + sz1) * 0.25;
	maxNumPts = sz0 + sz1;

	// Add poins to the left
	bi0.GetBranchBndryLimits(&br0Idx, &br1Idx);

	for (idx = bi0.Prev(bi0.First()), n = 0; /* true */; bi0.MovePrev(idx), n++)
	{
		bi0.GetBoundaryPoint(idx, &pt);
		pts.push_front(pt);

		// Make sure that we have enough points to define one arm, and if so
		// check that idx is within bnry pts assoc with current branch
		if (n >= minNumPts && (idx == br0Idx || idx == br1Idx || n >= maxNumPts))
			break;
		}

	// Add poins to the left
	bi1.GetBranchBndryLimits(&br0Idx, &br1Idx);

	for (idx = bi1.Next(bi1.Last()), n = 0; /* true */; bi1.MoveNext(idx), n++)
	{
		bi1.GetBoundaryPoint(idx, &pt);
		pts.push_back(pt);
		
		// Make sure that we have enough points to define one arm, and if so
		// check that idx is within bnry pts assoc with current branch
		if (n >= minNumPts && (idx == br0Idx || idx == br1Idx || n >= maxNumPts))
			break;
		}

	FindCorner(pts, firstIt, lastIt, minNumPts * minNumPts,
		maxNumPts * maxNumPts, minCornerCosAngle);
}
///////////////////////////////////////////////////////////////////////////////
/*!
	@brief Finds the smallest angle with the boundary interval defined by
	the spokes of the given pair of skeletal points. The maximum
	scale of the "corner" is given by the squared distance 'maxSqDist'.

	@return pCornerInfo is filled in with corner attributes.
*/
void BoundaryCorner::FindCorner(KDTree& bndryPts, const SkelBranch* pBranch, char side, 
								SkelPtIndex skelPt0, SkelPtIndex skelPt1,
								const double& maxSqDist, const double& minCornerCosAngle)
{
	BoundaryIntervalWithGaps bi(pBranch, bndryPts);
	BoundaryIntervalWithGaps::Index left, right;
	sg::Point p0, p1;
	const unsigned int maxNumPixels = MAX_NUM_POINTS_TO_TEST;
	unsigned numPixels;

	if (!bi.IsValid())
	{
		Clear();
		return;
	}

	bi.SetLimits(skelPt0, skelPt1, side);

	numPixels = 0;

	// Find the expanded "left" side of the interval
	bi.GetBoundaryPoint(bi.First(), &p0);

	for (left = bi.Prev(bi.First()); left != bi.Last(); bi.MovePrev(left))
	{
		bi.GetBoundaryPoint(left, &p1);

		if (p0.sqDist(p1) > maxSqDist || ++numPixels > maxNumPixels)
			break;
	}

	// 'left' is now the index of the leftmost point that will be visited

	WARNING(numPixels > maxNumPixels, "Maximum corner radius reached");

	// Find the expanded "right" side of the interval
	bi.GetBoundaryPoint(bi.Last(), &p0);

	numPixels = 0;

	for (right = bi.Next(bi.Last()); right != left; bi.MoveNext(right))
	{
		bi.GetBoundaryPoint(right, &p1);

		if (p0.sqDist(p1) > maxSqDist || ++numPixels > maxNumPixels)
			break;
	}

	// 'right' is now the index of the rightmost point that will be visited

	WARNING(numPixels > maxNumPixels, "Maximum corner radius reached");

	// Find a corner in the interval 'bi' with arms in the larger interval [left,right]
	FindCorner(bi, maxSqDist, left, right, minCornerCosAngle);	
}

/*!
	@brief Finds a concave corner in the interval [bi.First(), bi.Last()]
	by inscrbing a triangle with the "main" vertex at the corner, and the
	two other vertices in the intervals [left, bi.First()), and 
	(bi.Last(), right], respectively. The "main" vertex with smallest angle
	is selected as the concave corner.

	There is an instability in the definition of limits for the sides of the 
	inscribed triangle. It may happen that the endpoints of such sides or 
	"arms" go over some neighbouring corner, and lead to a false positive 
	for corners in [bi.First(), bi.Last()].	One solution to this problem is 
	to used the given limits [left, right] for the arms, find corners in 
	[bi.First(), bi.Last()], and then see whether we can find a corner 
	outside [bi.First(), bi.Last()], but within [left,right]. If that's the 
	case, we must shrink the interval [left,right] so that it EXCLUDES the 
	outside corner, and search again the interval [bi.First(), bi.Last()] 
	for corners using the new [left,right] limits for the inscribed triangles.
*/
void BoundaryCorner::FindCorner(const BoundaryIntervalWithGaps& bi, 
								const double& maxSqDist, 
								BoundaryIntervalWithGaps::Index& left,
								BoundaryIntervalWithGaps::Index& right,
								const double& minCCA)
{
	BoundaryCorner bc;
	BoundaryIntervalWithGaps::Index idx, nullIdx;

	const BoundaryIntervalWithGaps::Index lastIdx = bi.Next(bi.Last());

	this->cosAngle = -1;
	nullIdx.SetNull();



	// Search for the minimum angle (ie, maximum cos(angle)) within the 
	// interval [First(), Last()]
	for (idx = bi.First(); idx != lastIdx; bi.MoveNext(idx))
	{
		bc.ComputeMinimumAngle(bi, idx, maxSqDist, left, right, minCCA);

		if (bc.cosAngle >= this->cosAngle)
			*this = bc;
	}

	bool bIsMaxCosAngleOutside = false;

	// Search for a cosangle greater than cosAngle in the left open interval (left, First())
	for (idx = bi.Prev(bi.First()); idx != left; bi.MovePrev(idx))
	{
		bc.ComputeMinimumAngle(bi, idx, maxSqDist, nullIdx, nullIdx, minCCA);

		if (bc.cosAngle > this->cosAngle)
		{
			left = idx; // update the left limit
			bIsMaxCosAngleOutside = true;
			break;
		}
	}

	// Search for a cosangle greater than cosAngle in the right open interval (Last(), right)
	for (idx = bi.Next(bi.Last()); idx != right; bi.MoveNext(idx))
	{
		bc.ComputeMinimumAngle(bi, idx, maxSqDist, nullIdx, nullIdx, minCCA);

		if (bc.cosAngle > this->cosAngle)
		{
			right = idx; // update the right limit
			bIsMaxCosAngleOutside = true;
			break;
		}
	}

	/*DBG_C_LOG(DBG_VAL(bi) << DBG_VAL(left) << DBG_VAL(right) << DBG_VAL(maxSqDist)
		<< DBG_VAL(maxCosAngleIdx) << DBG_VAL(maxCosAngle)
		<< DBG_VAL(pCornerInfo->index) << DBG_VAL(pCornerInfo->angle))*/

	// If there is a greater cos(angle) in the extended interval. Call the function
	// rcursively with the updated indices left and right
	if (bIsMaxCosAngleOutside)
		FindCorner(bi, maxSqDist, left, right, minCCA);
}

/*!
	@brief Compute the minimum angle and boundary point i by inscribing
	a triangle. Each arm of the triangle has a maximim length of sqrt(maxSqDist)
	and a minimum length of sqrt(s_dBndryCornerMinSqDist).

	In addition to the maximum length, exclusion limit points can be specified for the
	left and right arm. In this case, the search for the best arms will stop as soon as 
	the exclusion limit points are found. The search for the arms' endpoints begins from 
	the closest valid poinst and continues outwards.

	The exclusion limits can be ignored be setting either or both of them to the null 
	index using the Index's member function SetNull().

	@return fills the pt, angle, leftArm and rightArm fields of the 
            BoundaryCorner structure given by the out parameter pCornerInfo.
*/
void BoundaryCorner::ComputeMinimumAngle(const BoundaryIntervalWithGaps& bi,
										 const BoundaryIntervalWithGaps::Index& idx,
										 const double& maxSqDist, 
										 const BoundaryIntervalWithGaps::Index& exLimLeft,
										 const BoundaryIntervalWithGaps::Index& exLimRight,
										 const double& minCornerCosAngle)
{
	double cosAlpha, p0Norm2, p0Norm;
	BoundaryIntervalWithGaps::Index left, right;
	sg::Point p0;

	this->cosAngle = -1;
	this->valid = false;

	bi.GetBoundaryPoint(idx, &this->pt);
	
	DBG_ONLY(int i = 0)

	std::list< std::pair<sg::Point, double> > rightPoints;
	std::list< std::pair<sg::Point, double> >::const_iterator it;

	// Find all points on the right that provide a valid "arm" endpoint and store them
	for (right = bi.Next(idx); right != idx && right != exLimRight; bi.MoveNext(right))
	{
		DBG_ONLY(i++)
		
		bi.GetBoundaryPoint(right, &p0);
		p0 -= this->pt;
		p0Norm2 = p0.sqNorm();

		if (p0Norm2 < s_dBndryCornerMinSqDist)
			continue;

		if (p0Norm2 > maxSqDist)
			break;

		rightPoints.push_back(std::make_pair(p0, sqrt(p0Norm2)));
	}

	//DBG_STREAM_IF("Corner search: too many points (" << i 
	//		<< ") on the right of " << pt << " [idx:" << idx.bndryPointIdx << "]", i >= 30)

	DBG_ONLY(i = 0)

	// Find all points on the left that provide a valid "arm" endpoint and compute
	// the angle between the left and right arms. Save the maximum cos angle (ie, min angle)
	for (left = bi.Prev(idx); left != idx && left != exLimLeft; bi.MovePrev(left))
	{
		DBG_ONLY(i++)
		
		bi.GetBoundaryPoint(left, &p0);

		p0 -= this->pt;
		p0Norm2 = p0.sqNorm();

		if (p0Norm2 < s_dBndryCornerMinSqDist)
			continue;

		if (p0Norm2 > maxSqDist)
			break;

		p0Norm = sqrt(p0Norm2);

		for (it = rightPoints.begin(); it != rightPoints.end(); it++)
		{
			cosAlpha = p0.dot(it->first) / (p0Norm * it->second);

			if (cosAlpha > this->cosAngle)
			{
				this->cosAngle = cosAlpha;
				this->leftArm  = p0;
				this->rightArm = it->first;
			}

			// Record the first (shortest) pair of arms that make the
			// corner a "valid" concave corner
			if (!this->valid && cosAlpha >= minCornerCosAngle)
			{
				this->minLeftArm  = p0;
				this->minRightArm = it->first;
				this->valid = true;
			}
		}
	}

	//DBG_STREAM_IF("Corner search: too many points (" << i 
	//		<< ") on the left of " << pt << " [idx:" << idx.bndryPointIdx << "]", i >= 30)
}

///////////////////////////////////////////////////////////////////////////////
void BoundaryCorner::FindCorner(BPList& pts, BPIterator left, BPIterator right, 
								const double& maxSqDist, const double& minCCA)
{
	BoundaryCorner bc;
	BPIterator it;

	this->cosAngle = -1; // init to widest angle

	if (pts.empty())
		return;

	//DBG_C_LOG("Searching for corners within " << *left << ", " << *right)

	// Search for the minimum angle (ie, maximum cos(angle)) within the 
	// interval [First(), Last()]
	for (it = left; /* true */; it++)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
			*this = bc;

		if (it == right)
			break;

		ASSERT(it != pts.end());
	}

	const unsigned int originalNumPts = pts.size();

	// See if there is a corner within the left margin [begin,left). Start from the 
	// points closer to the 'left' limit. If there is a corner, remove all margin
	// points to its left, in order to avoid having a left "arm" that goes over it
	for (it = left, --it; /* true */; --it)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
		{
			// Remove pts in the interval [begin(), it)
			pts.erase(pts.begin(), it);
			ASSERT(pts.begin() == it);
			break;
		}

		if (it == pts.begin())
			break;
	}

	// See if there is a corner within the left margin (right,end). Start from the 
	// points closer to the 'left' limit. If there is a corner, remove all margin
	// points to its left, in order to avoid having a left "arm" that goes over it
	for (it = right, ++it; it != pts.end(); ++it)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
		{
			// Remove pts in the interval (it, end())
			it++;

			if (it != pts.end())
				pts.erase(it, pts.end());

			break;
		}
	}

	if (pts.size() < originalNumPts)
	{
		DBG_C_LOG("Restarting the searching for corners")
		//FindCorner(pts, left, right, maxSqDist, minCCA);
	}
}
///////////////////////////////////////////////////////////////////////////////
/*! 
		Forms valid boundary intervals for all the points on each branch side
		and determines whether the boundary points, on eithr side of the branch,
		should be visited clock-wise or counter clock-wise, when moving
		from the first branch point to the last branch point.
	*/
	void SetBoundaryIntervals()
	{
		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

		const int first1 = GetBoundaryIndex(bil.front(), '1');
		const int last1  = GetBoundaryIndex(bil.back(), '1');
		const int first2 = GetBoundaryIndex(bil.front(), '2');
		const int last2  = GetBoundaryIndex(bil.back(), '2');

		const int numPts = m_bndryPts.Size();

		// Set the interval associated with the first side
		m_bndryIntervalSide1.Set(numPts, first1, last1);
		
		if (first1 == last1)
		{
			const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();

			// we want the succesor of th boundary point to be closer to the branch's
			// back point, and the predecessor closer to the branch's front point
			int succIdx = m_bndryIntervalSide1.Succ(last1);
			int predIdx = m_bndryIntervalSide1.Pred(first1);

			sg::Point succPt, predPt;

			m_bndryPts.GetDataPoint(succIdx, succPt.x, succPt.y);
			m_bndryPts.GetDataPoint(predIdx, predIdx.x, predIdx.y);

			double dist0a = fpl.front().p.sqDist(predIdx);
			double dist1a = fpl.back().p.sqDist(succPt);

			double dist0b = fpl.front().p.sqDist(succPt);
			double dist1b = fpl.back().p.sqDist(predIdx);

			if (dist0a < dist0b && dist1a < dist1b)
			{
				m_moveClockWise[0] = true;
			}
			else if (dist0a > dist0b && dist1a > dist1b)
			{
				m_moveClockWise[0] = false;
			}
			else
			{
				m_moveClockWise[0] = true;
				m_bIsValidInterval = false;
			}
		}
		else if (m_bndryIntervalSide1.Inside(first2) || m_bndryIntervalSide1.Inside(last2))
		{
			m_bndryIntervalSide1.Swap();
			m_moveClockWise[0] = false;

			if (m_bndryIntervalSide1.Inside(first2) || m_bndryIntervalSide1.Inside(last2))
			{
				m_bIsValidInterval = false;
				return;
			}
		}
		else
		{
			m_moveClockWise[0] = true;
		}

		ASSERT(!m_bndryIntervalSide1.Inside(first2) && !m_bndryIntervalSide1.Inside(last2));

		// Set the interval associated with the second side
		m_bndryIntervalSide2.Set(numPts, first2, last2);

		if (m_bndryIntervalSide2.Inside(first1) || m_bndryIntervalSide2.Inside(last1))
		{
			m_bndryIntervalSide2.Swap();
			m_moveClockWise[1] = false;

			if (m_bndryIntervalSide2.Inside(first1) || m_bndryIntervalSide2.Inside(last1))
			{
				m_bIsValidInterval = false;
				return;
			}
		}
		else
		{
			m_moveClockWise[1] = true;
		}

		ASSERT(!m_bndryIntervalSide2.Inside(first1) && !m_bndryIntervalSide2.Inside(last1));

		m_bIsValidInterval = true;
	}
///////////////////////////////////////////////////////////////////////////////
void BoundaryCorner::FindCorner(BPList& pts, BPIterator left, BPIterator right, 
								const double& maxSqDist, const double& minCCA)
{
	BoundaryCorner bc;
	BPIterator it;

	this->cosAngle = -1; // init to widest angle

	if (pts.empty())
		return;

	//DBG_C_LOG("Searching for corners within " << *left << ", " << *right)

	// Search for the minimum angle (ie, maximum cos(angle)) within the 
	// interval [First(), Last()]
	for (it = left; /* true */; it++)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
			*this = bc;

		if (it == right)
			break;

		ASSERT(it != pts.end());
	}

	const unsigned int originalNumPts = pts.size();

	// See if there is a corner within the left margin [begin,left). Start from the 
	// points closer to the 'left' limit. If there is a corner, remove all margin
	// points to its left, in order to avoid having a left "arm" that goes over it
	for (it = left, --it; /* true */; --it)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
		{
			// Remove pts in the interval [begin(), it)
			pts.erase(pts.begin(), it);
			ASSERT(pts.begin() == it);
			break;
		}

		if (it == pts.begin())
			break;
	}

	// See if there is a corner within the left margin (right,end). Start from the 
	// points closer to the 'left' limit. If there is a corner, remove all margin
	// points to its left, in order to avoid having a left "arm" that goes over it
	for (it = right, ++it; it != pts.end(); ++it)
	{
		bc.ComputeMinimumAngle(pts, it, maxSqDist, minCCA);

		if (bc.cosAngle >= this->cosAngle)
		{
			// Remove pts in the interval (it, end())
			it++;

			if (it != pts.end())
				pts.erase(it, pts.end());

			break;
		}
	}

	if (pts.size() < originalNumPts)
	{
		DBG_C_LOG("Restarting the searching for corners")
		FindCorner(pts, left, right, maxSqDist, minCCA);
	}
}

///////////////////////////////////////////////////////////////////////////////
	//pCornerInfo->valid = (rv != 1);
	//pCornerInfo->valid = pt.sqDist(pCornerInfo->pt) <= pt.sqDist(intPt);
	
	
	//DBG_PRINT2(sz0, sz1)

		//DBG_PRINT1(LigatureSegment::s_pBndryPtFinder->GetOriginalPoints().Size())

		/*DBG_PRINT2(ls0(ls0.Source())[sides.first].pt, ls0(ls0.Target())[sides.first].pt)
		DBG_PRINT2(bi0.GetBoundaryPoint(bi0.First()), bi0.GetBoundaryPoint(bi0.Last()))

		DBG_PRINT2(ls1(ls1.Source())[sides.second].pt, ls1(ls1.Target())[sides.second].pt)
		DBG_PRINT2(bi1.GetBoundaryPoint(bi1.First()), bi1.GetBoundaryPoint(bi1.Last()))*/
///////////////////////////////////////////////////////////////////////////////
	// Add all pts in bi0
	/*for (idx = bi0.First(), sz0 = 0;  ; bi0.MoveNext(idx), sz0++)
	{
		bi0.GetBoundaryPoint(idx, &pt);
		pts.push_back(pt);

		if (idx == bi0.Last())
			break;
	}

	// Add all pts in bi1 but the first, since it's equal to the last point of bi0
	for (idx = bi1.Next(bi1.First()), sz1 = 1;  ; bi1.MoveNext(idx), sz1++)
	{
		bi1.GetBoundaryPoint(idx, &pt);
		pts.push_back(pt);

		if (idx == bi1.Last())
			break;
	}*/
///////////////////////////////////////////////////////////////////////////////
	/*void SetBoundaryCornerInfo(const BoundaryCorner& bc1, const BoundaryCorner& bc2, 
		SmartArray<BoundaryCorner> mergedCorners)
	{
		ASSERT(m_corners.IsEmpty());

		m_corners.AddTail(bc1);
		m_corners.AddTail(bc2);

		if (!mergedCorners.IsEmpty())
			m_corners.AddTail(mergedCorners);
	}*/
///////////////////////////////////////////////////////////////////////////////
double m_dSourceRadius;   //!< radius of the endpoint with largets radius (eg joint point)
double m_dGapSizeSquared; //!< squared gap size opened by the protrusion

m_dGapSizeSquared = wi.SquaredSpokesDistance(first);


/*bool GSG::IsBranchMergeValid(SkelJoint* pJoint, const LigatureSegmentList& nonLig, 
							 const std::list<LigatureSegment>& ligSegs)
{
}*/

/*!
	@brief Checks whether the fusion of two branches is valid by
	measuring the boundary gap created by the "principal" and
	comparing it againts the radii of the associated skeletal gap endpoints.
*/
/*bool GSG::IsBranchMergeValid(SkelJoint* pJoint, const LigatureSegmentList& nonLig, 
							   const std::list<LigatureSegment>& ligSegs)
{
	DBG_C_LOG("Checking for the validity of the branch merge")

	ASSERT(nonLig.size() == 2 && ligSegs.size() >= 1);

	if (ligSegs.size() > 1 || ligSegs.front().m_dTargetRadius == 0)
		return true;
	
	const LigatureSegment& ls = ligSegs.front();

	return (ls.m_dGapSizeSquared <= (ls.m_dSourceRadius * ls.m_dSourceRadius));
}*/
///////////////////////////////////////////////////////////////////////////////

if (m_corner1.cosAngle >= MIN_FULL_LIG_CORNER_COS_ANGLE)
	m_corner1.valid = IsCornerValid('1', m_corner1);
else
	m_corner1.valid = false;
			
if (m_corner2.cosAngle >= MIN_FULL_LIG_CORNER_COS_ANGLE)
	m_corner2.valid = IsCornerValid('2', m_corner2);
else
	m_corner2.valid = false;
			
bool IsCornerValid(char side, const BoundaryCorner& corner) const;

/*!
	@brief Counts the number of spokes on side S that end within a radius of R
	around the given corner point C, and divides this number by the number of
	spokes in the ligature segment.

	@return the ratio described above.
*/
bool LigatureSegment::IsCornerValid(char side, const BoundaryCorner& corner) const
{
	return true;
	/*ASSERT(!corner.IsNull());

	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
	double dist2, count = 0;

	for (unsigned int i = m_first; i <= m_last; i++)
	{
		dist2 = bil[i][side].pt.sqDist(corner.pt);

		if (dist2 <= MAX_SQUARED_DIST_FROM_CORNER)
			count++;
	}

	double ratio = count / Size();

	DBG_C_LOG(DBG_VAL(ratio) << " for " << DBG_VAL(corner.pt) << DBG_VAL(count) << DBG_VAL(Size()))

	// If the ratio is valid, also check that the flux point at the smaller
	// end of the segment is a bit closet to the corner than the other endpoint
	if (ratio >= MIN_SPOKE_WITHIN_RANGE_RATIO)
	{
		const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();

		double distToFirst = fpl[m_first].p.dist(corner.pt);
		double distToLast = fpl[m_last].p.dist(corner.pt);

		if (m_bDecreasing) 
			return (distToLast + 0.5 < distToFirst);
		else
			return (distToFirst + 0.5 < distToLast);
	}

	return false;*/
}
///////////////////////////////////////////////////////////////////////////////
void GetBranchBndryLimits(sg::Point* p0, sg::Point* p1) const
	{
		ASSERT(m_first.branchSide == m_last.branchSide);

		char s = m_first.branchSide;

		*p0 = m_pBranch->getFirstBndryInfo()[s].pt;
		*p1 = m_pBranch->getLastBndryInfo()[s].pt;
	}
///////////////////////////////////////////////////////////////////////////////
inline std::pair<char,char> GetSharedSideByBranches(const BoundaryInfo& bi0,
												   const BoundaryInfo& bi1)

// We need to find which bndry sides are shared by the two branches
		BoundaryInfo bi0 = ls0(ls0.Source()); // don't use a const reference here!
		BoundaryInfo bi1 = ls1(ls1.Source()); // don't use a const reference here!
///////////////////////////////////////////////////////////////////////////////

//lsl.FindRootedLigatureSegments(nodeBS);
//if (m_params.nSubtractLigatureFromJunctions)
//	AddPseudoLigatureSegments(v, lsl);
	
bool FindRootedLigatureSegments(const BranchSegment& bs);

bool LigatureSegmentList::FindRootedLigatureSegments(const BranchSegment& bs)
{
	ASSERT(!bs.IsInverted());

	clear();

	if (bs.Size() < 2 || bs[bs.First()].p.dist(bs[bs.Last()].p) < 1) 
		return false;

	if (bs.First() == bs.BranchFirst() && bs.BranchFirstPtDegree() > 1)
	{
		LigatureSegment ls;

		ls.FindRootedLigature(bs.m_pBranch, (SkelJoint*) bs.FirstJoint());

		if (ls.IsLigature())
			push_back(ls);
	}

	if (bs.Last() == bs.BranchLast() && bs.BranchLastPtDegree() > 1)
	{
		LigatureSegment ls;

		ls.FindRootedLigature(bs.m_pBranch, (SkelJoint*) bs.LastJoint());

		if (ls.IsLigature())
			push_back(ls);
	}

	return !empty();
}
///////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
	forall_nodes(v, *this)
	{
		if (GetNode(v).m_type == GSG_BRANCH)
		{
			ASSERT(!GetNode(v).GetBonePart().IsEmpty());
		}
	}
#endif
///////////////////////////////////////////////////////////////////////////////
	const LineSegmentArray& f0; 
	const LineSegmentArray& f1;	
///////////////////////////////////////////////////////////////////////////////
double BGContextualSimilarityMeasurer::RadiusFunctionDiff(const LineSegmentArray& func0, 
														  const LineSegmentArray& func1) const
{
	TrapezoidList tl(func0, func1);
	double x0, x1;
	int idx0, idx1, sz0, sz1;

	idx0 = 0;
	sz0 = tl.f0.Size(); // num ctrl points in f0 is sz0 + 1

	idx1 = 0;
	sz1 = tl.f1.Size(); // num ctrl points in f1 is sz1 + 1

	ASSERT(sz0 > 0 && sz1 > 0);
	
	// Visit all OVERLAPPING control points in each radius function 
	// in ascending order and add trapezoid sides
	while (idx0 <= sz0 && idx1 <= sz1)
	{
		x0 = (idx0 < sz0) ? tl.f0[idx0].X0() : tl.f0[sz0 - 1].X1();
		x1 = (idx1 < sz1) ? tl.f1[idx1].X0() : tl.f1[sz1 - 1].X1();

		if (x0 == x1)
			tl.Add(x0, idx0++, idx1++);
		else if (x0 < x1)
			tl.Add(x0, idx0++, idx1 - 1);
		else
			tl.Add(x1, idx0 - 1, idx1++);
	}

	// Visit the remaining (if any) NON overlapping control pts in F0 and add them
	while (idx0 <= sz0)
	{
		x0 = (idx0 < sz0) ? tl.f0[idx0].X0() : tl.f0[sz0 - 1].X1();
		tl.Add(x0, idx0++, sz1 - 1);
	}

	// Visit the remaining (if any) NON overlapping control pts in F1 and add them
	while (idx1 <= sz1)
	{
		x1 = (idx1 < sz1) ? tl.f1[idx1].X0() : tl.f1[sz1 - 1].X1();
		tl.Add(x1, sz0 - 1, idx1++);
	}

	// Visit all the control points in each radius function in ascending order
	/*while (idx0 < sz0 || idx1 < sz1)
	{
		x0 = (idx0 < sz0) ? tl.f0[idx0].X0() : tl.f0[sz0 - 1].X1();
		x1 = (idx1 < sz1) ? tl.f1[idx1].X0() : tl.f1[sz1 - 1].X1();

		if (x0 == x1)
			tl.Add(x0, idx0++, idx1++);
		else if (x0 < x1)
			tl.Add(x0, idx0++, idx1);
		else
			tl.Add(x1, idx0, idx1++);
	}*/

	// Compute the area between the curves
	TrapezoidList::const_iterator itA, itB;
	double area, totalArea;

	totalArea = 0;
	itB = tl.begin();
	itA = itB++;

	for (; itB != tl.end(); itA++, itB++)
	{
		DBG_PRINT2(itB->x, itA->x)
		ASSERT(itB->x > itA->x);

		// Compute the area of the trapezoid
		area = (itB->x - itA->x) * (fabs(itA->dy) + fabs(itB->dy)) / 2;

		ASSERT(area >= 0);

		totalArea += area;
	}

	return totalArea;
}
///////////////////////////////////////////////////////////////////////////////
int i = 0, j = 0;

		// Add heading non-overlapping points
		for (; pts0[i].x < pts1[0].x; i++)
			Add(pts0[i].x,  pts0[i].y, -1);

		for (; pts1[j] < pts0[0].x; j++)
			Add(pts1[j].x, -1, pts1[j].y);

		// Add overlapping points
		while (i < pts0.size() && j < pts1.size())
		{
			const POINT& p0 = pts0[i];
			const POINT& p1 = pts1[j];

			if (p0.x == p1.x)
			{
				Add(p0.x, p0.y, p1.y);
				i++;
				j++;
			}
			else if (p0.x < p1.x)
			{
				// f0 overlaps with f1 iff there was a previous p1' (ie, j>0)
				if (j == 0)
					Add(p0.x, p0.y, -1);
				else
					Add(p0.x, p0.y, p1);

				i++;
			}
			else // ie(p0.x > p1.x)
			{
				// f1 overlaps with f0 iff there was a previous p0' (ie, i>0)
				if (i == 0)
					Add(p1.x, -1, p1.y);
				else
					Add(p1.x, p0, p1.y);

				j++;
			}
		}

		// Add trailing non-overlapping points
		for (; i < pts0.size(); i++)
			Add(pts0[i].x,  pts0[i].y, -1);

		for (; j < pts1.size(); j++)
			Add(pts1[j].x, -1, pts1[j].y);
///////////////////////////////////////////////////////////////////////////////
		/*!
		
	*/
	void Add(const double& x, int idx0, int idx1)
	{
		ASSERT(empty() || back().x < x);
		ASSERT(idx0 >= 0 && idx0 <= f0.Size());
		ASSERT(idx1 >= 0 && idx1 <= f1.Size());

		bool f0HasX = (x >= f0.GetHead().X0() && x <= f0.GetTail().X1());
		bool f1HasX = (x >= f1.GetHead().X0() && x <= f1.GetTail().X1());

		ASSERT(f0HasX || f1HasX);

		// If the index of the segment that contains x in each function is
		// equal to the number of segments
		if (idx0 == f0.Size())
			idx0--;

		if (idx1 == f1.Size())
			idx1--;

		// If x is in both functions, then there may be crossings of segments
		// which define tro triangular trapezoids
		if (f0HasX && f1HasX)
		{
			//ASSERT(f0[idx0].ContainsX(x) && f1[idx1].ContainsX(x));
			ASSERT(f0[idx0].ContainsX(x));
			ASSERT(f1[idx1].ContainsX(x));

			// Get the difference in the y-coord to determine if lines cross
			double dy = f1[idx1].Y(x) - f0[idx0].Y(x);

			// Check if the functions cross one another and form TWO triangles
			// Ignore the case where the lines end at the same point
			if (!empty() && dy != 0 && back().dy != 0 && SIGN(dy) != SIGN(back().dy))
			{
				double xa = f0[idx0].CrossingPoint(f1[idx1]);
				ASSERT(xa > back().x && xa < x);

				push_back(TrapezoidSide(xa, 0)); //this side has zero height
			}

			push_back(TrapezoidSide(x, dy));
		}
		else if (f0HasX)
		{
			ASSERT(f0[idx0].ContainsX(x) && !f1[idx1].ContainsX(x));

			push_back(TrapezoidSide(x, -f0[idx0].Y(x)));
		}
		else
		{
			ASSERT(!f0[idx0].ContainsX(x) && f1[idx1].ContainsX(x));

			push_back(TrapezoidSide(x, f1[idx1].Y(x)));
		}
	}
///////////////////////////////////////////////////////////////////////////////
		ASSERT(idx0 >= 0 && idx0 < f0.Size());
		ASSERT(idx1 >= 0 && idx1 < f1.Size());

		double y0 = (f0[idx0].ContainsX(x)) ? f0[idx0].Y(x) : 0;
		double y1 = (f1[idx1].ContainsX(x)) ? f1[idx1].Y(x) : 0;

		// Get the difference in the y-coord to determine if lines cross
		double dy = y1 - y0;

		// Check if the functions cross one another and form TWO triangles
		// Ignore the case where the lines end at the same point
		if (!empty() && dy != 0 && back().dy != 0 && SIGN(dy) != SIGN(back().dy))
		{
			double xa = f0[idx0].CrossingPoint(f1[idx1]);
			ASSERT(xa > back().x && xa < x);

			push_back(TrapezoidSide(xa, 0)); //this side has zero hight
		}
///////////////////////////////////////////////////////////////////////////////
sz0 = (tl.f0.IsEmpty()) ? 0 : tl.f0.Size() + 1; // ie, num ctrl points in f0
sz1 = (tl.f1.IsEmpty()) ? 0 : tl.f1.Size();     // ie, num ctrl points in f1
///////////////////////////////////////////////////////////////////////////////
pBGNode->m_radiusFunction.Clear();
///////////////////////////////////////////////////////////////////////////////
LineSegmentArray f1, f2;
	bool bN1HasFewerKnots = (f1.Size() < f2.Size());

	f1 = (bN1HasFewerKnots) ? pNode1->RadiusFunction() : pNode2->RadiusFunction();
	f2 = (bN1HasFewerKnots) ? pNode2->RadiusFunction() : pNode1->RadiusFunction();
	
	std::list<KnotParams> ctrlPts;
	int i, j, greaterY, overlapKnotCount;
	double x1, x2;

	//if (!f1.IsEmpty() && !f2.IsEmpty())
	//	greaterY = (f1[0].Y0() >= f2[0].Y0()) ? 1 : 2;

	i = 0;
	j = 0;

	// Visit all the control points in each radius function in ascending order
	while (i < f1.Size() && j < f2.Size())
	{
		x1 = (i == f1.Size()) ? f1[i].X1() : f1[i].X0();
		x2 = (j == f2.Size()) ? f2[i].X1() : f2[i].X0();

		if (x1 <= x2)
			ctrlPts.push_back(KnotParams(x1, i++, 1, j /*may be out of range*/));
		else
			ctrlPts.push_back(KnotParams(x2, j++, 2, i /*may be out of range*/));
	}

	overlapKnotCount = ctrlPts.size();

	if (i <= f1.Size() && !f1.IsEmpty())
	{
		while (i < f1.Size())
			ctrlPts.push_back(KnotParams(f1[i].X0(), i++, 1));

		ctrlPts.push_back(KnotParams(f1[i].X1(), i++, 1));
	}

	if (j <= f2.Size() && !f2.IsEmpty())
	{
		while (j < f2.Size())
			ctrlPts.push_back(KnotParams(f2[i].X0(), j++, 2);

		ctrlPts.push_back(KnotParams(f2[i].X1(), j++, 2);
	}

	// Compute the area of each segment.
	std::list<KnotParams>::const_iterator it;

	for (it = ctrlPts.begin(); it != ctrlPts.end(); it++)
	{
		if (it->index < f[it->funcID].size())
		{
			linSeg1 = f[it->funcID][it->index];
			linSeg2 = f[!it->funcID][it->assocIndex];

			y1 = linSeg1.Y0();
			y2 = linSeg2.Y(linSeg1.X0);
		}
	}

	for (unsigned int j = 0; j < ctrlPts.size(); j++)
		DBG_PRINT2(ctrlPts[j].first, ctrlPts[j].second);
///////////////////////////////////////////////////////////////////////////////
for (; itB != ctrlPts.end(); itA++, itB++)
	{
		// Check if there is no overlap
		if (itA->y0 == -1 || itA->y1 == -1) || (itB->y0 == -1 || itB->y1 == -1)
		{
			area = ;
		}
		// Check if we have an increasing triangle (or a line) shape
		else if (itA->y0 == itA->y1)
		{
			area = fabs(itB->y0 == itB->y1) * (it1->x - it0->x) / 2.0;
		}
		// Check if we have a decreasing triangle shape
		else if (itB->y0 == itB->y1)
		{
			area = fabs(itA->y0 - itA->y1) * (it1->x - it0->x) / 2.0;
		}
		// Check if we have a trapezoid shape
		else if ((itA->y0 < itA->y1 && itB->y0 < itB->y1) || 
			     (itA->y0 > itA->y1 && itB->y0 > itB->y1))
		{
			area = ;
		}
		// The only remaining case is that we have two triangles
		else
		{
			area = ;
		}

		totalArea += area;
	}
///////////////////////////////////////////////////////////////////////////////
	// Initialize the indices of each current segment of each function to 'none'
	double xa = -1, Ya[2] = {-1, -1};
	double xb, yb[2]; 
	int idx[2] = {-1, -1};
	int i, j;
	//idx0 = -1;
	//idx1 = -1;
	x0 = -1;
	x1 = -1;

	for (it = ctrlPts.begin(); it != ctrlPts.end(); it++)
	{
		i = it->funcID;
		j = (i == 0) ? 1 : 0;

		if (xa == -1)
		{
			xa = it->x;
			ya[i] = f[i][it->index].Y(xa);
			ya[j] = 
		}

		// See if the functions overlap...
		if (idx[j] >= 0 && f[j][idx[j]].X1() >= it->x) // ...they do
		{
			// have x0, y0a, y0b
			x1 = it->x;

			y1a = f[0][it->index].Y(x1);
			y1b = f[1][idx[j]].Y(x1);

			//x0 = f[i][idx[i]].X
			x0p = it->x;
			y0p = 
			

			x
		}
		else
		{
		}

		if (it->index < f[it->funcID].size())
		{
			linSeg1 = f[it->funcID][it->index];
			linSeg2 = f[!it->funcID][it->assocIndex];

			y1 = linSeg1.Y0();
			y2 = linSeg2.Y(linSeg1.X0);
		}
	}
///////////////////////////////////////////////////////////////////////////////
			ctrlPts.push_back(KnotParams(x1, (idx0 == -1) ? -1 : f[0][idx0].Y(x1), f[1][idx1].Y(x1)));



			if (idx1 == 0)
			ctrlPts.push_back(KnotParams(x0, idx0++, 0, idx1 /*may be out of range*/));
		else
			ctrlPts.push_back(KnotParams(x1, idx1++, 1, idx0 /*may be out of range*/));


		if (x0 <= x1)
			ctrlPts.push_back(KnotParams(x0, idx0++, 0, idx1 /*may be out of range*/));
		else
			ctrlPts.push_back(KnotParams(x1, idx1++, 1, idx0 /*may be out of range*/));

///////////////////////////////////////////////////////////////////////////////
	struct KnotParams
	{
		double x;
		int index;
		int funcID;
		int assocIndex;

		KnotParams() { }

		KnotParams(const double& xval, int i, int fid, int j) 
			: x(xval), index(i), funcID(fid), assocIndex(j) { }

		/*friend bool operator<(const KnotParams& a, const KnotParams& b)
		{
			return a.x < b.x;
		}*/
	};
///////////////////////////////////////////////////////////////////////////////
/*! 
		Constructs an iterator with a graph, a starting node and an 
		optional direction parameter where false indicates depth first
		and true indicates hight first (ie, edge directions are inverted).
	*/
	graph_dfs_iterator(const leda::graph& G, leda::node v, bool inverted = false)
	{
		init(G, v, inverted);
	}

	/*! 
		Initializes the iterator with a graph, a starting node and an 
		optional direction parameter where false indicates depth first 
		(default) and true indicates hight first (inverted edge directions).
	*/
	void init(const leda::graph& G, leda::node v, bool inverted = false)
	{
		m_pGraph = &G;
		m_currentEdge = first_edge(v);
		m_visited.init(G, false);
	}
///////////////////////////////////////////////////////////////////////////////
// Process sibling and sibling descendants
	DBG_M_LOG("Processing sibling and sibling descendants\n") 
	for (int i = 0; i < 2; i++)
	{
		pq = &pq_ssd[i];

		while(!pq->empty())
		{
			// Pop the next node in the queue with lowest relative level (in the DAG)
			pq_it  = pq->find_min();
			bgNode = pq->inf(pq_it); // gets the "bipartite node"
			u      = inf(bgNode);    // gets the "DAG node"
			level  = pq->del_min();  // delete from queue and get the relative level

			forall_inout_edges(e, bgNode)
			{
				if (!procEdges[e])
				{
					procEdges[e] = true; // mark e as processed

					// Edges are always directed from query to model nodes
					penCoeff = npi.GetSiblingPenalty(inf(source(e)), inf(target(e)));

					DBG_M_LOG_ONLY(npi.Print(g_dagMatchingLog << "\n",
						inf(source(e)), inf(target(e)), penCoeff))

					ASSERT_UNIT_INTERVAL(penCoeff);

					if (penCoeff > 0) 
					{
						// Get a non-const reference to the edge attribute
						NodeMatchInfoPtr& ptrEdgeInfo = Inf(e);

						// Update the edge info with a clode of itself
						// so that we can modify it for this graph only
						if (ptrEdgeInfo.Links() > 1)
							ptrEdgeInfo = inf(e).Clone();

						ptrEdgeInfo->ApplyPenalty(penCoeff);
					}
					else
						zeroEdges.push(e);
				}
			}
		}
	}
///////////////////////////////////////////////////////////////////////////////	
	// The ancestor queue of set i is processed first (dir == 0). Next, the descendant
		// queue is processed (dir == 1). 'dir' is set wrt npi::IsImmediateRelative(dir)
		for (dir = 0, pq = &pq_ancestor[i]; dir < 2; dir++, pq = &pq_descendant[i])
		{
			// Process all paths until either there are no more nodes
			// in the path or a gap is found in the path
			do
			{
				DBG_MSG1("Starting new path...\n")
				// Reset the last node seen to the matched node when starting a new path
				lastNode = matchedNode;

				// Initially, we assume that there is only one path of nodes that
				// starts at the matched node and goes to the current ancestor/descendant
				bHasAnotherPath = false;

				// Process all ancestors/descendants of the matched node in set i
				while(!pq->empty())
				{
					// Pop the next node in the queue with lowest relative level (in the DAG)
					pq_it  = pq->find_min();
					bgNode = pq->inf(pq_it); // gets the "bipartite node"
					u      = inf(bgNode);    // gets the "DAG node"
					level  = pq->del_min();  // delete from queue and get the relative level

					/*int lbl1 = ptrNMI->GetNodePair().Graph(i).GetNodeDFSIndex(u);
					int lbl2 = ptrNMI->GetNodePair().Graph(i).GetNodeDFSIndex(lastNode);
					int lbl3 = ptrNMI->GetNodePair().Graph(i).GetNodeDFSIndex(matchedNode);
					DBG_MSG3(lbl1, lbl2, lbl3)*/

					// Check that u is either the parent or the child of the last node seen
					// ie, the node is the next in the path of ancestors/descendants
					if (npi.IsImmediateRelative(dir, u, lastNode))
					{
						// The node becomes the last in the path
						lastNode = u;

						// Process all incident edges on the "bipartite graph node" bgNode
						forall_inout_edges(e, bgNode)
						{
							// Check that e (in this bip graph) is not processed already
							if (!procEdges[e])
							{
								procEdges[e] = true; // mark e as processed

								// Compute the penalty for the pair of nodes linked by the edge. Note
								// that edges are always directed from query (src) to model (tgt)
								q = inf(source(e));
								m = inf(target(e));

								penCoeff = (dir == 0) ? npi.GetAncestorPenalty(q, m) :
									npi.GetDescendantPenalty(q, m);

								DBG_M_LOG_ONLY(npi.Print(g_dagMatchingLog << "\n", q, m, penCoeff))

								ASSERT_UNIT_INTERVAL(penCoeff);

								// m_setA zero penalty coefficient means that the edge
								// is no longer valid, so we save it for later removal
								if (penCoeff > 0) 
								{
									// Get a non-const reference to the edge attribute
									NodeMatchInfoPtr& ptrEdgeInfo = Inf(e);

									// Update the edge info with a clode of itself
									// so that we can modify it for this graph only
									if (ptrEdgeInfo.Links() > 1)
										ptrEdgeInfo = inf(e).Clone();

									if (dir == 0) // processing ancestors
									{
										eq = npi.FindFirstEdgeFromAncestor(0, q);
										em = npi.FindFirstEdgeFromAncestor(1, m);
									}
									else // processing descendants
									{
										eq = npi.FindLastEdgeToDescendant(0, q);
										em = npi.FindLastEdgeToDescendant(1, m);

										ptrEdgeInfo->SetClosestKnownAncestor(npi);
									}

									// Often, there is no need to recompute the sim value
									bRecomputeSimilarity = false;
									paramIdx = ptrNMI->GetParameterIndex();
									
									if (eq != nil && em != nil)
									{
										ptrEdgeInfo->FixEdgeMatch(eq, em, (dir != 0));
							
										// Edge info changed, must recompute sim value
										bRecomputeSimilarity = true;
									}

									if (ptrEdgeInfo->GetParameterIndex() != paramIdx)
									{
										//DBG_PRINT1(paramIdx)
										//ptrEdgeInfo->Print(std::cout);

										ptrEdgeInfo->SetParameterIndex(paramIdx);

										// Node param changed, must recompute sim value
										bRecomputeSimilarity = true;
									}

									
								}
								else
									zeroEdges.push(e);
							}
						}
					}
					else // we either found a "gap" in the path or another path
					{
						bool bIsRel = npi.IsImmediateRelative(dir, u, matchedNode);

						//DBG_MSG3("Gap or Alternate path", bIsRel, bHasAnotherPath)

						// We can't tell which case it is here, so save the node
						// in an auxiliar path queue
						pq_aux.insert(level, bgNode);

						// If u is an immediate relative of the matched node, it means 
						// that there still is another path that must be processed later
						if (!bHasAnotherPath && npi.IsImmediateRelative(dir, u, matchedNode))
						{
							//DBG_MSG1("Alternate path!")
							bHasAnotherPath = true;
						}
					}
				} 

				// If there is another path to process, we iterate again with
				// pq set to the remaining nodes in pq_aux
				if (bHasAnotherPath)
					*pq = pq_aux;
					
				// The nodes in the auxiliar path queue are no longer necessary regardless
				// of whether they belong to another path (they are in pq now) or if they
				// can't be reached by following the current path (they induce no penalties)
				pq_aux.clear();

			} while (bHasAnotherPath);
		}
	}

///////////////////////////////////////////////////////////////////////////////	
	
	DBG_MSG1("START DFS")
	while (dfsIt.has_next())
	{
		leda::node v = dfsIt.next();
		DBG_PRINT1(npi.Graph(0).GetNodeDFSIndex(v))
	}
	DBG_MSG1("END DFS")

	return;
	
	typedef leda::p_queue<int, leda::node> PathQueue;
	typedef leda::pq_item PathQueueItem;

	// If the node is an ancestor or descencant of the matched
	// node, then store it in the corresponding path queue, which
	// is sorted by distance to the matched node (in the DAG)
	if (npi.IsAncestor(i, u))
	{
		// Find the relative level of the nodes "in the DAGs"
		level = npi.GetRelativeNodeLevel(i, u);
		ASSERT(level < 0);

		// Insert "the NEW node of this Bip Graph". Negate the level.
		pq_ancestor[i].insert(-level, newNode);
	}
	else if (npi.IsDescendant(i, u))
	{
		// Find the relative level of the nodes "in the DAGs"
		level = npi.GetRelativeNodeLevel(i, u);
		ASSERT(level > 0);

		// Insert "the NEW node of this Bip Graph"
		pq_descendant[i].insert(level, newNode);
	}
	//else if (npi.IsSiblingOrSiblingDescendant(i, u))
	else if (npi.IsSibling(i, u))
	{
		level = npi.GetRelativeNodeLevel(i, u);
		ASSERT(level >= 0);

		pq_ssd[i].insert(level, newNode);
	}
///////////////////////////////////////////////////////////////////////////////
void PrintLastMatch(std::ostream& os) const
	{
		m_ptrNodeMatchInfo->Print(os);
	}
///////////////////////////////////////////////////////////////////////////////
protected:
	double SumAssignmentValues() const
	{
		NodeAssignment nodeAssig;
		double sum = 0;

		forall(nodeAssig, m_nodeAssigments)
		{
			sum += nodeAssig.first();
		}

		return sum;
	}
	
	m_bipGraph.SolveMaxWeightAssignment(&m_nodeAssigments, sortType);

		SortNodeAssignments(type);

		m_nodeSimilarityEstimate = m_bipGraph.SumAssignmentValues();
///////////////////////////////////////////////////////////////////////////////
//! Retrieves the first node correspondence in the bipartite graph
	const_iterator begin() const
	{
		ASSERT(!m_nodeAssigments.empty());

		return const_iterator(m_nodeAssigments.first(), this);
	}
///////////////////////////////////////////////////////////////////////////////
EdgeValueArray m_edgeSaliency;

void SetEdgeSaliency(leda::edge e, const double& saliency)
	{
		if (m_edgeSaliency.empty())
			m_edgeSaliency.init(*this);

		m_edgeSaliency[e] = saliency;
	}
///////////////////////////////////////////////////////////////////////////////
m_nodeSimilarityEstimate = m_bipGraph.SumUpAssignments(m_nodeAssigments);

	//! Sums the values associated with each assignment
	double SumUpAssignments(const NodeAssigmentList& nodeAssigments) const
	{
		return BASE_CLASS::SumUpAssignments(m_edgeValues, nodeAssigments);
	}
///////////////////////////////////////////////////////////////////////////////
//! Iterator of selected correspondeces among nodes that are not in the set
	class const_iterator
	{
		leda::list_item m_item;
		const SolutionSet* m_pSet;

	public:
		const_iterator()
		{
			m_pSet = NULL;
		}

		const_iterator(leda::list_item it, const SolutionSet* pSet)
		{
			m_item = it;
			m_pSet = pSet;
		}

		void operator++()
		{
			m_item = m_pSet->m_nodeAssigments.succ(m_item);
		}

		bool end() const
		{
			return m_item == nil;
		}

		const leda::edge& operator*() const 
		{ 
			return m_pSet->m_nodeAssigments.inf(m_item); 
		}

		double Value() const
		{
			return m_pSet->m_bipGraph.SimilarityValue(operator*());
		}
	};

	//friend class const_iterator;

///////////////////////////////////////////////////////////////////////////////

//! Finds the last edge in the path that goes from 'q' or 'm' to 'd'
	leda::edge FindLastEdgeToDescendant(int i, leda::node d) const
	{
		leda::node v = Node(i);
		leda::edge e;

		forall_in_edges(e, d)
		{
			if (v == source(e) || IsDescendant(i, source(e), v))
				return e;
		}

		return nil;
	}

	//! Finds the first edge in the path that goes from 'a' to 'q' or 'm'
	leda::edge FindFirstEdgeFromAncestor(int i, leda::node a) const
	{
		leda::node v = Node(i);
		leda::edge e;

		forall_out_edges(e, a)
		{
			if (v == target(e) || IsAncestor(i, target(e), v))
				return e;
		}

		return nil;
	}


	//! True if there is a path from node 'a' to node 'v' in the query (i==0) or model (i==1)
	bool IsAncestor(int i, leda::node a, leda::node v) const
	{
		ASSERT_SAME_GRAPH(a, v);

		return (TCM(i)[NodeIndex(i, a)][NodeIndex(i, v)] != 0);
	}

	//! True if there is a path from 'v' to node 'd' in the query (i==0) or model (i==1)
	bool IsDescendant(int i, leda::node d, leda::node v) const
	{
		ASSERT_SAME_GRAPH(d, v);

		return (TCM(i)[NodeIndex(i, v)][NodeIndex(i, d)] != 0);
	}
	
	/*! 
		True if node 'v' is a child of a parent of the query 
		node (i == 0) or the model node (i == 1)
	*/
	bool IsSibling(int i, leda::node v) const
	{
		leda::node p;
		leda::edge e, ee;
		int idxV = NodeIndex(i, v);
		leda::node u = GetMatchedNode(i);
		
		ASSERT_SAME_GRAPH(u, v);

		// See if v is a child of any parent of the matched node u
		// for all parents of u...
		forall_in_edges(e, u) 
		{
			p = source(e); // parent of matched node u

			forall_out_edges(ee, p)
			{
				if (target(ee) == v)
					return true;
			}
		}

		return false;
	}

	/*! 
		True if there is a path from a parent of the query node (i == 0) 
		or the model node (i == 1) to node 'v'
	*/
	bool IsSiblingOrSiblingDescendant(int i, leda::node v) const
	{
		leda::edge e;
		int idxV = NodeIndex(i, v);
		leda::node u = GetMatchedNode(i);

		ASSERT_SAME_GRAPH(u, v);

		// See if v is a descendant of any parent of the matched node u
		forall_in_edges(e, u)
		{
			// Deal with the special case of v being a parent node
			if (source(e) == v)
				return false;

			// See if there is a path in the TCM from parent to node v
			if (TCM(i)[NodeIndex(i, source(e))][idxV] != 0)
				return true;
		}

		return false;
	}
	
///////////////////////////////////////////////////////////////////////////////
// VC++6 -> Include CImg before DAG.h
//#include "../CImg/CImg.h"

class VisualDAG* m_pVisualDAG;
///////////////////////////////////////////////////////////////////////////////
ASSERT(npi.IsSibling(i, u));
ASSERT((i == 0 && inf(source(e)) == u) || (i == 1 && inf(target(e)) == u));
ASSERT(npi.IsSibling(0, inf(source(e))) || npi.IsSibling(1, inf(target(e))));
///////////////////////////////////////////////////////////////////////////////
double ComputePenaltyCoefficient(leda::node qq, leda::node mm) const
	{
		if (!IsAncestorRelPreserved(qq, mm))
			return DAGMatcher::GetMatchParams().dBreakAncestorRelPen;

		if (!IsDescendantRelPreserved(qq, mm))
			return DAGMatcher::GetMatchParams().dBreakDescendantRelPen;

		if (!IsSiblingOrSiblingDescendantRelPreserved(qq, mm))
			return DAGMatcher::GetMatchParams().dBreakSiblingRelPen;

		return 1;
	}
///////////////////////////////////////////////////////////////////////////////
//invalidEdges.push(e);
//del_edges(invalidEdges);
//hide_edges(invalidEdges);

//ASSERT(outdeg(v0) == 1 && inf(target(first_out_edge(v0))) == a1);
///////////////////////////////////////////////////////////////////////////////
	double MatchEdges(const BipartiteEdgeGraph& g, const double& maxEdgeSim,
		const NodeParams& p) const;
		
/*! 
	@brief Sums a on-to-one mapping of edge contributions. 
	
	The sum is not normalized, which means that there more edges, 
	there higher the contribution might be. In turn, the contribution
	also dependes on edge similarity and salience. The presence of 
	many edges with high similarity and saliency constitutes 
	strong contextual evidence.
*/
double BGContextualSimilarityMeasurer::MatchEdges(const BipartiteEdgeGraph& g, 
												  const double& maxEdgeSim,
												  const NodeParams& p) const
{
	if (maxEdgeSim == 0)
		return 1;

	leda::edge e;

	//ASSERT(!ptrMatchInfo->HasEdgeSimilarity());

	EdgeValueArray edgeValues(g);
	NodeAssigmentList assigList;

	// Set the values of each candidate mapping (ie, edge) in the bipartite graph
	forall_edges(e, g)
		edgeValues[e] = EdgeSimilarity(g(e, 0), g(e, 1), p);

	g.SolveMaxWeightAssignment(edgeValues, &assigList);

	// Get the salience of the set 
	//const NodeAssigmentList& assigList = g.GetNodeAssigmentList();
	leda::list_item it;
	double sal1, sal2;
	//double cumSal1 = 0, cumSal2 = 0, partialCumSal = 0;
	double sim = 0;

	forall_items(it, assigList)
	{
		e = assigList[it];

		sal1 = pG1->GetBGEdge(g(e, 0))->Saliency();
		sal2 = pG2->GetBGEdge(g(e, 1))->Saliency();

		//cumSal1 += sal1;
		//cumSal2 += sal2;
		
		sim += edgeValues[e] * MIN(sal1, sal2);

		//sim += g.SimilarityValue(e) * (sal1 + sal2) / 2;
		//partialCumSal += MAX(sal1, sal2);
	}

	ASSERT(sim <= maxEdgeSim);

	return sim / maxEdgeSim;

	/*double unmatchedCumSal;

	if (pG1->outdeg(v1) >= pG2->outdeg(v2))
		unmatchedCumSal = TotalSaliency(pG1, v1) - cumSal1;
	else
		unmatchedCumSal = TotalSaliency(pG2, v2) - cumSal2;

	ASSERT(unmatchedCumSal >= 0);

	double maxCumSim = partialCumSal + unmatchedCumSal;

	if (maxCumSim > 0)
		sim /= maxCumSim;
	else
		sim = 1;

	ASSERT(sim >= 0 && sim <= 1);

	return sim;*/
}

///////////////////////////////////////////////////////////////////////////////
	//! Retrieves the similarity value associated with the assignment item 'it'
	const double& SimilarityValue(leda::list_item it) const
	{
		return SimilarityValue(m_nodeAssigments[it]);
	}

	//! First assignment or nil if there are no assigments
	leda::list_item FirstAssignment() const
	{
		return m_nodeAssigments.first();
	}

	//! Next assignment or nil if there are no more assignments
	leda::list_item NextAssignment(leda::list_item it) const
	{
		return m_nodeAssigments.succ(it);
	}

	//! Value associated with an assignment and a node in set 0 or 1
	leda::node operator()(leda::list_item it, int i) const
	{
		return operator()(m_nodeAssigments[it], i);
	}
///////////////////////////////////////////////////////////////////////////////
	// State that we don't have the one-to-one node assignments yet
	m_bHasNodeAssignment = false; 

///////////////////////////////////////////////////////////////////////////////
	const NodeSet& GetLargestSet() const
	{
		return (m_setA.size() >= m_setB.size()) ? m_setA : m_setB;
	}
////////////////////////////////////////////////////////////////////////////////	
	//! Set the value of the candidate assignemnt
	/*void SetEdgeValue(leda::edge e, const double& val)
	{
		ASSERT(!IsSolved());

		m_edgeValues[e] = val;
	}*/

////////////////////////////////////////////////////////////////////////////////	
/*void PrintNodeAssignments(std::ostream& os = std::cout) const
	{
		leda::list_item it;
		leda::edge e;

		os << "\n----------------------------------\n";

		forall_items(it, m_nodeAssigments)
		{
			e = m_nodeAssigments[it];

			os << GetDAGNodeDFSIndex(source(e)) << "<-->"
			   << GetDAGNodeDFSIndex(target(e)) << " = "
			   << SimilarityValue(e) << "\n";
		}

		os << std::endl;
	}*/
////////////////////////////////////////////////////////////////////////////////	
const T& e = inf(v);
////////////////////////////////////////////////////////////////////////////////	
/*//! True if there is a path from node 'a' to query node (i==0) or model nodel (i==1)
	bool IsAncestor(int i, leda::node a) const
	{
		return (TCM(i)[NodeIndex(i, a)][NodeIndex(i)] != 0);
	}*/
	
	/*//! True if there is a path from query node (i==0) or model nodel (i==1) to node 'd'
	bool IsDescendant(int i, leda::node d) const
	{
		return (TCM(i)[NodeIndex(i)][NodeIndex(i, d)] != 0);
	}*/
////////////////////////////////////////////////////////////////////////////////	
//DBG_PRINT2(inf(e)->GetSimilarityValue(), ptr->GetSimilarityValue())
////////////////////////////////////////////////////////////////////////////////	

	void RestoreLigature(const LigatureSegment& ls)
	{
		ASSERT(!ls.IsEmpty);
		ASSERT(ls.Last() + 1 == bs.First() || bs.Last() + 1 == ls.First());

		if (ls.Last() + 1 == bs.First())
			SetLimits(ls.First(), Last());
		else if (bs.Last() + 1 == ls.First())
			SetLimits(First(), ls.Last());
	}
	
////////////////////////////////////////////////////////////////////////////////	

//void BGC::AddEdgesFromGSGJunction(leda::node t)
//{
//	ASSERT(m_genSkelGraph.GetNodeType(t) == GSG_JUNCTION);
//	ASSERT(indeg(t) == 0);
//
//	std::vector<leda::edge> possibleRootEdges; 
//	leda::edge e;
//
//	// Find all non-ligature segments incident to the junction. These are
//	// the only ones that could become the "root" node
//	forall_out_edges(e, t)
//	{
//		ASSERT(m_genSkelGraph.GetEdge(e).m_position == 0);
//
//		if (!m_genSkelGraph.GetEdge(e).HasLigaturePoints() && 
//			!m_genSkelGraph.GetNode(target(e)).GetBonePart().IsEmpty())
//			possibleRootEdges.push_back(e);
//	}
//
//	/*if (possibleRootEdges.size() != 1)
//	{
//		double area, maxArea = -1;
//		leda::edge parentEdge = nil;
//		BranchSegment bone;
//
//		possibleRootEdges.clear();
//
//		forall_out_edges(e, t)
//		{
//			bone = m_genSkelGraph.GetNode(target(e)).GetBonePart();
//			area = bone.ComputeArea(false, false);
//
//			if (area > maxArea)
//			{
//				maxArea = area;
//				parentEdge = e;
//			}
//		}
//
//		if (parentEdge != nil)
//			possibleRootEdges.push_back(parentEdge);
//	}*/
//
//	// If there is only one, the choice is clear
//	if (possibleRootEdges.size() == 1)
//	{
//		e = possibleRootEdges.front();
//		m_genSkelGraph.rev_edge(e); // make it root by reversing the edge
//
//		const GSGNode& rootNode = m_genSkelGraph.GetNode(source(e)); 
//		const GSGNode& juncNode = m_genSkelGraph.GetNode(t); 
//
//		const BranchSegment rootBone = rootNode.GetBonePart();
//		SkelPtIndex pos;
//
//		// Set the position of the end-to-end attachment
//		ASSERT(rootBone.FirstPtCoord() == juncNode.GetJointCoord() || 
//			rootBone.LastPtCoord() == juncNode.GetJointCoord());
//
//		if (rootBone.FirstPtCoord() == juncNode.GetJointCoord())
//			pos = rootBone.First();
//		else
//			pos = rootBone.Last();
//
//		forall_out_edges(e, t)
//		{
//			m_genSkelGraph.GetEdge(e).m_position = pos;
//		}
//	}
//	else
//	{
//		leda::node r = m_genSkelGraph.AddRootBranchNodeToJunctionNode(t);
//		GSGNode& gsgnode = m_genSkelGraph.GetNode(r);
//
//		// Define a new entry in the gsgnode-bone map, and create a new bone node
//		AddBGNode(gsgnode.GetBonePart(), m_gsgNodeToBones[r], BGElement::SIMPLE_ROOT_BONE);
//
//		// All EE positions should already be zero by default
//
//		//ComputeRadiusFunction(BGNode* pBGNode);
//	}
//}


////////////////////////////////////////////////////////////////////////////////	
// Make sure that all attachments have valid positions
	//OrganizeAttachments(); //TODO: do we still need this?

	// The graph is built, we can now set the junction positions
	//SetJunctionPositions();
	//AssignRootNodesToJunctions();
	
/*!
	@brief Moves attachments that have a "negative" position to their
	parents attachment nodes.

	Once a branch is restored, it can be seen as an "attaching" branch itself,
	which will subtract the ligature interval from the branch. This can happend
	on both sides of a branch. Since the branch was restored it means that it had
	branches attaching to it and the position of those attachments could now be
	outside the new branch segment defined by the trailing ligature segments.

	In these case, we move the attachments such that they are related to a valid
	position in some of its parent branches.

	Eg, let A be attachment nodes and a number be some branch node:
	    1 -> A0 -> 0 -> A2 -> 2
		
		ie, branch 1 is attached to branch 0 which itself is attached to branch 2

	If branch 1 has a position outside the branch segment of 0, we move the edge 1-A0
	to the new edge 1-A2.

	The algorithm works even when the same edge needs to be multiple times and it does
	not depend on the order in which nodes are evaluated.
*/
void GSG::OrganizeAttachments()
{
	std::vector<leda::edge> attVec;
	leda::node v, a0;
	leda::edge e, pe;
	SkelPtCoord j0, j1, pt;

	forall_nodes(v, *this)
	{
		GSGNode& gn = GetNode(v);

		if (gn.m_type == GSG_BRANCH)
		{
			GetSourceAttachments(v, &attVec); // up to two (ie, H case)
			a0 = GetTargetNode(v, GSG_ATTACHMENT);

			if (attVec.size() > 0 && a0 != nil)
			{
				BranchSegment bs = gn.GetBonePart();

				j0 = GetEdge(attVec[0]).m_pAttachJoint->fp.p;

				// If we have an H case, we alse need the other joint
				if (attVec.size() > 1) 
					j1 = GetEdge(attVec[1]).m_pAttachJoint->fp.p;

				ASSERT(outdeg(a0) >= 1 && indeg(a0) == 1);

				forall_out_edges(e, a0)
				{
					if (!bs.IsInside(GetEdge(e).m_position)) 
					{	
						pt = GetEdge(e).m_pAttachJoint->fp.p;

						// Get the parent's edge to one of its attachment node(s)
						if (attVec.size() == 1 || (j0.sqDist(pt) < j1.sqDist(pt)))
							pe = attVec[0];
						else
							pe = attVec[1];

						DBG_MSG1("Moving edge...")
						move_edge(e, source(pe), target(e));
						GetEdge(e).m_position = GetEdge(pe).m_position;
					}
				}

				if (outdeg(a0) == 0)
					del_node(a0);
			}
		}
	}
}


/*!
	@brief Deprecated function. Do not use it.
*/
void GSG::SetJunctionPositions()
{
	leda::node v;
	leda::edge e;

	forall_nodes(v, *this)
	{
		if (GetNode(v).m_type == GSG_JUNCTION)
		{
			ASSERT(indeg(v) == 1);

			GSGNode& gn           = GetNode(source(first_in_edge(v))); // parent node (the source)
			BranchSegment bs      = gn.GetBonePart();                  // source branch segment
			const SkelPtCoord& pt = GetNode(v).m_pJoint->fp.p;

			ASSERT(IsEndpointOf(GetNode(v).m_pJoint, bs.m_pBranch));

			if (bs.IsEmpty())
			{
				DBG_MSG2("Things are wrong at junction", GetNode(v).m_pJoint->fp.p)

				ASSERT(!gn.HasFixedBranch());

				BranchSegment bs2(bs.m_pBranch);

				gn.m_segments.front() = bs2;
				bs = bs2;
			}

			ASSERT(!bs.IsEmpty());
			ASSERT(pt == bs[bs.First()].p || pt == bs[bs.Last()].p);
				
			unsigned int pos = (pt == bs[bs.First()].p) ? bs.First() : bs.Last();

			forall_out_edges(e, v)
			{
				GetEdge(e).m_position = pos;
			}
		}
	}
}

void GSG::AssignRootNodesToJunctions()
{
	leda::node v;
	leda::edge e;

	forall_nodes(v, *this)
	{
		if (GetNode(v).m_type == GSG_JUNCTION)
		{
			ASSERT(indeg(v) == 0);
		}
	}
}

////////////////////////////////////////////////////////////////////////////////	
// Update parametersffected by the merge
	const double combinedSaliency = Saliency() + pTgtNode->Saliency();
////////////////////////////////////////////////////////////////////////////////	
// If lastNode is equal to matchedNode and dir is 0, then we have
						// a parent node and must also compute SSD-based penalties.
						if (dir == 0 && lastNode == matchedNode)
							ApplyPenaltiesToNonSiblingOrSiblingDescendants(npi, i, u, procEdges);
							
void BNG::ApplyPenaltiesToNonSiblingOrSiblingDescendants(const NodePairInfo& npi, 
							 int i, leda::node u, 
							 leda::edge_array<bool>& procEdges)
{
	leda::edge e;
	leda::node v = npi.GetMatchedNode(i);;

	forall_out_edges(e, u)
	{
		if (target(e) == v)
			continue;
		

	}
}
////////////////////////////////////////////////////////////////////////////////	
/*
	@brief Creates a similarity matrx between nodes in set m_setA and
	nodes in set m_setB.
*/
/*SmartMatrix<leda::edge> BNG::CreateSimilarityMatrix() const
{
	SmartMatrix<leda::edge> simMat;
	leda::edge e;
	int i, j;

	DBG_PRINT2(m_setA.size(), m_setB.size())
	simMat.Resize(m_setA.size(), m_setB.size(), true); // init mattrix to zeros

	forall_edges(e, *this)
	{
		i = GetDAGNodeDFSIndex(source(e));
		j = GetDAGNodeDFSIndex(target(e));

		simMat[i][j] = e;
	}

	return simMat;
}*/
////////////////////////////////////////////////////////////////////////////////	
/*void SetMatchingNodeColors(DAGPtr& ptrG1, DAGPtr& ptrG2, const NodeMatchMap& map)
{
	leda::node v;

	// Init all node colors in g2 to "unmatched"
	forall_nodes(v, g2)
		gw.set_color(v, leda::red);

	forall_nodes(v, g1)
	{
		if (map[v].IsEmpty())
		{
			gw.set_color(v, leda::red);
		}
		else
		{
			gw.set_color(v, leda::blue);
			gw.set_color(map[v].node, leda::blue);
		}
	}
}*/

////////////////////////////////////////////////////////////////////////////////	
double TotalSaliency(const BoneGraph* pBG, leda::node v) const
{
	leda::edge e;
	double totalSaliency = 0;

	forall_out_edges(e, v)
	{
		totalSaliency += pG1->GetBGEdge(e)->Saliency();
	}

	return totalSaliency;
}
////////////////////////////////////////////////////////////////////////////////	

class SGDistMeasurer1: public SGNodeDistanceMeasurer
{
	// The following integers will be the relative weights
	// that will be given to the 1st and 2nd level of matching.
	double w1, w2;
	
	virtual double CompDistance(ConstraintsPtr ptrConstraints) const;
	
public:
	SGDistMeasurer1() { w1 = .7; w2 = 1 - w1; }	
	void SetWeights(double level1Weight, double level2Weight);
	
private:
	double NodeDistanceLevel2(leda_node a, leda_node b) const;
	
	double rule1(leda_node a, leda_node b) const;
	double rule2(leda_node a, leda_node b) const;
	double rule3(leda_node a, leda_node b) const;
	double rule4(leda_node a, leda_node b) const;
	double rule5_6(leda_node a, leda_node b) const;
	
	double NodeDistanceLevel1() const;
	
	double ElongationDiff() const;
	double SweepContrastDiff() const;
	double TaperDiff() const;
	double AccelerationDiff() const;
	double BendDiff() const;
	
	double AverageRadius(const SGNode *u) const;
	double Length(const SGNode *u) const;
	double Elongation(const SGNode *u) const;
	double SweepContrast(const SGNode *u) const;
	double Acceleration(const SGNode *u) const;
	double Bend(const SGNode *u) const;
	double Taper(const SGNode *u) const;
};

double SGDistMeasurer1::ComputeSimilarity(ConstraintsPtr ptrConstraints) const
{		
	double level1 = NodeDistanceLevel1();
	double level2 = 0;

	//	double level2 = NodeDistanceLevel2(v1,v2);
		
	/*if(pG1->GetNodeLbl(v1) == pG2->GetNodeLbl(v2)){
//	cout << pG1->GetNodeLbl(v1) << "<>" << pG2->GetNodeLbl(v2) << endl;
//	cout << level1 << ":" <<level2 << endl;
}*/
	
	//double value = w1 * (level1) + w2 * (level2);
	double value = level1;
	
	//cout << " s = " << value;
	
	ASSERT(value >= 0 && value <= 1);
	
	return value;
}

/* 
Takes two numbers which represent the relative weights 
of level1 vs level2 in the node distance calculation.
*/
void SGDistMeasurer1::SetWeights(double level1Weight, double level2Weight)
{
	ASSERT(level1Weight + level2Weight == 1);
	
	w1 = level1Weight;
	w2 = level2Weight;
}

double SGDistMeasurer1::AverageRadius(const SGNode *sb) const
{
	double min_rad = 999999;
	double max_rad = 0;
	double avg_rad = 0;
	int shockCount;
	
	shockCount = sb->GetShockCount();
	
	for (int j = 0; j < shockCount; j++)
    {
		double curr_rad = sb->m_shocks[j].radius;	    
		if (curr_rad > max_rad)
			max_rad = curr_rad;
		if (curr_rad < min_rad)
			min_rad = curr_rad;
		
		avg_rad += curr_rad;
    }
	
	if (shockCount != 0)
		avg_rad /= shockCount;
	return avg_rad;
}

double SGDistMeasurer1::Length(const SGNode *sb) const
{
	int shockCount = sb->GetShockCount();
	
	double distance = 0;
	double x1,x2,y1,y2;
	
	for(int i = 1; i < shockCount; i++)
    {
		x1 =  sb->m_shocks[i-1].xcoord;
		y1 =  sb->m_shocks[i-1].ycoord;
		
		x2 =  sb->m_shocks[i].xcoord;
		y2 =  sb->m_shocks[i].ycoord;
		
		distance += sqrt(pow(x2-x1,2.0) + pow(y2-y1,2.0));
    }
	
	return distance;
}

double SGDistMeasurer1::Elongation(const SGNode *sb) const
{
	double avg_radius_sb = AverageRadius(sb);
	double length = Length(sb);
	double elongation;
	
	
	if(length != 0)
	  {
	    // This just normalizes the value.
	    elongation = (avg_radius_sb/length)/(avg_radius_sb + length);
	  }
	else
	  elongation = avg_radius_sb;
	//	cout << "elongation = " << elongation << endl;
	return elongation;
		
}

double SGDistMeasurer1::Bend(const SGNode *u) const
{
	double x1,x2,y1,y2;
	int numSinModel = u->GetShockCount();
	
	if(numSinModel <= 3)
		return M_PI;
	
	x1 =  u->m_shocks[numSinModel/2].xcoord - u->m_shocks[0].xcoord;
	x2 =  u->m_shocks[numSinModel-1].xcoord - u->m_shocks[numSinModel/2].xcoord;
	
	y1 =  u->m_shocks[numSinModel/2].ycoord - u->m_shocks[0].ycoord;
	y2 =  u->m_shocks[numSinModel-1].ycoord - u->m_shocks[numSinModel/2].ycoord;
	
	
	double value = (x1*x2+y1*y2)/(sqrt(pow(x1,2.0)+pow(y1,2.0))*sqrt(pow(x2,2.0)+pow(y2,2.0)));
	double theta;
	
	if(fabs(value) <= 1)
		theta = acos(value);
	else
		theta = 0;
	
	return theta;
}


double SGDistMeasurer1::SweepContrast(const SGNode *node) const
{
	
	double min_rad = 999999;
	double max_rad = 0;
	double curr_rad = 0;
	double sweep_contrast = 0.0;
	
	int shockCount = node->GetShockCount();

	if (shockCount <= 0)
		return 0;
	
	double LengthNode = Length(node);
	
	for (int j = 0; j < shockCount; j++)
    {
		double curr_rad = node->m_shocks[j].radius;
	    
		if (curr_rad > max_rad)
			max_rad = curr_rad;

		if (curr_rad < min_rad)
			min_rad = curr_rad;
    }

	if (max_rad > 0.0)
		sweep_contrast = ((double) max_rad - (double) min_rad) / (double) max_rad;

	return(sweep_contrast);
}


double SGDistMeasurer1::Taper(const SGNode *u) const
{
	
	int numSinNode = u->GetShockCount();  
	double length = Length(u);
	double slope;
	double del_radius;

	if (numSinNode < 2)
		return 0.0;
	
	del_radius = fabs(u->m_shocks[0].radius - u->m_shocks[numSinNode - 1].radius);
	
	if (del_radius == 0.0)
	{
		slope = 0.0;
	}
	else
	{
		slope = del_radius / length;
	}
	//	cout << "del_radius = " << del_radius << " length = " << length << " slope = " << slope << endl;
	
	return(slope);
}

double SGDistMeasurer1::Acceleration(const SGNode *u) const
{
	int numShocks = u->GetShockCount();
	double accelerationSum = 0;
	
	for(int i = 2; i < numShocks; i++)
    {
		// These are the X and Y coordinates 
		// in the shocks that will be used 
		// to approximate the derivative.
		double x1 =  u->m_shocks[i-2].xcoord;
		double x2 =  u->m_shocks[i-1].xcoord;
		double x3 =  u->m_shocks[i].xcoord;
		
		double y1 =  u->m_shocks[i-2].ycoord;
		double y2 =  u->m_shocks[i-1].ycoord;
		double y3 =  u->m_shocks[i].ycoord;
		
		double radius1 =  u->m_shocks[i-2].radius;
		double radius2 =  u->m_shocks[i-1].radius;
		double radius3 =  u->m_shocks[i].radius;
		
		double D1 = sqrt(pow(x2-x1,2.0) + pow(y2-y1,2.0));
		double D2 = sqrt(pow(x3-x2,2.0) + pow(y3-y2,2.0));
		
		double dT1 = radius2 - radius1;
		double dT2 = radius3 - radius2;
		
		double V1 = D1/dT1;
		double V2 = D2/dT2;
		
		double A = (V2 - V1)/dT2 - dT2;
		
		accelerationSum += A;
    }  
	return accelerationSum;
}

double SGDistMeasurer1::ElongationDiff() const
{
	double u_elongation = Elongation(pNode1);
	double v_elongation = Elongation(pNode2);
	
	double elongation_diff;
	
	if(fabs(v_elongation + u_elongation) != 0)
		elongation_diff = fabs(v_elongation - u_elongation)/fabs(v_elongation + u_elongation);
	else{
		elongation_diff =  fabs(v_elongation - u_elongation);
	}
	
	return elongation_diff;
}

double SGDistMeasurer1::TaperDiff() const
{
	double taper_u = Taper(pNode1);
	double taper_v = Taper(pNode2);
	
	double taper_max, taper_diff;
	
	if (taper_u >= taper_v) 
	{
		taper_max = taper_u;
	}
	else
	{
		taper_max = taper_v;
	}
	if (taper_max == 0)
	{
		taper_diff = 0;
	}
	else
	{
		taper_diff = fabs(taper_u - taper_v)/taper_max;
	}
	return(taper_diff);
}

double SGDistMeasurer1::SweepContrastDiff() const
{
	double u_sweep_contrast = SweepContrast(pNode1);
	double v_sweep_contrast = SweepContrast(pNode2);
	double max_sweep_contrast = 0.0;
	
	
	double sweep_contrast_diff = 0.0;
	
	if (u_sweep_contrast >= v_sweep_contrast)
	{
		max_sweep_contrast = u_sweep_contrast;
	}
	else
	{
		max_sweep_contrast = v_sweep_contrast;
	}
	
	if((u_sweep_contrast == 0.0) && (v_sweep_contrast == 0.0))
	{
		sweep_contrast_diff = 0;
	}
	else
	{
		sweep_contrast_diff = fabs(u_sweep_contrast - v_sweep_contrast)/max_sweep_contrast;
	}
	
	return (sweep_contrast_diff);
}

/* 
This takes two nodes and returns a number representing
the distance between these two nodes in terms of the
2nd derivative of the radius vs time "graph".
*/

double SGDistMeasurer1::AccelerationDiff() const
{
	double u_acc = Acceleration(pNode1);
	double v_acc = Acceleration(pNode2);
	
	double acc_diff;
	
	if(fabs(v_acc) + fabs(u_acc) != 0)
		acc_diff = fabs(v_acc -u_acc)/(fabs(v_acc)+fabs(u_acc));
	else
		acc_diff =  fabs(v_acc - u_acc);
	
	return acc_diff;
}

/* 
This takes two nodes and returns a number representing
the distance between these two nodes in terms of an
approximation of an angle that represents it's medial
axis.
*/

double SGDistMeasurer1::BendDiff() const
{
	double u_bend = Bend(pNode1);
	double v_bend = Bend(pNode2);
	
	double bend_diff = fabs(u_bend - v_bend)/M_PI;
	
	return bend_diff;
}

/* 
This function is the control function for the first level of
matching. 
*/
double SGDistMeasurer1::NodeDistanceLevel1() const
{ 
	int uType = pG1->NodeType(v1);
	int vType = pG2->NodeType(v2);
	
	if (uType == ROOT && vType == ROOT)
		return 0;
	else if(uType == ROOT || vType == ROOT)
		return 1;
		
	//cout << endl << pG1->GetNodeLbl(v1) << " <> " << pG2->GetNodeLbl(v2);
	
	if(uType == SHOCK_1 && vType == SHOCK_1)
    {
		if (pNode1->GetShockCount() <= 1 || pNode2->GetShockCount() <= 1)
		{
			DBG_MSG1("Warning: Type 1 node with 1 or 0 shocks!")
			return 1;
		}

		double taper = TaperDiff();
		//		double acc = AccelerationDiff();
		double bend = BendDiff();
		double elongation = ElongationDiff();
		
		//		cout << "taper diff = " << taper << " bend diff = " << bend << " elongation diff = " << elongation << endl;
		
		
		double value = 0.5*taper + 0.2*bend + 0.3*elongation; // + 0.1*acc;
		
		if(value <= 1 && value >= 0)
			return value;
		else if(value < 0)
		{
			cerr << "Error in the distance calculation type 1 SHOCK!!" << value << endl;
			ASSERT(false);
			return -1;
		}
		else
		{
			cerr << "Error in the normalization type 1 SHOCK!!" << value << endl;
			ASSERT(false);
			return -1;
		}
    }
	else if(uType == SHOCK_3 && vType == SHOCK_3)
    {
		if (pNode1->GetShockCount() <= 1 || pNode2->GetShockCount() <= 1)
		{
			DBG_MSG1("Warning: Type 3 node with 1 or 0 shocks!")
			return 1;
		}

		double bend = BendDiff();
		double elongation = ElongationDiff();
		
		if(bend <= 1 && bend >= 0)
		{
			double value = 0.8*bend + 0.2*elongation;
			
			if(value >= 0 && value <= 1)
				return value;
			else
			{
				cerr << "Error in the distance calculation type 3 SHOCK!!" << bend << endl;
				ASSERT(false);
				return -1;
			}
		}
		else if(bend < 0 || elongation < 0)
		{
			cerr << "Error in the distance calculation type 3 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -1;
		}
		else
		{
			cerr << "Error in the normalization type 3 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -11;
		}
    }
	else if(uType == SHOCK_2 && vType == SHOCK_2)
    {
		if (pNode1->GetShockCount() <= 0 || pNode2->GetShockCount() <= 0)
		{
			DBG_MSG1("Warning: Type 2 node with 0 shocks!")
			return 1;
		}

		double bend = BendDiff();
		double elongation = ElongationDiff();
		double contrast_sweep = SweepContrastDiff();
		
		//		cout << "cont sweep diff = " << contrast_sweep << " bend diff = " << bend << " elongation diff = " << elongation << endl;
		
		if(bend <= 1 && bend >= 0)
		{
			double value = 0.3 * bend + 0.2 * elongation + 0.5 * contrast_sweep;
			
			if(value >= 0 && value <= 1)
				return value;
			else
			{
				cerr << "Error in the distance calculation type 2 SHOCK!!" << bend << endl;
				ASSERT(false);
				return -1;
			}
		}
		else if(bend < 0 || elongation < 0)
		{
			cerr << "Error in the distance calculation type 2 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -1;
		}
		else{
			cerr << "Error in the normalization type 2 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -1;
		}
    }
	else if(uType == SHOCK_4 && vType == SHOCK_4)  //updated to compare non-perfect blobs, using same criteria as type 2.
    {
		double bend = BendDiff();
		double elongation = ElongationDiff();
		
		if(bend <= 1 && bend >= 0)
		{
			double value = 0.8*bend + 0.2*elongation;
			
			if(value >= 0 && value <= 1)
				return value;
			else
			{
				cerr << "Error in the distance calculation type 2 SHOCK!!" << bend << endl;
				ASSERT(false);
				return -1;
			}
		}
		else if(bend < 0 || elongation < 0)
		{
			cerr << "Error in the distance calculation type 2 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -1;
		}
		else{
			cerr << "Error in the normalization type 2 SHOCK!!" << bend << endl;
			ASSERT(false);
			return -1;
		}
    }
	else if((vType == SHOCK_1 && uType == SHOCK_3) || (vType == SHOCK_3 && uType == SHOCK_1))
    {    
		double taper = TaperDiff();
		double bend = BendDiff();
		double elongation = ElongationDiff();
		
		double value = 0.5*taper + 0.3*elongation +  0.2*bend;
		
		if(value <= 1)
			return value;
		else if(value < 0){
			cerr << "Error in comparison of TYPE 3 and 1!! " << value << endl;
			ASSERT(false);
			return -1;
		}
		else
		{
			cerr << "Error in normalization of TYPE 3 and 1!! " << value << endl;
			ASSERT(false);
			return -1;
		}
    }
	/*	else if((uType == SHOCK_3 && vType == SHOCK_2) || (uType == SHOCK_2 && vType == SHOCK_3))
    {
	double bend = BendDiff();
	double elongation = ElongationDiff();
	
	 if(bend <= 1 && bend >= 0)
	 {
	 double value = 0.8*bend + 0.2*elongation;
	 
	  if(value >= 0 && value <= 1)
	  return value;
	  else
	  {
	  cerr << "Error in the distance calculation type 3 SHOCK!!" << bend << endl;
	  ASSERT(false);
	  return -1;
	  }
	  }
	  else if(bend < 0 || elongation < 0)
	  {
	  cerr << "Error in the distance calculation type 3 SHOCK!!" << bend << endl;
	  ASSERT(false);
	  return -1;
	  }
	  else
	  {
	  cerr << "Error in the normalization type 3 SHOCK!!" << bend << endl;
	  ASSERT(false);
	  return 1;
	  }
	  }
	*/
	else{
		
		return 1;
	}
}

/* 
This function implements rule 1 of the grammar. It tries to quantify how
close the roots (a and b) are to each other in terms of the sub tree they
generated. 
*/

double SGDistMeasurer1::rule1(leda_node a, leda_node b) const
{
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);
	
	double num_3A = 0, num_3B = 0, num_4A = 0,num_4B = 0;
	
	leda_node w,s;
	
	if(aType == ROOT &&  bType == ROOT)
    {
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_3)
				num_3A++;
			else if(pG1->NodeType(w) == SHOCK_4)
				num_4A++;
		}
		
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_3)
				num_3B++;
			else if(pG2->NodeType(s) == SHOCK_4)
				num_4B++;
		}
		
		if(num_3A + num_4A == 0){
			cerr << "Tree has no children of the root" << endl;
			ASSERT(false);
			return -1;
		}
		
		if(num_3B + num_4B == 0){
			cerr << "Tree has no children of the root" << endl;
			ASSERT(false);
			return -1;
		}
		
		double score;
		
		if(num_3A + num_3B > 0)
			score = fabs(num_3A - num_3B)/(num_3A + num_3B);
		else if(num_3A + num_3B == 0)
		{
			score = 0;
		}
		else
		{
			cerr << "Tree has a negative number of children of the root node" << endl;
			ASSERT(false);
			return -1;
		}
		
		if(num_4A + num_4B > 0)
			score += fabs(num_4A - num_4B)/(num_4A + num_4B);
		else if(num_4A + num_4B == 0)
		{
			score += 0;
		}
		else
		{
			cerr << "Tree has a negative number of children of the root node" << endl;
			ASSERT(false);
			return -1;
		}
		
		return score/2;
    }
	else
    {
		return 1;
    }
}

/* 
This function tries to check how closely related both nodes
that were generated from rule 2 match. 
*/

double SGDistMeasurer1::rule2(leda_node a, leda_node b)  const
{
	leda_node w,s;
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);
	
	int num_child_a = 0, num_child_b = 0;
	
	if(aType == SHOCK_4 && bType == SHOCK_4)
    {
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_1)
				num_child_a++;
		}
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_1)
				num_child_b++;
		}
		
		if (pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		else if (pG1->outdeg(a) == 0 || pG2->outdeg(b) == 0)
			return 1;
    }
	else
    {
		return 1;
    }
	
	double sim = abs(num_child_a - num_child_b);
	
	
	// If this isn't true then it must go into death
	// and it's outdeg should be zero!! I check for 
	// this above.
	ASSERT(num_child_a + num_child_b > 0);
	
	// normalizing
	sim = sim/(num_child_a +num_child_b);
	
	return sim;
}

/* 
This function tries to check how closely related both nodes
that were generated from rule 3 match. NOTE this function
assumes that the nodes being passed as parameters are of
type 3.
*/

double SGDistMeasurer1::rule3(leda_node a, leda_node b)  const
{
	
	leda_edge e = pG1->first_in_edge(a);
	leda_edge f = pG2->first_in_edge(b);
	
	int aParentType, bParentType;
	int num_child_a = 0, num_child_b = 0;
	
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);  
	
	
	// If a node has been removed such that it
	//  no longer has any parent then we will
	// assume that it's parent is the ROOT.
	if(e == nil && f == nil)
    {
		aParentType = ROOT;
		bParentType = ROOT;   
    }
	else if (e == nil || f == nil)
    {
		return 1;
    }
	else
    {
		aParentType = pG1->NodeType(pG1->source(e));
		bParentType = pG2->NodeType(pG2->source(f));
    }
	
	leda_node w,s;
	
	// rule 3a
	if(aParentType == SHOCK_1 && bParentType == SHOCK_1 
		&& pG1->indeg(a) == 1 && pG2->indeg(b) == 1)
    {
		
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_1)
				num_child_a++;
		}
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_1)
				num_child_b++;
		}
		
		// If both go to death...
		if (pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		else if (pG1->outdeg(a) == 0 || pG2->outdeg(b) == 0)
			return 1;
    }
	else if(aParentType == ROOT && bParentType == ROOT)
    {
		// Rule 3 b
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_1)
				num_child_a++;
		}
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_1)
				num_child_b++;
		}
		
		if (pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		if (pG1->outdeg(a) == 0 || pG2->outdeg(b) == 0)
			return 1;
    }
	else
    {
		return 1;
    }
	
	double sim = abs(num_child_a - num_child_b);
	
	// If this isn't true then it must go into death
	// and it's outdeg should be zero!! I check for 
	// this above.
	ASSERT(num_child_a + num_child_b > 0);
	
	// normalizing
	sim = sim/(num_child_a + num_child_b);
	
	return sim;
}

/* 
This function tries to check how closely related both nodes
that were generated from rule 4 match. 
*/

double SGDistMeasurer1::rule4(leda_node a, leda_node b)  const
{
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);
	int num_child_a = 0, num_child_b = 0;
	leda_node w,s;
	
	if(aType == SHOCK_1 && bType == SHOCK_1)
    {
		// If they go to death
		if (pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		else if (pG1->outdeg(a) == 0 || pG2->outdeg(b) == 0)
			return 1;
		
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_1)
				num_child_a++;
		}
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_1)
				num_child_b++;
		}
    }
	else
    {
		return 1;
    }
	
	double sim = abs(num_child_a - num_child_b);
	
	// If this isn't true then it must go into death
	// and it's outdeg should be zero!! I check for 
	// this above.
	ASSERT(num_child_a + num_child_b > 0);
	
	
	sim = sim/(num_child_a +num_child_b);
	
	return sim;
}


/* 
This function tries to check how closely related both nodes
that were generated from rule 5 match. 
*/

double SGDistMeasurer1::rule5_6(leda_node a, leda_node b)  const
{
	
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);
	int num_2child_a = 0; 
	int num_2child_b = 0;
	int num_3child_a = 0; 
	int num_3child_b = 0;
	leda_node w,s;
	
	if(aType == SHOCK_1 && bType == SHOCK_1)
    {
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_2)
				num_2child_a++;
			else if (pG1->NodeType(w) == SHOCK_3)
				num_3child_a++;
		}
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_2)
				num_2child_b++;
			else if (pG2->NodeType(s) == SHOCK_3)
				num_3child_b++;
		}    
		
		/* This checks that a type 1 doesn't have more than
		1 type 2 child. */
		ASSERT(num_2child_a <= 1 && num_2child_b <= 1);
		
		/* This checks that a type 1 doesn't have more than
		1 type 3 child. */
		ASSERT(num_3child_a <= 1 && num_3child_b <= 1);
		
		if (pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		else if (pG1->outdeg(a) == 0 || pG2->outdeg(b) == 0)
			return 1;
		
		// rule 5
		if(num_2child_a == 1 && num_2child_b == 1){
			return 0;
		}
		else if(num_3child_a == 1 && num_3child_b == 1)
		{
			// rule 6a
			leda_node t,r;
			
			forall_adj_nodes(t, a)
			{
				forall_adj_nodes(r, b)
				{
					if(pG1->indeg(t) == 2 && pG2->indeg(r) == 2)
						return 0;
					else if(pG1->indeg(t) == 1 && pG2->indeg(r) == 1)
						return 0;
					else{
						return 1;
					}
				}
			}
		}
		else{
			// Nodes have different types of children
			return 1;
		}
    }
	else
	{
		return 1;
	}

	return 0;
}

/* 
This function is the control function for the second level of
matching. 
*/
double SGDistMeasurer1::NodeDistanceLevel2(leda_node a, leda_node b) const
{
	
	int aType = pG1->NodeType(a);
	int bType = pG2->NodeType(b);
	
	if (aType == ROOT && bType == ROOT)
		return rule1(a,b);
	else if(aType == ROOT || bType == ROOT)
		return 1;
	
	if(pG1->NodeRole(a) == DUMMY && pG2->NodeRole(b) == DUMMY)
    {
		return 0;
    }
	else if(pG1->NodeRole(a) == DUMMY || pG2->NodeRole(b) == DUMMY)
    {
		return 1;
    }
	
	int aParentType = pG1->NodeType(pG1->source(pG1->first_in_edge(a)));
	int bParentType = pG2->NodeType(pG2->source(pG2->first_in_edge(b)));
	
	leda_node parent_a = pG1->source(pG1->first_in_edge(a));
	leda_node parent_b = pG2->source(pG2->first_in_edge(b));
	
	if(aType == SHOCK_1 && bType == SHOCK_1)
    {
		double parent_score;
		
		// IF BOTH EMERGED FROM RULE 2
		if(aParentType == SHOCK_4 && bParentType == SHOCK_4)
		{
			// This will return a normalized number which
			// is the difference in siblings for each of
			// a and b
			
			parent_score = rule2(parent_a, parent_b);
		}
		// IF BOTH EMERGED FROM RULE 3
		else if(aParentType == SHOCK_3 && bParentType == SHOCK_3)
		{
			parent_score = rule3(parent_a, parent_b);
		}
		// IF BOTH EMERGED FROM RULE 4
		else if(aParentType == SHOCK_1 && bParentType == SHOCK_1)
		{
			parent_score = rule4(parent_a, parent_b);
		}
		else
		{
			// Nodes didn't emerge from the same production rule.
			parent_score = 1;
		}
		
		
		
		leda_node w,s;
		bool rule4a = false, rule4b = false;
		
		forall_adj_nodes(w, a)
		{
			if (pG1->NodeType(w) == SHOCK_1){
				rule4a = true;
				break;
			}
		}
		
		forall_adj_nodes(s, b)
		{
			if (pG2->NodeType(s) == SHOCK_1){
				rule4b = true;
				break;
			} 
		}    
		
		// DESCENDANTS SIMILARITY
		
		double child_score;  
		
		if(rule4a && rule4b)
		{
			child_score = rule4(a, b);
		}
		else if(!rule4a && !rule4b)
		{
			child_score = rule5_6(a, b);
		}
		else if(pG1->indeg(a) == 0 && pG2->indeg(b) == 0){
			// If both go to death
			child_score = 0;
		}
		else
		{
			child_score = 1;
		}
		return (parent_score + child_score)/2;
    }
	else if(aType == SHOCK_2 && bType == SHOCK_2)
    {
		// ANCESTOR SIMILARITY
		if(aParentType == SHOCK_1 && bParentType == SHOCK_1 && pG1->outdeg(a) == 0 && pG2->outdeg(b) == 0)
			return 0;
		else
		{
			cerr << "A type 2 shock doesn't go to death or have type 1 parents!!" << endl;
			ASSERT(false);
			return -1;
		}
    }
	else if(aType == SHOCK_3 && bType == SHOCK_3)
    {
		double child_score = rule3(a, b);    
		double ancestor_score;
		
		if(aParentType == ROOT && bParentType == ROOT)
			ancestor_score = 0;
		else if(pG1->indeg(a) == 2 && pG2->indeg(b) == 2)
			ancestor_score = 0;
		else if(pG1->indeg(a) == 1 && pG2->indeg(b) == 1)
		{
			ancestor_score = 0;
		}
		else
			ancestor_score = 1;
		
		return (child_score + ancestor_score)/2;
    }
	else if(aType == SHOCK_4 && bType == SHOCK_4)
    {
		// Descendants
		double child_score = rule2(a, b);
		// parents
		double parent_score = rule1(parent_a,parent_b);
		
		return (child_score + parent_score)/2;
    }
	else{
		return 1;
	}
}

//////////////////////////////////////////////////////////////////////////////
// SGDistMeasurer2

#define MAX_DIST       100
#define DIFF_ROLE_DIST 100
#define DIFF_TYPE_DIST 1

/*void DbgNodeSimilarity(const ShockGraph& sg1, leda_node u, const ShockGraph& sg2, leda_node v,
double scale, double dr, double dv, 
double branchSim, double tsvSim, double nodeSim)
{
static bool bFirstTime = true;
static fstream dbg;

 if (bFirstTime)
 {
 bFirstTime = false;
 dbg.open("nodesim.log", ios::trunc | ios::out);
 }
 
  dbg << sg1.GetDAGLbl() << " vs " << sg2.GetDAGLbl() << endl
  << sg1.GetNodeLbl(u) << " vs " << sg2.GetNodeLbl(v) << endl
  << "role " << sg1.NodeRole(u) << " vs role " << sg2.NodeRole(v) << endl
  << "scale = " << scale << ", dr = " << dr << ", dv = " << dv << endl
  << "Branch similarity = " << branchSim << endl
  << "TSV similarity = " << tsvSim << endl
  << "Node similarity = " << nodeSim << endl
  << endl << flush;
}*/

/*bool SGDistMeasurer1::AreNodesRelated() const
{
const ShockGraph& sgFrom = dynamic_cast<const ShockGraph&>(from);

 NODE_ROLE ru = NodeRole(u), rv = sgFrom.NodeRole(v);
 
  if (ru == UNK_ROLE || rv == UNK_ROLE)
  return NodeType(u) == sgFrom.NodeType(v);		
  else if (ru == DUMMY || rv == DUMMY)
  return false;
  else
  return ru == rv;
}*/
////////////////////////////////////////////////////////////////////////////////	
	if (dNodeSim < 0 || dNodeSim > 1)
	{
		if (DAG::IsDbgMode())
		{
			std::cerr << "\nWrong similarity value (" << dNodeSim << ") when matching: \n"
				<< g1.GetDAGLbl() << ":" << g1.GetNodeLbl(u) << " against "
				<< g2.GetDAGLbl() << ":" << g2.GetNodeLbl(v) << std::endl;
		}
			
		dNodeSim = (dNodeSim < 0) ? 0:1;
	}
////////////////////////////////////////////////////////////////////////////////
/*!
	Initially, we don't know anything, so every edge correspondence
	is possible.
*/
void BGContextualNDM::InitializeEdgeAssignmentInfo()
{
	// Create a bipartite graph in which the nodes refer to the
	// outward edges in the pair of nodes being compared
	BipartiteGraph<leda::edge>& g = m_pMatchInfo->outwardEdgeMap;

	leda::edge e;

	forall_out_edges(e, v1)
		g.AddNode(e, 0);      // add the edge to the set 0

	forall_out_edges(e, v2)
		g.AddNode(e, 1);      // add the edge to the set 1

	g.CreateFullMap();        // maps every node is set 1 to every node in set 2
}

////////////////////////////////////////////////////////////////////////////////
if (m_bipGraph.number_of_nodes() >= 6)
		{
			m_bipGraph.SolveUsingBeliefProp();
			m_bipGraph.PrintNodeAssignments();
			m_bipGraph.ResetNodeAssignments();
		}

////////////////////////////////////////////////////////////////////////////////
	// Make sure that each nodes has a color different to that
	// of its neighbours
	ptrDag->SetNodeColorIndices();
	
	//! Gets the color associated with the node. Can be used to display its attributes.
	int GetColorIndex() const               { return nColorIdx; }

void SetNodeColorIndices();
int GetNodeColorIndex(leda::node v) const { return GetNode(v)->GetColorIndex(); }
	
/*!
	@brief Gives a color to each node different to that of its neighbours.

	colors rang from 0 to 4.

	The color is assigned to each node.
*/
void DAG::SetNodeColorIndices()
{
	leda::node_array<int> nodeColors(*this);
	leda::node v;

	FIVE_COLOR(*this, nodeColors);

	// Try to make the color of parent nodes sharing a child node
	// be different from one another
	forall_nodes(v, *this)
	{
		// If a node has multiple parents...
		if (indeg(v) > 1)
		{
			std::stack<leda::node> repCol;
			bool freeColors[5] = {true, true, true, true, true};
			leda::edge e;
			leda::node w;
			int i, parentCol;
			bool bFreeCol;

			// The color of the child cannot be used
			freeColors[nodeColors[v]] = false;

			// See which parens have repeated colores and add them to repCol
			forall_in_edges(e, v)
			{
				w = source(e);
				parentCol = nodeColors[w];

				if (freeColors[parentCol])
					freeColors[parentCol] = false;
				else
					repCol.push(w);
			}

			// Find a unique color for each parent with repeated color
			while (!repCol.empty())
			{
				w = repCol.top();
				repCol.pop();

				// Try each of the five colores
				for (i = 0; i < 5; i++)
				{
					// if no other parent has this color
					if (freeColors[i])
					{
						bFreeCol = true;

						// and the parents of w don't have it either
						forall_in_edges(e, w)
							if (i == nodeColors[source(e)])
								bFreeCol = false;

						// the color can be used
						if (bFreeCol)
						{
							nodeColors[w] = i;
							freeColors[i] = false;
							break;
						}
					}
				}
			}
		}
	}

	// Now, set the colors of each node
	forall_nodes(v, *this)
	{
		GetNode(v)->SetColorIndex(nodeColors[v]);
	}
}
////////////////////////////////////////////////////////////////////////////////
typedef leda::node_array<double> NodeMatchMap;
struct DAGMatcher
{
	double Match(const DAG& g1, const DAG& g2) const { return 0; }
	void GetNodeMap(NodeMatchMap& nodeMap) const { }
	double NodeAttributeDistance(const DAG& g1, leda::node u, const DAG& g2, leda::node v) const
	{ return 0; }

	double NodeSimilarity(const DAG& g1, leda::node u, const DAG& g2, leda::node v) const
	{ return 0; }
};
////////////////////////////////////////////////////////////////////////////////
/*else if (localSQ.inf(sqItem)->LastMatchSimilarity() <
					ptrNewSet->LastMatchSimilarity())
				{	
					localSQ.insert_at(sqItem, newTotalSimEstimate, ptrNewSet);
				}*/
////////////////////////////////////////////////////////////////////////////////
/*DBG_MSG4(ptrNewSet->LastMatchSimilarity(), 
				ptrNewSet->PartialSimilarity(),
				ptrNewSet->SimilarityEstimateToCompletion(),
				newTotalSimEstimate)*/
////////////////////////////////////////////////////////////////////////////////
	/*leda::pq_item it;

	while (!localSQ.empty())
	{
		it = aux.find_min();
	}*/

	/*SolutionQueue aux = sq;
	leda::pq_item it;

	while (!aux.empty())
	{
		std::cout << "\nSolution Queue: ";
		it = aux.find_min();
		aux.inf(it)->Print(std::cout) << std::endl;
		aux.del_item(it);
	}*/

	// We can clean the uncommited correspondences in the set 
	// now that we processed them all (this is simply to free up memory)
	//ptrSet->CleanCandidateCorrespondences();

	// Recurse as long as the queue is not empty
	//if (!sq.empty())
	//	FindBestNodeAssigment(sq);
////////////////////////////////////////////////////////////////////////////////
const NodeSet* pSrcSet[2] = {&src.A, &src.B};
NodeSet* pTgtSet[2] = {&A, &B};
////////////////////////////////////////////////////////////////////////////////
//! Gets a pointer to the current matched node in the query (i == 0) or the model (i == 1)
	const DAGNodePtr GetMatchedNodePtr(int i) const
	{
		ASSERT(i == 0 || i == 1);

		return (i == 0) ? Q.GetNode(q) : M.GetNode(m);
	}


	const DAGNodePtr GetQueryNode() const { return m_matchedNodeInfo.GetMatchedNodePtr(0); }

	const DAGNodePtr GetModelNode() const { return m_matchedNodeInfo.GetMatchedNodePtr(1); }

	void FillNodeMap(NodeMatchMap* pNodeMap) const
	{
		const SolutionSet* pSet = this;

		pNodeMap->init();

		while (!pSet->IsEmpty())
		{
			(*pNodeMap)[pSet->GetQueryNode()] = pSet->GetModelNode();

			pSet = pSet->m_ptrParent;
		}
	}
////////////////////////////////////////////////////////////////////////////////
/*int UnmatchedNodeCount() const
	{
		return 0;
	}*/
////////////////////////////////////////////////////////////////////////////////
	const leda::edge m_mappingEdge;   //<! last correspondence added to the set
////////////////////////////////////////////////////////////////////////////////
//! True if node 'u' is a parent or child of node 'v'
	bool IsImmediateRelative(leda::node u, leda::node v) const;
////////////////////////////////////////////////////////////////////////////////
const DAG* GetGraph(int i) const
	{
		ASSERT(i == 0 || i == 1);

		return (i == 0) ? pQG : pMG;
	}
////////////////////////////////////////////////////////////////////////////////
//! Retrieves the current matched node index by: query = 0 and model = 1
	leda::node operator[](int i) const
	{
		return GetMatchedNode(i);
	}
////////////////////////////////////////////////////////////////////////////////
static double Similarity(const DAG& image, const DAG& model, 
		DAGNodeMap& nodeMap, bool bRecomputeTSVs = false);
		
static double Distance(const DAG& image, const DAG& model, 
		DAGNodeMap& nodeMap, bool bRecomputeTSVs = false);
		
/*!
	\brief Returns the match distance between the two dags. 
	
	This function is simply the inverse of the Similarity function

	\see Similarity
*/
/*static*/
double DAG::Distance(const DAG& image, const DAG& model, 
	DAGNodeMap& nodeMap, bool bRecomputeTSVs)
{
	return 1.0 / DAG::Similarity(image, model, nodeMap, bRecomputeTSVs);
}
////////////////////////////////////////////////////////////////////////////////
enum METHOD {MWMC, MW};

class SimilarityGraph : public LEDA_GRAPH<leda::node, double>
{
	NodeMap g1Map, g2Map;
	EdgeNodeMap g1MatchedNodeMap, g2MatchedNodeMap;
	const DAG* pG1, *pG2;

public:
	SimilarityGraph(const DAG& g1, const DAG& g2)
	{
		pG1 = &g1;
		pG2 = &g2;
	}

	leda::node MapNode(NodeMap& map, leda::node v)
	{
		if (!map.defined(v))
			return map[v] = new_node(v);
		else
			return map[v];
	}

	bool IsG1NodeMapped(leda::node v) const
	{
		return g1Map.defined(v);
	}

	bool IsG2NodeMapped(leda::node v) const
	{
		return g2Map.defined(v);
	}

	void Add(leda::node g1Node, leda::node g2Node, double dSimilarity, 
		leda::node g1MatchedNode, leda::node g2MatchedNode);

	void Add(leda::node g1Node, leda::node g2Node, double dSimilarity);

	void MergeG2Nodes(leda::node remNode, leda::node delNode);

	double ComputeBestAssignment(METHOD nMethod, int* pnMatched, NodeMap* pNodeMap = NULL);
};

////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////
// SimilarityGraph functions

void SimilarityGraph::Add(leda::node g1Node, leda::node g2Node, double dSimilarity)
{
	new_edge(MapNode(g1Map, g1Node), MapNode(g2Map, g2Node), dSimilarity);
}

/*void SimilarityGraph::Add(leda::node g1Node, leda::node g2Node, double dSimilarity,
						  leda::node g1MatchedNode, leda::node g2MatchedNode)
{
	leda::node u = MapNode(g1Map, g1Node);
	leda::node v = MapNode(g2Map, g2Node);

	leda::edge e = new_edge(u, v, dSimilarity);

	g1MatchedNodeMap[e] = g1MatchedNode;
	g2MatchedNodeMap[e] = g2MatchedNode;
}*/

/*
	Remaining node, deleting node
*/
void SimilarityGraph::MergeG2Nodes(leda::node remNode, leda::node delNode)
{
	leda::node r, d;
	leda::edge e;

	r = g2Map[remNode];
	d = g2Map[delNode];

	forall_in_edges(e, d)
		move_edge(e, source(e), r);

	g2Map.undefine(delNode);
	del_node(d);
}

double SimilarityGraph::ComputeBestAssignment(METHOD nMethod, int* pnMatched, 
											  NodeMap* pNodeMap /*= NULL*/)
{
	leda::edge_array<double> edgeCosts(*this, 0.0);
	leda::edge e;

	forall_edges(e, *this)
	{
		edgeCosts[e] = inf(e);
		operator[](e) = 1.0;
	}

	EdgeList l;

	if (nMethod == MWMC)
	{
		MWA_SCALE_WEIGHTS(*this, edgeCosts);
		
		NodeList setA, setB;
		bool bBipartite = Is_Bipartite(*this, setA, setB);

		ASSERT(bBipartite);
		l = MWMCB_MATCHING(*this, setA, setB, edgeCosts);
	}
	else
	{
#ifdef USE_TEMPLATE_BASED_MWBM_FUNCTION
		scale_weights(*this, edgeCosts, 3.0);
		l = MAX_WEIGHT_BIPARTITE_MATCHING_T(*this, edgeCosts);
#else
		MWBM_SCALE_WEIGHTS(*this, edgeCosts);
		l = MAX_WEIGHT_BIPARTITE_MATCHING(*this, edgeCosts);
#endif //USE_TEMPLATE_BASED_MWBM_FUNCTION
	}

	leda::list_item i;
	leda::node u, v;
	double s = 0;

	forall_items(i, l) 
	{
		e = l[i];
		s += inf(e);

		if (pNodeMap)
		{
			if (g1MatchedNodeMap.defined(e))
			{
				u = g1MatchedNodeMap[e];
				v = g2MatchedNodeMap[e];
			}
			else
			{
				u = inf(source(e));
				v = inf(target(e));
			}

			(*pNodeMap)[u] = v;
		}
	}

	if (pnMatched)
		*pnMatched = l.size();

	return s;
}

////////////////////////////////////////////////////////////////////////////////
	/*!
		@brief Commits a node correspondece by adding it to the solution set
		and creating a new set that doesn't include the correspondece in
		the bipartita graph (ie, the set of candidate node mappings).

		Note: the destruction of the new set is handled by the SharedPtr object.
	*/
	SolutionSetPtr CommitNodeCorrespondence(leda::node e)
	{
		return new SolutionSet(this, e);
	}
////////////////////////////////////////////////////////////////////////////////
class EdgeWeight
{
	double weight;
public:
	EdgeWeight() {}

	EdgeWeight(const EdgeWeight& rhs) : weight(rhs.weight)
	{
	}

	EdgeWeight& operator+(const EdgeWeight& rhs) const
	{
		EdgeWeight ew(*this);

		ew.weight += rhs.weight;

		return ew;
	}

	EdgeWeight& operator-(const EdgeWeight& rhs) const
	{
		EdgeWeight ew(rhs);

		ew.weight += weight;

		return ew;
	}
};

////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.VC80.DebugCRT' version='8.0.50727.762' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")
////////////////////////////////////////////////////////////////////////////////
/*leda_point start(s1.x - GetImageInfo1()->delta_x,
					 (GetImageInfo1()->reflex_y - s1.y) - GetImageInfo1()->delta_y);

			leda_point end(s2.x - GetImageInfo2()->delta_x,
				       (GetImageInfo2()->reflex_y - s2.y) - GetImageInfo2()->delta_y);*/
////////////////////////////////////////////////////////////////////////////////
/*double x_pts[2][6] = {
		{159.556, 150.778, 155.889, 112.556, 111, 115},
		{195.556, 201, 192.889, 246.556, 247.222, 246.111}
	};


	double y_pts[2][6] = {
		{121.333, 118, 129.889, 161, 159, 162},
		{132.333, 129, 138.222, 198, 197.889, 198.556}
	};*/

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < numPts; j++)
		{
			//pts[i][j].x = x_pts[i][j];
			//pts[i][j].y = y_pts[i][j];

			m_pBGElementsToWarp

			//DBG_CODE_LINE(if (i == 0) P.Column(j + 1) << x_pts[i][j] << y_pts[i][j] << 1)

			//if (i == 0) 
			//	P.Row(j + 1) << x_pts[i][j] << y_pts[i][j] << 1;
		}
	}
/////////////////////////////////////////////////////////////////////////////////
	// If debugging, test the result of the homography
#ifdef _DEBUG
	NEWMAT::Matrix test = H * P.t();

	DBG_PRINT1(test)

	for (int i = 1; i <= numPts; i++)
	{
		test(1, i) /= test(3, i);
		test(2, i) /= test(3, i);
	}

	DBG_PRINT1(test)
#endif
/////////////////////////////////////////////////////////////////////////////////
	/*std::cout << "\n" << A << std::endl;
	std::cout << "\n" << U << std::endl;
	std::cout << "\n" << D << std::endl;
	std::cout << "\n" << V << std::endl;
	std::cout << "\n" << V.Column(9) << std::endl;
	
	for (int i = 0; i < 2; i++)
	{
		std::cout << "\npts" << i << " = [";

		for (int j = 0; j < numPts; j++)
		{
			std::cout << pts[i][j].x;

			if (j < numPts - 1)
				std::cout << ", ";
		}

		std::cout << ";\n";
		
		for (int j = 0; j < numPts; j++)
		{
			std::cout << pts[i][j].y;

			if (j < numPts - 1)
				std::cout << ", ";
		}

		std::cout << "];" << std::endl;
	}
	*/
/////////////////////////////////////////////////////////////////////////////////
//! Choose either a skeletal point (0) or one of the boundary points (1 or 2)
	POINT& operator[](int i)
	{
		if (i == 0) return pt;
		else if (i == 1) return bndryInfo.first.pt;
		else if (i == 2) return bndryInfo.second.pt;

		ASSERT(false);

		return pt;
	}
/////////////////////////////////////////////////////////////////////////////////
//! Gets point coordinates using an index (x == 0 and y == 1)
	const double& operator[](int i) const 
	{
		ASSERT(i == 0 || i == 1);

		return (i == 0) ? x : y;
	}

	//! Gets point coordinates using an index (x == 0 and y == 1)
	double& operator[](int i)
	{
		ASSERT(i == 0 || i == 1);

		return (i == 0) ? x : y;
	}
/////////////////////////////////////////////////////////////////////////////////
void MatchDAG(const DAG* pImgDag, DAGDatabase& dagDB, ShapeMatchingParams& info, 
			  streamoff nModelDagOffset, STATINFO& matSt)
{
	double dSim;
	DAGNodeMap nodeMap;
	DAGPtr ptrDag;

	matSt.matchList.resize(1);

	// Match model DAG
	ptrDag = dagDB.ReadDAG(nModelDagOffset, pImgDag->ClassName());

	if (ptrDag.IsNull())
	{
		cerr << "Can't read DAG with offset " << nModelDagOffset << endl << flush;
		return;
	}

	dSim = pImgDag->Similarity(*ptrDag, nodeMap);

	matSt.matchList[0].Set(ptrDag, dSim);
}

/////////////////////////////////////////////////////////////////////////////////

DWORD WINAPI MyThread( LPVOID lpParam )
{
	//int num = *((int*)lpParam);
	//std::cout << "Hello" << std::endl;

	return 0;
}

DWORD dwThreadId;
HANDLE hThread; 

int* pData = new int;
*pData = 10;

hThread = CreateThread ( 
    NULL,              // default security attributes
    0,                 // use default stack size  
    MyThread,          // thread function 
    pData,             // argument to thread function 
    0,                 // use default creation flags 
    &dwThreadId);      // returns the thread identifier 

/////////////////////////////////////////////////////////////////////////////////
$(OutDir)\$(ProjectName).exe
/////////////////////////////////////////////////////////////////////////////////
char* pLeak = new char[5];

	pLeak[0] = 'x';
	pLeak[1] = 'x';
	pLeak[2] = 'x';
	pLeak[3] = 'x';
	pLeak[4] = 'x';
/////////////////////////////////////////////////////////////////////////////////
/*!
	@brief Replaces the endpoints equal to 'oldBndryPt' of each spokes incident on 
	the given junction with the new value 'newBndryPt'.

	Note that oldBndryPt cannot be a reference, because it is being changed!!!!!
*/
void BoundaryPointFinder::ReplaceBoundaryPoint(SkelJoint* pJoint, 
		                             sg::BoundaryPoint oldBndryPt /*must be a copy!*/,
						             const sg::BoundaryPoint& newBndryPt)
{
	SkelBranch* pBranch;
	SkelPtIndex idx;

	forall_branches(pBranch, pJoint->getEdges())
	{
		sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();

		idx = GetEndpointIndex(pBranch, pJoint);
		ASSERT(idx == 0 || idx == pBranch->size() - 1);

		for (char side = '1'; side <= '2'; side++)
		{
			sg::BoundaryPoint& bp = bil[idx][side];

			if (bp.pt == oldBndryPt.pt)
			{
				// See if branch hasn't been processed yet or is too short
				if (bp.cumBndryDist < 0 || pBranch->size() < 2) 
				{
					bp = newBndryPt; // easy case
				}
				else
				{
					unsigned int negPtIdx = (idx == 0) ? 1 : pBranch->size() - 2;
					sg::BoundaryPoint& neigBp = bil[negPtIdx][side];
					double d = bp.pt.dist(neigBp.pt);

					if (bp.cumBndryDist == 0) // need to update all cumBndryDist values
					{
						double diff = neigBp.cumBndryDist - d;

						bp = newBndryPt;
						bp.cumBndryDist = 0;

						if (idx == 0)
						{
							for (unsigned int i = 1; i < bil.size(); i++)
								bil[i][side].cumBndryDist -= diff;
						}
						else
						{
							for (unsigned int i = bil.size() - 2; i != 0; i--)
								bil[i][side].cumBndryDist -= diff;
						}
					}
					else // need to update only last cumBndryDist values
					{
						bp = newBndryPt;
						bp.cumBndryDist = neigBp.cumBndryDist + d;
					}
				}
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////
	DBG_MSG4(bil.front().first.cumBndryDist, bil.back().first.cumBndryDist,
		bil.front().second.cumBndryDist, bil.back().second.cumBndryDist)
		
	#ifdef _DEBUG
	DBG_MSG2(fpl.front().p, fpl.back().p)
	DBG_MSG5(bil.size(), bil.front().first.cumBndryDist, bil.back().first.cumBndryDist,
		bil.front().second.cumBndryDist, bil.back().second.cumBndryDist)

	/*for (unsigned int i = 1; i < bil.size(); i++)
	{
		ASSERT(bil[i].first.cumBndryDist <= bil[i - 1].first.cumBndryDist);
		ASSERT(bil[i].second.cumBndryDist <= bil[i - 1].second.cumBndryDist);
	}*/
#endif
/////////////////////////////////////////////////////////////////////////////////
WARNING(bp.cumBndryDist < prevCBD[j], "Invalid cumulative distance");

				if (bp.cumBndryDist >= prevCBD[j])
					cbd[j] += bp.cumBndryDist - prevCBD[j];
				else
					cbd[j] += bp.pt.dist(bp0.pt);
/////////////////////////////////////////////////////////////////////////////////
	TBBInterval tbbi(m_pSkeletalGraph, nonLig.front().m_pBranch, nonLig.back().m_pBranch);

	if (!tbbi.IsValid())
	{
		DBG_MSG1("Invalid merge!!!!!!!!!!!!!!!!")
	}
/////////////////////////////////////////////////////////////////////////////////
//! Find the index of the boundary point associated with the given indices
	int GetBoundaryIndex(char side, int subindex, int index, sg::Point* pSkelPt = NULL)
	{
		if (index >= 0) // we already have it
			return index;
		else (pSkelPt == NULL) // it's a gap point, find closest boundary point to it
			return GetClosestBoundaryIndex(m_bsl[side][subindex][-index - 1]);
		else // it's a gap pt, find closet boundary point to given skeletal point
			return GetClosestBoundaryIndex(*pSkelPt);
	}
	
	int GetBoundaryIndex(const sg::BoundaryInfo& bi, char side, sg::Point* pSkelPt = NULL)
	{
		return GetBoundaryIndex(side, bi[side].subindex, bi[side].index, pSkelPt);
	}
	
		//! Forms valid boundary intervals for all the points on each branch side
	void SetBoundaryIntervals()
	{
		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

		const int first1 = GetBoundaryIndex(bil.front(), '1');
		const int last1  = GetBoundaryIndex(bil.back(), '1');
		const int first2 = GetBoundaryIndex(bil.front(), '2');
		const int last2  = GetBoundaryIndex(bil.back(), '2');

		SetBoundaryIntervals(first1, last1, first2, last2, true);
	}

	//! Forms valid boundary intervals for all the points on each branch side
	void SetBoundaryIntervalsSafe()
	{
		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
		const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();

		const int first1 = GetBoundaryIndex(bil.front(), '1', &fpl.front().p);
		const int last1  = GetBoundaryIndex(bil.back(),  '1', &fpl.back().p);
		const int first2 = GetBoundaryIndex(bil.front(), '2', &fpl.front().p);
		const int last2  = GetBoundaryIndex(bil.back(),  '2', &fpl.back().p);

		SetBoundaryIntervals(first1, last1, first2, last2, false);
	}


	//! Forms valid boundary intervals for all the points on each branch side
	void SetBoundaryIntervals(const int first1, const int last1,
		                      const int first2, const int last2,
							  bool bFirstCall = true)
	{
/////////////////////////////////////////////////////////////////////////////////
	void SetBoundaryIntervals()
	{
		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
		const int first1 = GetBoundaryIndex(bil.front(), '1');
		const int last1  = GetBoundaryIndex(bil.back(), '1');
		const int first2 = GetBoundaryIndex(bil.front(), '2');
		const int last2  = GetBoundaryIndex(bil.back(), '2');
		const int numPts = m_bndryPts.Size();

		// Set the interval associated with the first side
		m_bndryIntervalSide1.Set(numPts, first1, last1);
		
		if (m_bndryIntervalSide1.Inside(first2) || m_bndryIntervalSide1.Inside(last2))
		{
			m_bndryIntervalSide1.Swap();
			m_moveClockWise[0] = false;

			if (m_bndryIntervalSide1.Inside(first2) || m_bndryIntervalSide1.Inside(last2))
			{
				WARNING(true, "we still have a problem");
			}
		}
		else
		{
			m_moveClockWise[0] = true;
		}

		ASSERT(!m_bndryIntervalSide1.Inside(first2) && !m_bndryIntervalSide1.Inside(last2));

		// Set the interval associated with the second side
		m_bndryIntervalSide2.Set(numPts, first2, last2);

		if (m_bndryIntervalSide2.Inside(first1) || m_bndryIntervalSide2.Inside(last1))
		{
			m_bndryIntervalSide2.Swap();
			m_moveClockWise[1] = false;
		}
		else
		{
			m_moveClockWise[1] = true;
		}

		ASSERT(!m_bndryIntervalSide2.Inside(first1) && !m_bndryIntervalSide2.Inside(last1));
	}
/////////////////////////////////////////////////////////////////////////////////
bool GSG::IsBranchMergeValid(SkelJoint* pJoint, const LigatureSegmentList& nonLig, 
							   const std::list<LigatureSegment>& ligSegs)
{
	// Find the gap ligature. Make sure to use the original branches instead of the
	// fixed branches. Otherwise, the gap lig can't be subtracted from 'm_segments'
	ls.FindGapLigature(GetOriginalBranch(nonLigBranches[0], pJoint), pJoint, ligSegs);
	GetNode(u).SubtractGapLigature(ls);

	ls.FindGapLigature(GetOriginalBranch(nonLigBranches[1], pJoint), pJoint, ligSegs);
	GetNode(v).SubtractGapLigature(ls);

	void GSG::FillMedialAxisGap(const BranchSegment& bs0, bool bIsFirstSeg0,
						const BranchSegment& bs1, bool bIsLastSeg1,
						const AttachEdges& attchs, CubicBezier& cb,
						SkelPtIndex& ptIdx0, SkelPtIndex& ptIdx1)
}
/////////////////////////////////////////////////////////////////////////////////
		idx0 = GetEndpointIndex(pBranch, pJoint);
		idx1 = GetOtherEndpointIndex(pBranch, pJoint);

		const sg::BoundaryPoint& bp0side1 = bil[idx0].first;
		const sg::BoundaryPoint& bp0side2 = bil[idx0].second;

		const sg::BoundaryPoint& bp1side1 = bil[idx1].first;
		const sg::BoundaryPoint& bp1side2 = bil[idx1].second;

		if (bp0side1.pt == oldBndryPt.pt && 
			!TestBoundaryInterval(newBndryPt.index, bp1side1.index, 
			                      bp0side2.index, bp1side2.index))
		{
			return false;
		}
		else if (bp0side2.pt == oldBndryPt.pt &&
			!TestBoundaryInterval(newBndryPt.index, bp1side2.index, 
			                      bp0side1.index, bp1side1.index))
		{
			return false;
		}
/////////////////////////////////////////////////////////////////////////////////
	SkelPtCoord FirstBonePointCoord() const
	{
		return GetBonePart().FirstPtCoord();
	}

	SkelPtCoord LastBonePointCoord() const
	{
		return GetBonePart().LastPtCoord();
	}
/////////////////////////////////////////////////////////////////////////////////
		/*SkelBranch* pSrcBranch = FindSourceBranch(pJoint, nonLigBranches);
		
		// Add edges between all insident branches and the junction node
		SkelBranch* pBranch;

		if (pSrcBranch == nil)
		{
			pSrcBranch = NewSkelBranchFromJoint(pJoint);
			pSrcBranch->pEdgeData = NewBranchNode(pSrcBranch);

			NewJunctionEdge(GetNode(pSrcBranch), j, pJoint); // flows towards the joint

			forall_branches(pBranch, nonLigBranches)
			{
				NewJunctionEdge(j, GetNode(pBranch), pJoint); // flows away from joint
			}
		}
		else
		{
			forall_branches(pBranch, nonLigBranches)
			{
				if (pBranch == pSrcBranch)
					NewJunctionEdge(GetNode(pBranch), j, pJoint); // flows towards the joint
				else
					NewJunctionEdge(j, GetNode(pBranch), pJoint); // flows away from joint
			}
		}

		ASSERT(indeg(j) == 1);*/
/////////////////////////////////////////////////////////////////////////////////
	/*forall_in_edges(e, v)
	{
		GSGEdge& edge = GetEdge(e);
		GSGNode& src = GetNode(source(e));
		GSGNode& tgt = GetNode(target(e));

		DBG_PRINT2(src.m_type, tgt.m_type)
	}*/
/////////////////////////////////////////////////////////////////////////////////
// Check if we have a spurious branch. See notes above.
	/*if (m_first == 0 && m_last == pBranch->size() - 1 && 
		(pBranch->n1->degree() == 1 || pBranch->n2->degree() == 1) &&
		(m_cumBAR1.straight < 1 && m_cumBAR2.straight < 1) &&
		((m_cumBAR1.straight + m_cumBAR2.straight) / 2 <= MAX_CUM_BAR) &&
		wi.ComputeDiskOverlap(m_first, m_last) >= MIN_ENDPT_OVERLAP)
	{
		m_dEndptRadius = 0; // so that it ranks first in operator<()
		m_bSpuriousBranch = true;
	}
	else
	{
		m_bSpuriousBranch = false;
	}*/
/////////////////////////////////////////////////////////////////////////////////
	/*SkelPtIndex idx = GetEndpointIndex(pBranch, pJoint);
	
	sg::Point v1 = pBranch->getBoundaryInfo(idx).first.pt - pJoint->fp.p;
	sg::Point v2 = pBranch->getBoundaryInfo(idx).second.pt - pJoint->fp.p;
	
	double alpha = fabs(VectorAngle(v1, v2, v1.norm(), v2.norm()));
	double arcLen = alpha * pJoint->fp.radius();

	BoundaryIntervalWithGaps bi(pBranch, s_pBndryPtFinder->GetOriginalPoints());

	bi.SetLimits(0, pBranch->size() - 1, '1');*/
/////////////////////////////////////////////////////////////////////////////////
			// Test what happens if we swap the index of pBiN
			///bndryInt.Set(m_origBndryPts.Size(), bi0.first.index, pBiN->second.index /*swapped*/);

			//if (bndryInt.Inside(bi0.second.index) || bndryInt.Inside(pBiN->first.index /*swapped*/))
			//	bndryInt.Swap();

			
			/*{
				// Swaping does not fix things. Then, make them be the same point
				pBiN->second = pBiN->first;
			}
			else
			{
				// Swaping the boundary info of pBiN fixes things
				std::swap(pBiN->first, pBiN->second);
			}*/
			
/////////////////////////////////////////////////////////////////////////////////
	
	//void UpdateTrailingLigatures(SkelBranch* pNewFixedBranch);

	//! Copies 'bs' and subtracts the pending trailing lig segments from it
	/*BranchSegment ApplyTrailingLigatures(BranchSegment bs) const
	{
		LigatureSegmentList::const_iterator it;

		for (it = m_ligatures.begin(); it != m_ligatures.end(); it++)
			bs.SubtractLigatureInterval(*it);

		return bs;
	}*/

	//! Removes the trailing ligature of an "attaching" branch
	/*void SubtractAttachmentLigature(const LigatureSegment& ls)
	{
		ASSERT(!HasBrokenBranch()); // should be repaired already

		// Store the ligature segment so that it can be removed later 
		// and multiple times, if needed.
		m_ligatures.push_back(ls);
	}*/
	
	/*!
	@brief Stores the new branch as the current fixed branch. If there
	is a previously fixed branch, the ligature information in it is
	transferred to the new branch. 
	
	In general, a branch does not need to be fixed more than once and so
	there is no need to transfer any information.
*/
/*void GSGNode::UpdateTrailingLigatures(SkelBranch* pNewBranch)
{
	LigatureSegmentList::iterator it;
	SkelPtCoord newFirstCoord, newLastCoord, oldFirstCoord, oldLastCoord;

	// Make sure that n1 is the first flux point and n2 is the last
	ASSERT(GetFirstJoint(pNewBranch) == pNewBranch->n1);
	ASSERT(GetLastJoint(pNewBranch) == pNewBranch->n2);

	// Get the flux point coordinates of the new branch endpoints
	newFirstCoord = pNewBranch->getFirstXYPoint();
	newLastCoord  = pNewBranch->getLastXYPoint();

	// Update each ligature interval with the new branch pointer and the
	// corresponding redefinition of its limits
	for (it = m_ligatures.begin(); it != m_ligatures.end(); it++)
	{
		ASSERT(it->Size() >= 1 && it->Size() <= pNewBranch->size());

		// The lig segment maybe inverted, so first and last coord are arbitrary
		oldFirstCoord = it->FirstPtCoord();
		oldLastCoord  = it->LastPtCoord();

		if (newFirstCoord == oldFirstCoord || newFirstCoord == oldLastCoord)
		{
			it->SetBranchSegment(pNewBranch, 0, it->Size() - 1);
		}
		else if (newLastCoord == oldFirstCoord || newLastCoord == oldLastCoord)
		{
			SkelPtIndex first = pNewBranch->size() - it->Size();

			it->SetBranchSegment(pNewBranch, first, it->Size() - 1);
		}
		else
		{
			WARNING(true, "Traling ligature is not related to new branch endpoints");
			it->m_pBranch = NULL;
			continue;
		}
	}
}*/
/////////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
	const sg::FluxPointList& fpl = nodeBS.m_pBranch->getFluxPoints();

	for (unsigned int j = 1; j < fpl.size(); j++)
	{
		ASSERT(fpl[j - 1].p != fpl[j].p);
	}
#endif
/////////////////////////////////////////////////////////////////////////////////
						// If fpl isn't empty, its last point should be the same than the gap's first
			ASSERT(fpl.empty() || fpl.back().p.dist(gapFluxPts[i][0].p) < 1.5);


			// Ignore gap's first point unless it's fpl's first
			//k = (fpl.empty()) ? 0 : 1;
			if (fpl.empty() || fpl.back().p.dist(gapFluxPts[i][0].p) >= 0.5)
				k = 0;
			else
				k = 1;
/////////////////////////////////////////////////////////////////////////////////		
		// Ignore segment's first point unless it's fpl's first
		j = (fpl.empty()) ? it0->First() : it0->First() + 1;

/////////////////////////////////////////////////////////////////////////////////

bool bCheckInterval = (biN.first.index >= 0 && biN.second.index >= 0);

// If possible, check that idx forms a valid boundary interval
					if (bCheckInterval && !IsValidInterval('1', bi0, biN))
						continue;
						
// If possible, check that idx forms a valid boundary interval
if (bCheckInterval && !IsValidInterval('2', bndryPts.GetNNIndex(i), biN))
	continue;
/////////////////////////////////////////////////////////////////////////////////
//return ((m_corner1.cosAngle + m_corner2.cosAngle) < 
		//	(rhs.m_corner1.cosAngle + rhs.m_corner2.cosAngle));
/////////////////////////////////////////////////////////////////////////////////
  double avgOuterRadius = AVG(outerRadius0, outerRadius1);
  else if (avgInnerRadius > avgOuterRadius)
  if (avgInnerRadius < avgOuterRadius)

/////////////////////////////////////////////////////////////////////////////////
if (FindNextFile(hFile, &m_pFindData) == 0) 
		return false;

	sz = m_pFindData->cFileName;
/////////////////////////////////////////////////////////////////////////////////
		DirWalker::ChangeFileExt(m_target, NULL, szFileNameNoExt);
		strcat(szFileNameNoExt, "_stats");
		
		nFileIdx = DirWalker::CreateFileName(".", szFileNameNoExt, "m", szFileName);
		
DirWalker::ChangeFileExt(dagDB.GetFileName(), NULL, szFileNameNoExt);
		strcat(szFileNameNoExt, "_results");
			
		DirWalker::CreateFileName(".", szFileNameNoExt, "log", szFileName);
/////////////////////////////////////////////////////////////////////////////////
String str1("Hello"), str2("Hello");

	if (!(str1 < str2) && !(str2 < str1))
		cerr << "Strings are equal" << endl;
	else
		cerr << "Strings are different" << endl;
/////////////////////////////////////////////////////////////////////////////////
bool compare(const String& lhs, const String& rhs)
	{
		return operator==()
	}
/////////////////////////////////////////////////////////////////////////////////	
alpha, alpha2, cosAlpha, 

cosAlpha = p0.dot(p1) / (p0Norm * p1Norm);
		
		if (cosAlpha < -1) cosAlpha = -1;
		else if (cosAlpha > 1) cosAlpha = 1;

		alpha2 = acos(cosAlpha);

		alpha = VectorAngle(p0, p1, p0Norm, p1Norm);
		DBG_PRINT2(alpha, alpha2)
/////////////////////////////////////////////////////////////////////////////////
	bElbowCandidate = false;

		if (!it0->m_corner1.valid && it0->m_cumBAR1.normal > 1)
		{
			bElbowCandidate = true;
			cornerPt = it0->m_corner2.pt;
		}
		else if (!it0->m_corner2.valid && it0->m_cumBAR2.normal > 1)
		{
			bElbowCandidate = true;
			cornerPt = it0->m_corner1.pt;
		}

		if (bElbowCandidate)
		{
			it0->FindMinMaxDistances(cornerPt, &minDist, &maxDist);

			DBG_MSG2("Elbow candidate found", cornerPt)
			DBG_MSG3("Min-max distances found", minDist, maxDist)
		}
/////////////////////////////////////////////////////////////////////////////////
		if (m_nShowPtCoords)
		{
			std::stringstream ss;
			ss << "(" << 
		}
/////////////////////////////////////////////////////////////////////////////////
	if (m_strInputedKeys.eof())
		cout << "Invalid input coordinates." << endl;
	else
		m_strInputedKeys >> pt.x;

	if (m_strInputedKeys.eof())
		cout << "Invalid input coordinates." << endl;
	else
		m_strInputedKeys >> pt.y;

	m_inputCoords.AddTail(ReMapPt(pt, GetSGInfo1()));
/////////////////////////////////////////////////////////////////////////////////
//std::string m_strInputedKeys;
//m_strInputedKeys.append(&keyVal, 1);
/////////////////////////////////////////////////////////////////////////////////

	/*std::string::size_type pos;

	pos = m_strInputedKeys.find(",");

	if (pos != std::string::npos)
	{
		cout << "(" << m_strInputedKeys.substr(0, pos) << ", " 
			<< m_strInputedKeys.substr(pos + 1) << ")" << endl;
	}
	else
	{
		cout << "Invalid coordinates" << endl;
	}*/
	
		while (!m_strInputedKeys.eof())
	{
		m_strInputedKeys >> n;
		cout << n << endl;
	}
/////////////////////////////////////////////////////////////////////////////////
/*m_pWnd->draw_pixel(pt, skelPtCol);

					m_pWnd->draw_pixel(ReMapPt(p.x + 1, p.y, si), skelPtCol);
					m_pWnd->draw_pixel(ReMapPt(p.x, p.y + 1, si), skelPtCol);
					m_pWnd->draw_pixel(ReMapPt(p.x - 1, p.y, si), skelPtCol);
					m_pWnd->draw_pixel(ReMapPt(p.x, p.y - 1, si), skelPtCol);*/

/////////////////////////////////////////////////////////////////////////////////					
					
forall_const_branches(pBranch, sk->getEdges())
		{
			const sg::FluxPointList& fpl = pBranch->getFluxPoints();
			const sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();
			bool bDrawSpokes = (m_nShowRays && fpl.size() == bil.size());

			for (i = 0; i < fpl.size(); i++)
			{
				pt = ReMapPt(fpl[i].p, si);

				if (bDrawSpokes)
				{
					m_pWnd->draw_segment(pt, ReMapPt(bil[i].first.pt, si), leda::red);
					m_pWnd->draw_segment(pt, ReMapPt(bil[i].second.pt, si), leda::orange);
				}

				if (m_bShowSkeletalGraph)
					m_pWnd->draw_disc(pt, 0.4, skelPtCol);
			}
		}
					
/////////////////////////////////////////////////////////////////////////////////
					
	// Show rays from skleton points to bondary points
	if (m_nShowRays > 0 && sk != NULL)
	{
		const sg::DDSEdgeVect& edges = sk->getEdges();
		sg::DDSEdgeVect::const_iterator I;
		int i, nSize;
		leda::color col = leda::blue;

		for(I = edges.begin(); I != edges.end(); I++)
		{
			const sg::FluxPointList& fpl    = (*I)->getFluxPoints();
			const sg::BoundaryInfoList& bil = (*I)->getBoundaryInfoList();
			nSize = bil.size();

			for (i = 0; i < nSize; i++)
			{
				// If m_nShowRays == 2, show external rays only
				if (m_nShowRays == 2 && !(i == 0 || i == nSize - 1))
					continue;

				const sg::Point& fp = fpl[i].p;
				const sg::BoundaryPoint& bp1 = bil[i].first;
				const sg::BoundaryPoint& bp2 = bil[i].second;

				if (bp1.index != -1 || bp1.subindex != -1)
					m_pWnd->draw_segment(ReMapPt(fp, si), ReMapPt(bp1.pt, si), col);

				if (bp2.index != -1 || bp2.subindex != -1)
					m_pWnd->draw_segment(ReMapPt(fp, si), ReMapPt(bp2.pt, si), col);
			}
		}
	}
/////////////////////////////////////////////////////////////////////////////////	
	
static leda::color s_shockColors[];

//! Six colors are needed. Only the first 5 colors should be used. The sixth one is the default.
leda::color ShockGraphView::s_shockColors[] = 
{ 
	leda_black, leda_red, leda_yellow, leda_green, leda_brown, leda_grey3
};

/////////////////////////////////////////////////////////////////////////////////	
static leda::color s_diskColors[];

//! Six colors are needed. Only the first 5 colors should be used. The sixth one is the default.
//leda::color BoneGraphView::s_diskColors[] = 
//{
//	leda::color(164, 230, 198) /*pastel green*/, 
//	leda::color(178, 168, 255) /*pastel purple*/, 
//	leda::color(255, 113, 81)  /*pastel orange*/, 
//	leda::color(242, 129, 103) /*"skin" pink*/, 
//	leda::color(255, 213, 136) /*"sand" yellow*/,
//	leda::red                  /* used as warning only*/
//};

/////////////////////////////////////////////////////////////////////////////////	
		/*switch (i)
		{
			case 0: return leda::color(164, 230, 198);
			case 1: return leda::color(178, 168, 255);
			case 2: return leda::color(255, 113, 81);
			case 3: return leda::color(242, 129, 103);
			case 4: return leda::color(255, 213, 136);
		}

		ASSERT(false);

		return leda::red;*/
/////////////////////////////////////////////////////////////////////////////////
	//! Computes the squared Euclidean distance between the points
	int RoundedSqDist(const POINT& rhs) const
	{
		int this_x, this_y, rhs_x, rhs_y;

		GetRoundedCoords(&this_x, &this_y);
		rhs.GetRoundedCoords(&rhs_x, &rhs_y);

		int dx = this_x - rhs_x;
		int dy = this_y - rhs_y;
		return dx * dx + dy * dy;
	}
/////////////////////////////////////////////////////////////////////////////////
	DBG_STREAM_IF("Warning: points are far apart: " << 
		pNewBranch->getFirstXYPoint() << ", " << pNewBranch->n1->fp.p,
		pNewBranch->getFirstXYPoint().dist(pNewBranch->n1->fp.p) >= 1
	)

	DBG_STREAM_IF("Warning: points are far apart: " <<
		pNewBranch->getLastXYPoint() << ", " << pNewBranch->n2->fp.p,
		pNewBranch->getLastXYPoint().dist(pNewBranch->n2->fp.p) >= 1
	)
/////////////////////////////////////////////////////////////////////////////////
			// Save the boundary gaps
			BoundaryIntervalWithGaps biwg(node.GetBonePart().m_pBranch, 
				m_genSkelGraph.GetOriginalSkeletalGraph()->GetBndryPtFinder()->GetOriginalPoints());

			biwg.SetLimits(0, node.GetBonePart().m_pBranch->size() - 1, '1');

			BoundaryIntervalWithGaps::Index idx = biwg.First();

			pts.Clear();

			//DBG_PRINT3(biwg.Last().bndryPointIdx, biwg.Last().bndrySegmentIdx, biwg.Last().branchSide)
			//DBG_PRINT3(idx.bndryPointIdx, idx.bndrySegmentIdx, idx.branchSide)

			//DBG_MSG1("")
			sg::Point sgPt;
			POINT pt;

			while (idx != biwg.Last())
			{
				biwg.GetBoundaryPoint(idx, sgPt);

				pts.AddTail(pt = AssignPtCoord(pt, sgPt));

				//DBG_PRINT5(idx.bndryPointIdx, idx.bndrySegmentIdx, idx.branchSide, pt.x, pt.y)

				biwg.MovePrev(idx);
			} //while (idx != biwg.First());

			m_pBoneGraph->m_boundaryGaps.AddTail(pts);

			//DBG_MSG1("\n-------------\n")
/////////////////////////////////////////////////////////////////////////////////
		// Do the other side
			/*biwg.SetLimits(0, node.GetBonePart().m_pBranch->size() - 1, '2');
			idx = biwg.First();
			pts.Clear();

			while (idx != biwg.Last())
			{
				pts.AddTail(pt = AssignPtCoord(pt, biwg.Succ(idx)));
				DBG_PRINT5(idx.bndryPointIdx, idx.bndrySegmentIdx, idx.branchSide, pt.x, pt.y)
			}

			m_pBoneGraph->m_boundaryGaps.AddTail(pts);
			DBG_MSG1("\n*************\n")*/
/////////////////////////////////////////////////////////////////////////////////
DBG_PRINT4(x, y, si->delta_x, si->delta_y)
leda::point pt = pSGWnd->ReMapPt(leda::point(-x, y), si);
sprintf(szTxt, "%.1f %.1f", -pt.xcoord(), pt.ycoord());
leda::point(-pt.xcoord(), pt.ycoord())
/////////////////////////////////////////////////////////////////////////////////
if (ls.m_bDecreasing)
			os << ls.m_first << ", " << ls.m_last;
		else
			os << ls.m_last << ", " << ls.m_first;
/////////////////////////////////////////////////////////////////////////////////
	/*// Check for overlaps and possible valid merges
	iterator it0, it1 = begin();

	while (it1 != end())
	{
		it0 = it1++;

		if (it1 != end())
		{
			if ((it0->m_last >= it1->m_first) || 
				(it1->m_first - it0->m_last <= MIN_NON_LIG_SEGMENT_SIZE))
			{
				DBG_C_LOG("*** There is overlap: " << DBG_VAL(it0->m_first) << DBG_VAL(it0->m_last)
					<< DBG_VAL(it1->m_first) << DBG_VAL(it1->m_last))

				it1->m_first = it0->m_first;

				// For debugging purposes ONLY, add the merged corners too
				//it1->m_mergedCorners.AddTail(it0->m_corner1);
				//it1->m_mergedCorners.AddTail(it0->m_corner2);

				erase(it0);

				DBG_C_LOG("*** Merged segment is: " << DBG_VAL(it1->m_first) << DBG_VAL(it1->m_last))
			}
		}
	}*/
/////////////////////////////////////////////////////////////////////////////////
		/*// Also, it makes sense to remove heading ligature ending at a terminal point...
		if (front().m_first == bs.BranchFirst() && 
			GetFirstJoint(bs.m_pBranch)->degree() == 1)
		{
			pop_front();
			DBG_C_LOG("ignoring heading lig")
		}

		//...and trailing ligature ending at a terminal point
		if (!empty() && back().m_last == bs.BranchLast() && 
			GetLastJoint(bs.m_pBranch)->degree() == 1)
		{
			pop_back();
			DBG_C_LOG("ignoring trailing lig")
		}*/
/////////////////////////////////////////////////////////////////////////////////
	bool bBARCondition1 = (m_cumBAR1.normal <= MAX_CUM_BAR 
		|| m_cumBAR1.straight <= MAX_CUM_BAR);

	bool bBARCondition2 = (m_cumBAR2.normal <= MAX_CUM_BAR 
		|| m_cumBAR2.straight <= MAX_CUM_BAR);

	if (!m_bRegularizationRole)
	{
		// We are in a partitioning role...
		if (m_cumBAR1.normal <= MAX_CUM_BAR && 
	}
/////////////////////////////////////////////////////////////////////////////////
	bool TestBARCondition(const CumulativeBAR& bar) const
	{
		if (m_bRegularizationRole)
		{
			return (bar.normal <= MAX_CUM_BAR || 
				bar.straight <= MAX_CUM_BAR);
		}
		else // partitioning role
		{
			
		}
	}
/////////////////////////////////////////////////////////////////////////////////
//	DBG_PRINT4(idx.bndryPointIdx, idx.bndrySegmentIdx, exLimLeft.bndryPointIdx, exLimLeft.bndrySegmentIdx)
//		DBG_PRINT4(idx.bndryPointIdx, idx.bndrySegmentIdx, exLimRight.bndryPointIdx, exLimRight.bndrySegmentIdx)

//DBG_PRINT3(left.bndryPointIdx, left.bndrySegmentIdx, p1)
//DBG_C_LOG(DBG_VAL(left.bndryPointIdx) << DBG_VAL(left.bndrySegmentIdx) << DBG_VAL(p1) << DBG_VAL(prevP1))
//WARNING(p1 == prevP1, "Repeated boundary point on the left");
//prevP1 = p1;
		
/////////////////////////////////////////////////////////////////////////////////
//! Forms a valid boundary interval for all the points in the given branch and side
	/*void SetBoundaryInterval(char side)
	{
		const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

		const sg::BoundaryPoint& bp0 = bil.front()[side];
		const sg::BoundaryPoint& bp1 = bil.back()[side];

		const int first = GetBoundaryIndex(side, bp0.subindex, bp0.index);
		const int last = GetBoundaryIndex(side, bp1.subindex, bp1.index);

		// Now we can set the interval associated with the given side
		BoundaryInterval& bi = GetBndryInt(side);
		const int numPts = m_bndryPts.Size();

		bi.Set(numPts, first, last);

		// But, make sure it's specified correctly by finding a unique middle
		// point and checking that it's included within the interval
		int middleIdx = bp0.index;
		unsigned int i, idx;

		for (i = 1; middleIdx == bp0.index && i < bil.size(); i++)
			middleIdx = bil[i][side].index;

		// If we didn't find any (we reached the last point), it may be because all 
		// pts were gap pts. We can try with them to find a unique middle point
		if (middleIdx == bp1.index)
		{
			middleIdx = bp0.index;

			for (i = 1; middleIdx == bp0.index && i < bil.size(); i++)
			{
				idx = bil[i][side].index;

				if (idx < 0) // it's a gap point...
					middleIdx = GetBoundaryIndex(side, bil[i][side].subindex, idx);
			}
		}

		// If we don't have a valid middle point, choose the shortest interval.
		// Otherwise, choose the interval that includes the given middle point.
		if (((middleIdx == bp0.index || middleIdx == bp1.index) && bi.Size() > numPts / 2) ||
			!bi.Includes(middleIdx))
		{
			bi.Swap();
			m_moveClockWise[side - '1'] = false;
		}
		else
			m_moveClockWise[side - '1'] = true;
	}*/
/////////////////////////////////////////////////////////////////////////////////
//! Gets the CCW angle of the outward tangent at the given endpoint (using averages)
inline double GetBranchAngleAtEndpoint2(const SkelBranch* pBranch, SkelPtIndex idx)
{
	const sg::FluxPointList& fpl = pBranch->getFluxPoints();

	ASSERT(idx == 0 || idx == fpl.size() - 1);
	
	const int N = fpl.size() - 1;
	const int D = MIN(MAX_NUM_PTS_FOR_TANGENT, N);
	const int D_PLUS = MIN(MAX_NUM_PTS_FOR_TANGENT + 1, N);
	double angle = 0;

	ASSERT(D >= 1);

	if (idx == 0)
	{
		for (int d = D; d <= D_PLUS; d++)
			angle += atan2(fpl[d].p.y - fpl[0].p.y, fpl[d].p.x - fpl[0].p.x);
	}
	else
	{
		for (int d = D; d <= D_PLUS; d++)
			angle += atan2(fpl[N - d].p.y - fpl[N].p.y, fpl[N - d].p.x - fpl[N].p.x);
	}

	return angle / (D_PLUS - D + 1);
}
/////////////////////////////////////////////////////////////////////////////////
/*! 
	brief Returns true if the radius of fp0 is larger or equal to that of fp1.

	The distances to the NN boundary points are found and used as the points
	radii, rather than "trusting" the radius values associated with each flux point.
*/
bool BoundaryPointFinder::GetRobustFlowDirection(const sg::FluxPoint& fp0, const sg::FluxPoint& fp1)
{
	KDTree& bndryPts = m_smoothBndryPts;
	double epsilon = INIT_EPSILON;
	
	bndryPts.RangeSearch(fp0.p.x, fp0.p.y, fp0.radius(), &epsilon, EPSILON_INC, 2);

	double dist0a = bndryPts.GetNNDistance(0);
	double dist0b = bndryPts.GetNNDistance(1);
	double dist0 = MAX(dist0a, dist0b); // plays against fp0

	epsilon = INIT_EPSILON;
	bndryPts.RangeSearch(fp1.p.x, fp1.p.y, fp1.radius(), &epsilon, EPSILON_INC, 1);

	double dist1 = bndryPts.GetNNDistance(0); // there is a bias for decreasing radius

	return dist1 <= dist0;
}
/////////////////////////////////////////////////////////////////////////////////
		//angles[i++].Set(pBranch, idx, angle, tangent);
			
			/*angles[i].pBndryInfo = &bil[idx];
			angles[i].pOppositeBndryInfo = (idx == 0) ? &bil.back() : bil.front();

			GetEndpointForwardTangent(pBranch, idx, &angles[i].tangent);
			angles[i].tangent.normalize();

			angles[i++].angle = M_PI + GetBranchAngleAtEndpoint(pBranch, idx);*/
/////////////////////////////////////////////////////////////////////////////////
		//SkelBranch* m_pBranch;
		//SkelPtIndex m_index0, m_index1;
		//bool bFirstPt;
		
		/*void Set(SkelBranch* pBranch, SkelPtIndex idx, 
			const double& angle, const sg::Vector& tangent)
		{
			m_pBranch = pBranch;
			m_index0 = idx;
			m_index1 = (idx == 0) ? pBranch->size() - 1 : 0;
			m_dAngle = angle;
			m_tangent = tangent;
		}*/
		
		sg::BoundaryPoint& GetBndryPt(const double& objectAngle) const
		{
			if (objectAngle >= 0)
				return m_pBranch->getBoundaryInfoList()[m_index0].first;
			else
				return m_pBranch->getBoundaryInfoList()[m_index0].second;
		}
		
				/*sg::BoundaryPoint& GetBndryPt(bool bRotateCCW) const
		{
			return (bRotateCCW == bFirstPt) ? pBndryInfo->first : pBndryInfo->second;
		}*/
/////////////////////////////////////////////////////////////////////////////////
void ValidateEndpoints(const double& objectAngle) const
		{
			sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

			sg::BoundaryPoint& bp1 = (objectAngle >= 0) ? 
				bil[m_index1].first : bil[m_index1].second;

			if (bp1.index == -1)
				return;

			const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();
			sg::BoundaryPoint& bp0 = GetBndryPt(objectAngle);

			if (DoSpokesIntersect(fpl[m_index0].p, bp0.pt, fpl[m_index1].p, bp1.pt))
			{
				DBG_MSG1("Correcting spokes intersectiong:")
				DBG_STREAM("\n\tspoke from " << fpl[m_index0].p << " to " << bp0.pt)
				DBG_STREAM("\n\tspoke from " << fpl[m_index1].p << " to " << bp1.pt)

				if (fpl[m_index0].p.sqDist(bp1.pt) < fpl[m_index1].p.sqDist(bp0.pt))
					bp0 = bp1;
				else
					bp1 = bp0;
			}
		}
/////////////////////////////////////////////////////////////////////////////////
bool IsValidEndpoint(const sg::Point& pt0, const double& objectAngle) const
		{
			const sg::FluxPointList& fpl    = m_pBranch->getFluxPoints();
			const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

			const sg::BoundaryPoint& bp1 = (objectAngle >= 0) ? 
				bil[m_index1].first : bil[m_index1].second;

			if (bp1.index == -1)
				return true;

			if (DoSpokesIntersect(fpl[m_index0].p, pt0, fpl[m_index1].p, bp1.pt))
			{
				DBG_MSG5("Spokes intersect", fpl[m_index0].p, pt0, fpl[m_index1].p, bp1.pt)
			}

			return true;
		}
/////////////////////////////////////////////////////////////////////////////////
		char GetSideFromObjectAngle(const double& objectAngle)
		{
			return (objectAngle >= 0) ? '1' : '2';
		}
		
/////////////////////////////////////////////////////////////////////////////////
	/*int sz = m_origBndryPts.Size();
	BoundaryInterval side1(sz, bil[0].first.index, bil[N].first.index);
	BoundaryInterval side2(sz, bil[0].second.index, bil[N].second.index);

	// Swap the intervals' limits if they are set incorrectly
	if (side1.Includes(bil[0].second.index))
		side1.Swap();

	if (side2.Includes(bil[0].first.index))
		side2.Swap();*/
/////////////////////////////////////////////////////////////////////////////////
	// Correct inappropriate crossings of spokes
	forall_joints(pJoint, pDDSGraph->getNodes())
	{
		forall_branches(pBranch, pJoint->getEdges())
		{
			const sg::FluxPointList& fpl = pBranch->getFluxPoints();
			sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();

			SetBoundaryInterval('1', bil.front(), bil.back(), &bndryInt[0]);
			SetBoundaryInterval('2', bil.front(), bil.back(), &bndryInt[1]);

			forall_branches(pBranch2, pJoint->getEdges())
			{
				if (pBranch2 != pBranch)
				{
					sg::BoundaryInfoList& bil2 = pBranch2->getBoundaryInfoList();

					GetCommonSkelPtIndex(pBranch, pBranch2, &idx, &idx2);

					for (i = '1'; i <= '2'; i++)
					{
						for (j = '1'; j <= '2'; j++)
						{
							if (bndryInt[i - '1'].Inside(bil2[idx2][j].index))
							{
								DBG_MSG4("Fixing crossing spokes", fpl[idx].p, 
									bil[idx][i].pt, bil2[idx2][j].pt)

								BoundaryInterval bnint2;
								int ii = (i == '1') ? '2' : '1'; // other side of 'i'

								// Set the interval of branch 2 side j to find the offending spoke
								SetBoundaryInterval(j, bil2.front(), bil2.back(), &bnint2);								

								if (bnint2.Inside(bil[idx][i].index))
								{
									DBG_MSG1("Spokes are inverted")

									// the spokes are simply inverted
									std::swap(bil[idx][i], bil2[idx2][j]);
									// Update the interval to reflect the change
									SetBoundaryInterval(i, bil.front(), bil.back(), &bndryInt[i - '1']);
								}
								else if (bnint2.Inside(bil[idx][ii].index))
								{
									DBG_MSG4("Endpoint", bil2[idx2][j].pt, "is changed to", bil[idx][ii].pt)

									// the spoke of the other branch ended up on the wrong side
									bil2[idx2][j] = bil[idx][ii];
								}
								else
								{
									DBG_MSG4("Endpoint", bil[idx][i].pt, "is changed to", bil2[idx2][j].pt)

									// the spoke of the current branch is the offending one
									bil[idx][i] = bil2[idx2][j];
									// Update the interval to reflect the change
									SetBoundaryInterval(i, bil.front(), bil.back(), &bndryInt[i - '1']);
								}

								DBG_MSG3("Fixed spokes of branch one", bil.front(), bil.back())
								DBG_MSG3("Fixed spokes of branch two", bil2.front(), bil2.back())
							}
						}
					}
				}
			}
		}
	}
/////////////////////////////////////////////////////////////////////////////////

	inline void CorrectCrossingSpokes(const sg::Point& p0, sg::BoundaryPoint& bp0, 
		const sg::Point& p1, sg::BoundaryPoint& bp1) const;
		
	inline int CorrectSpokes(const sg::Point& skelPt, sg::BoundaryPoint& bp0, 
		sg::BoundaryPoint& bp1) const;
/*!
	@brief If any of the given pair of spokes (on either side) cross one onother, 
	they are corrected such that they end up sharing their target boundary point.
*/
void BoundaryPointFinder::CorrectCrossingSpokes(const sg::Point& p0, 
												sg::BoundaryPoint& bp0, 
												const sg::Point& p1, 
												sg::BoundaryPoint& bp1) const
{
	// IF the endpoins of the spokes is the same, we are done
	if (bp0.pt == bp1.pt)
		return; // this is an okay intersection

	POINT pt00, pt01, pt10, pt11, intPt;

	int status = FindLineSegmentIntersection(
		AssignPtCoord(pt00, p0), AssignPtCoord(pt01, bp0.pt),
		AssignPtCoord(pt10, p1), AssignPtCoord(pt11, bp1.pt),
		&intPt);

	// If the segments intersect, the return value is 2
	if (status == 2)
	{
		DBG_MSG5("Correcting spoke intersection", p0, bp0.pt, p1, bp1.pt)
		DBG_MSG2("Intersection point is", intPt)

		double dist01 = p0.sqDist(bp1.pt);
		double dist10 = p1.sqDist(bp0.pt);

		//(dist01 < dist10) ? bp0 = bp1 : bp1 = bp0;
	}
}

/*!
	@brief Makes a pair of given spokes end at the same boundary point.
	The source of each spoke is given by p0 and p1. The target of these spokes
	is given by bp0, bp1. The resulting common target point is either bp0 or bp1,
	such that the modified spokes have the shortest possible length.

	@return 0 if bp0 is the point that changed, and 1 otherwise (ie, bp1 changed)
*/
int BoundaryPointFinder::CorrectSpokes(const sg::Point& skelPt, sg::BoundaryPoint& bp0, 
									    sg::BoundaryPoint& bp1) const
{
	DBG_MSG4("Correcting spokes", skelPt, bp0.pt, bp1.pt)

	if (skelPt.sqDist(bp0.pt) < skelPt.sqDist(bp1.pt))
	{ 
		bp1 = bp0;
		return 1;
	}
	else
	{
		bp0 = bp1;
		return 0;
	}
}

/////////////////////////////////////////////////////////////////////////////////
/*!
	@brief Finds closest points using priority search. If the KDTree is not build,
	it builds it but does not check for errors. 
	
	If memory errors when building the tree are a concern, build the tree before 
	calling this function.

	If parameters pBi0 and pBiN are given, they are used as the first and last 
	boundary info elements. In such a case, the point search is restricted
	to the boundary intervals defined by each side of the given *pBi0 and *pBiN.
*/
void BoundaryPointFinder::AssignBoundaryPoints(const sg::FluxPointList& fpl, sg::BoundaryInfoList& bil,
											   const sg::BoundaryInfo* pBi0 /* = NULL */,
											   const sg::BoundaryInfo* pBiN /* = NULL */)
{
	if (!m_bAreKDTreesBuilt)
		BuildKDTrees();

	ASSERT(bil.empty() || fpl.size() == bil.size());
	ASSERT((!pBi0 && !pBiN) || (pBi0 && pBiN));

	if (bil.empty())
		bil.resize(fpl.size());

	const int N = fpl.size() - 1;

	// If the bndry infor of the two endpoins is not given, we fill it in
	// as as to get bndry intervals before processing the inner points
	if (pBi0 && pBiN)
	{
		bil[0] = *pBi0;
		bil[N] = *pBiN;
	}
	else
	{
		const int d = MIN(3, N);

		sg::Vector tangent0(fpl[d].p.x - fpl[0].p.x, fpl[d].p.y - fpl[0].p.y);
		sg::Vector tangentN(fpl[N].p.x - fpl[N - d].p.x, fpl[N].p.y - fpl[N - d].p.y);

		tangent0.normalize();
		tangentN.normalize();

		bool bDecrease0 = IsDecreasingRadius(fpl[0],     fpl[d], d == 3);
		bool bDecreaseN = IsDecreasingRadius(fpl[N - d], fpl[N], d == 3);

		FindExtremeBoundaryPoints(fpl[0], tangent0, bDecrease0, fpl[1], bil[0]);
		FindExtremeBoundaryPoints(fpl[N], tangentN, bDecreaseN, fpl[N - 1], bil[N]);
	}

	// Make sure that the spokes do not cross
	//CorrectCrossingSpokes(fpl[0].p, bil[0].first, fpl[N].p, bil[N].first);
	//CorrectCrossingSpokes(fpl[0].p, bil[0].second, fpl[N].p, bil[N].second);

	// Set intervals assuming a clock-wise ordering
	int sz = m_origBndryPts.Size();
	BoundaryInterval side1(sz, bil[0].first.index, bil[N].first.index);
	BoundaryInterval side2(sz, bil[0].second.index, bil[N].second.index);

	// Swap the intervals' limits if they are set incorrectly
	if (side1.Includes(bil[0].second.index))
		side1.Swap();

	if (side2.Includes(bil[0].first.index))
		side2.Swap();

	FindInnerBoundaryPoints(fpl, side1, side2, bil);
	
	AssignBoundaryDistanceInfo(fpl, side1, '1', bil);
	AssignBoundaryDistanceInfo(fpl, side2, '2', bil);

	AssignAxisDistanceInfo(fpl, bil);
}

/////////////////////////////////////////////////////////////////////////////////

	/*void GetMinMaxCosAngle(double& minCosAngle, double maxCosAngle) const
	{
		if (m_corner1.cosAngle <= m_corner2.cosAngle)
		{
			minCosAngle = m_corner1.cosAngle;
			maxCosAngle = m_corner2.cosAngle
		}
		else
		{
			minCosAngle = m_corner2.cosAngle;
			maxCosAngle = m_corner1.cosAngle
		}
	}*/
/////////////////////////////////////////////////////////////////////////////////
		//if (prevP1Norm >= p1Norm + 1)
		//	break;

		//DBG_STREAM_IF("Distance 1 is decreaing " << prevP1Norm << "," << p1Norm 
		//	<< ", " << pt << ", " << p1, prevP1Norm >= p1Norm + 3)

		//prevP2Norm = 0;
		//prevP2.set(-1, -1);

		//ASSERT(i++ < 1000);

		/*for (right = bi.Next(idx); right != idx && right != exLimRight; bi.MoveNext(right))
		{
			DBG_PRINT1(i)
			
			bi.GetBoundaryPoint(right, p2);

			//DBG_PRINT3(right.bndryPointIdx, right.bndrySegmentIdx, p2)
			//DBG_C_LOG(DBG_VAL(right.bndryPointIdx) << DBG_VAL(right.bndrySegmentIdx) << DBG_VAL(p2) << DBG_VAL(prevP2))
			//WARNING(p2 == prevP2, "Repeated boundary point on the right");
			prevP2 = p2;

			p2 -= this->pt;
			p2Norm2 = p2.sqNorm();

			if (p2Norm2 < s_dBndryCornerMinSqDist)
				continue;

			if (p2Norm2 > maxSqDist)
				break;

			p2Norm = sqrt(p2Norm2);

			if (prevP2Norm >= p2Norm + 1)
				break;

			//DBG_STREAM_IF("Distance 2 is decreaing " << prevP2Norm << "," << p2Norm
			//	<< "," << pt << "," << p2, prevP2Norm >= p2Norm + 3)

			cosAlpha = p1.dot(p2) / (p1Norm * p2Norm);

			if (cosAlpha > this->cosAngle)
			{
				this->cosAngle = cosAlpha;
				this->leftArm  = p1;
				this->rightArm = p2;
			}

			prevP2Norm = p2Norm;
		}

		prevP1Norm = p1Norm;*/
/////////////////////////////////////////////////////////////////////////////////
	//! Sets 'pt' to the boundary point referenced by idx
	/*void GetBoundaryPoint(const Index& idx, POINT& pt) const
	{
		sg::Point aux;

		GetBoundaryPoint(idx, aux);

		pt.x = aux.x;
		pt.y = aux.y;
	}*/
/////////////////////////////////////////////////////////////////////////////////
	BoundaryIntervalWithGaps::Index newLeft, newRight;

	exLimLeft.SetNull();
	exLimRight.SetNull();
/////////////////////////////////////////////////////////////////////////////////
/*!
	@brief 
*/
void BoundaryPointFinder::FindCorner(const int i, const int j, const int k, const double& maxSqDist, 
									 BoundaryCorner* pCornerInfo)
{
	ASSERT(i >= 0 && j >= 0 && k >= 0);

	KDTree& bndryPts = m_origBndryPts; // use original points

	const int sz = bndryPts.Size();
	BoundaryInterval bi(sz, i, k);

	// If we don't have a valid middle point, choose the shortest interval. Otherwise,
	// choose the interval that includes the given middle point.
	if (((i == j || k == j) && bi.Size() > sz / 2) || !bi.Includes(j))
		bi.Swap();

#ifdef _DEBUG
	if (!bi.Includes(j))
	{
		DBG_PRINT4(i, j, k, bi)
		pCornerInfo->angle = M_PI;
		pCornerInfo->index = -1;
		return;
	}
#endif

	ASSERT(bi.Includes(j));

	POINT p0, p1;
	double dist2;
	int i0, i1, k0, k1;

	// Expand the left side of the interval
	bndryPts.GetDataPoint(bi.First(), p0.x, p0.y);

	for (i0 = bi.First(); true; i0 = i1)
	{
		i1 = bi.Pred(i0);
		bndryPts.GetDataPoint(i1, p1.x, p1.y);

		dist2 = p0.SqDist(p1);

		if (dist2 > maxSqDist || i1 == bi.Last())
			break;
	}

	// Expand the right side of the interval
	bndryPts.GetDataPoint(bi.Last(), p0.x, p0.y);

	for (k0 = bi.Last(); true; k0 = k1)
	{
		k1 = bi.Succ(k0);
		bndryPts.GetDataPoint(k1, p1.x, p1.y);
		
		dist2 = p0.SqDist(p1);

		if (dist2 > maxSqDist || k1 == i0)
			break;
	}

	// Create an expanded boundary interval
	BoundaryInterval ebi(sz, i0, k0);

	//DBG_C_LOG(DBG_VAL(bi) << DBG_VAL(ebi) << DBG_VAL(j))
	ASSERT(ebi.Includes(i) && ebi.Includes(j) && ebi.Includes(k));

	FindCorner(bi, ebi, maxSqDist, -1, -1, pCornerInfo);
}

void BoundaryPointFinder::FindCorner(const BoundaryInterval& bi, BoundaryInterval& ebi,
									 const double& maxSqDist, 
									 int exLimLeft, int exLimRight,
									 BoundaryCorner* pCornerInfo)
{
	// Find minimum angle within the extended interval
	double minAvgAngle = M_PI, minValidAvgAngle = M_PI;
	double minAngle = M_PI;
	int minAngleIdx = -1;
	int lastIdx = ebi.Succ(ebi.Last());
	BoundaryCorner bc;

	pCornerInfo->Clear(); // sets corner angle to M_PI

	for (int idx = ebi.First(); idx != lastIdx; idx = ebi.Succ(idx))
	{
		ComputeMinimumAngle(idx, maxSqDist, exLimLeft, exLimRight, &bc);

		if (bc.angle <= minAngle)
		{
			minAngle = bc.angle;
			minAngleIdx = idx;

			// If min is in the non-extended interval, it is a valid return value
			if (bi.Includes(idx))
			{
				*pCornerInfo = bc;
				pCornerInfo->index = idx;
			}
		}
	}

	DBG_C_LOG(DBG_VAL(bi) << DBG_VAL(ebi) << DBG_VAL(maxSqDist)
		<< DBG_VAL(minAngleIdx) << DBG_VAL(minAngle)
		<< DBG_VAL(pCornerInfo->index) << DBG_VAL(pCornerInfo->angle))

	if (minAngle != pCornerInfo->angle)
	{
		BoundaryInterval leftInterval(bi.GetBndryLength(), ebi.First(), bi.First());

		if (leftInterval.Includes(minAngleIdx))
		{
			const int last = bi.Pred(bi.First());

			exLimLeft = minAngleIdx;

			for (int i = 0; i < 2 && exLimLeft != last; i++)
				exLimLeft = ebi.Succ(minAngleIdx);

			ebi.SetFirst(ebi.Succ(exLimLeft));

			//exLimLeft = ebi.Pred(minAngleIdx);
			//ebi.SetFirst(ebi.Succ(minAngleIdx));
		}
		else
		{
#ifdef _DEBUG
			BoundaryInterval rightInterval(bi.GetBndryLength(), bi.Last(), ebi.Last());
			ASSERT(rightInterval.Includes(minAngleIdx));
#endif
			const int last = bi.Succ(bi.Last());

			exLimRight = minAngleIdx;

			for (int i = 0; i < 2 && exLimRight != last; i++)
				exLimRight = ebi.Pred(minAngleIdx);

			ebi.SetLast(ebi.Pred(exLimRight));

			//exLimLeft = ebi.Succ(minAngleIdx);
			//ebi.SetLast(ebi.Pred(minAngleIdx));
		}
		
		double dist = sqrt(maxSqDist);// - 0.5;

		FindCorner(bi, ebi, dist * dist, exLimLeft, exLimRight, pCornerInfo);
	}	
}

/////////////////////////////////////////////////////////////////////////////////
/*!
	@brief Computes the angles between the tangents at both endpoints of
	the segment. The tangents are given in the direction of deacresing angle.
*/
void LigatureSegment::FindBoundaryCorner(char side, BoundaryCorner* pCornerInfo) const
{
	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

	int firstIdx = bil[m_first][side].index;
	int lastIdx  = bil[m_last][side].index;

	unsigned int i;
	bool bAllPointsAreValid = true;

	for (i = m_first; i <= m_last && bAllPointsAreValid; i++)
		if (bil[i][side].index < 0)
			bAllPointsAreValid = false;

	if (bAllPointsAreValid)
	{
		ASSERT(m_last >= m_first);

		// Find some unique middle point to fully specify the boundary interval
		int middleIdx = firstIdx;

		for (i = m_first + 1; i < m_last && middleIdx == firstIdx; i++)
			middleIdx = bil[i][side].index;

		// Set a reasonable scale for the computation of the convex corner
		const double dMaxSqDist = bil[m_first][side].pt.sqDist(bil[m_last][side].pt) + 16;
		
		s_pBndryPtFinder->FindCorner(firstIdx, middleIdx, lastIdx, dMaxSqDist, pCornerInfo);
	}	
	else // set valid output parameters
	{
		pCornerInfo->Clear();
	}
}
/////////////////////////////////////////////////////////////////////////////////
	//! Gets the boundary interval associated with the given index's branchSide
	const BoundaryInterval& GetBndryInt(const Index& idx) const
	{ 
		return GetBndryInt(idx.branchSide);
	}
/////////////////////////////////////////////////////////////////////////////////
	for (int i = 0; i < argc; i++)
		std::cout << argv[i] << ", ";
	std::cout << std::endl;
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 
*/
void BoundaryPointFinder::FindLigatureSegments(const sg::FluxPointList& fpl, 
											   char cSide,
											   sg::BoundaryInfoList& bil)
{
	int nSize = fpl.size() - 1; // we do not include the first point
	dml::POINTS data(nSize);
	double x = 0, cumulBar = 20;
	bool bUseBothSides = (cSide == 'x');

	ASSERT(cSide == 'x' || cSide == '1' || cSide == '2');

	for (int i = 0; i < nSize; i++)
	{
		x += SkeletonDistance(fpl[i], fpl[i + 1]);
		
		if (bUseBothSides)
			cumulBar += bil[i + 1]['1'].bar + bil[i + 1]['2'].bar;
		else
			cumulBar += bil[i + 1][cSide].bar;

		data[i].Set(x, cumulBar);
	}

	PolyLineApprox poly(nSize / 2.0, 0.05, 10, -1);

	poly.SetDbgMode(true);

	std::cout << "disp('Fitting branch: " << bil[0].first.pt << bil[nSize - 1].first.pt 
		<< ", size: " << cSide << "')" << std::endl;

	poly.Fit(data);
}

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Stores the new branch as the current fixed branch. If there
	is a previously fixed branch, the ligature information in it is
	transferred to the new branch. 
	
	In general, a branch does not need to be fixed more than once and so
	there is no need to transfer any information.
*/
void GSG::UpdateFixedBranchSegment(GSGNode& gnode, SkelBranch* pNewBranch)
{
	const BranchSegment& bs = gnode.GetFixedBranchSegment();

	// if there is a fix and it has a ligature segment...
	if (bs.m_pBranch && bs.Size() != bs.BranchSize())
	{
		ASSERT(!bs.IsInverted());

		DBG_C_LOG("Re fixing branch " << PRN_BRANCH_PTR(pNewBranch))

		ASSERT(GetFirstJoint(bs.m_pBranch) == bs.m_pBranch->n1);
		ASSERT(GetLastJoint(bs.m_pBranch) == bs.m_pBranch->n2);

		// The old fixed branch and the new one can only have one
		// of its endpoints in common, as the fixing involves adding
		// at least one segment at either end (or boths ends)
		if (bs.m_pBranch->n1 == pNewBranch->n1 || 
			bs.m_pBranch->n1 == pNewBranch->n2)
		{
			ASSERT(bs.m_pBranch->n2 != pNewBranch->n1 && 
			       bs.m_pBranch->n2 != pNewBranch->n2);

			DBG_C_LOG("\tcase 1: segments added on the left")

			gnode.SetFixedBranchSegment(
				BranchSegment(pNewBranch, bs.First(), pNewBranch->size() - 1));
		}
		else if (bs.m_pBranch->n2 == pNewBranch->n1 || 
			bs.m_pBranch->n2 == pNewBranch->n2)
		{
			ASSERT(bs.m_pBranch->n1 != pNewBranch->n1 && 
			       bs.m_pBranch->n1 != pNewBranch->n2);

			DBG_C_LOG("\tcase 2: segments added on the right")

			SkelPtIndex d = bs.BranchSize() - bs.Last();

			gnode.SetFixedBranchSegment(
				BranchSegment(pNewBranch, 0, pNewBranch->size() - d));
		}
		else // new segments were added on both ends
		{
			DBG_C_LOG("\tcase 3: segments added on both ends")

			gnode.SetFixedBranchSegment(BranchSegment(pNewBranch));
		}
	}
	else
	{
		gnode.SetFixedBranchSegment(BranchSegment(pNewBranch));
	}
}

/////////////////////////////////////////////////////////////////////////////////		
void BoneGraphView::DrawBGElementInfo(const BGElement* pBGElem, const SGInfo* si, 
									  const char* szLabel, leda::color c) const
{
	double x1, y1;
	leda_list<leda_point> pts;
	int nPtCount = pBGElem->m_shocks.GetSize();

	// Draw bone points
	for (int i = 0; i < nPtCount; i++)
	{
		const ShockPoint& bp = pBGElem->m_shocks[i];

		x1 = bp.pt.x - si->delta_x;
		y1 = (si->reflex_y - bp.pt.y) - si->delta_y;

		if (m_bDrawContinuousSkeleton)
			pts.push(leda::point(x1, y1));
		else
			m_pWnd->draw_pixel(x1, y1, c);

		if (m_bShowLabels && i == nPtCount / 2)
			m_pWnd->draw_text(x1, y1, szLabel, c);

		if (m_bShowBGSpokes)
		{
			leda::point pt(x1, y1);
			m_pWnd->draw_segment(pt, ReMapPt(bp.bndryPt1, si), leda::red);
			m_pWnd->draw_segment(pt, ReMapPt(bp.bndryPt2, si), leda::orange);
		}
	}

	if (m_bDrawContinuousSkeleton)
		m_pWnd->draw_polyline(pts, c);

	if (m_bShowBGAxis)
	{
		// Draw piecewise cubic Bezier approximation
		int oldWidth = m_pWnd->set_line_width(2);
		
		for (int j = 0; j < pBGElem->m_axisFunction.GetSize(); j++)
		{
			leda::list<leda::point> ctrlPts;

			ctrlPts.push_back(ReMapPt(pBGElem->m_axisFunction[j].GetP0(), si));
			ctrlPts.push_back(ReMapPt(pBGElem->m_axisFunction[j].GetP1(), si));
			ctrlPts.push_back(ReMapPt(pBGElem->m_axisFunction[j].GetP2(), si));
			ctrlPts.push_back(ReMapPt(pBGElem->m_axisFunction[j].GetP3(), si));

			m_pWnd->draw_bezier(ctrlPts, 100, leda::blue);
		}

		m_pWnd->set_line_width(oldWidth);
	}
}
/////////////////////////////////////////////////////////////////////////////////		
	//! Removes the trailing ligature around a gap joint
	void SubtractGapLigature(const LigatureSegment& ls)
	{
		// We cannot subtract from the fixed branch because we would lose...
		if(HasFixedBranch())
		{
			SetBroken(); // must me fixed again now
			//TODO, see how to subtract the segment
			SkelBranch* pBranch;

			forall_branches(pBranch, ls.m_pJoint->edges)
			{
				if (pBranch->pEdgeData == ls.m_pBranch->pEdgeData)
				{
					// both point to this gsg node
					LigatureSegment ls2(ls.m_pJoint, pBranch);
					m_segments.SubtractLigatureInterval(ls2);
					return;
				}
			}
			ASSERT(false); // we shouldn't be here
		}
		else
			m_segments.SubtractLigatureInterval(ls);
	}
/////////////////////////////////////////////////////////////////////////////////		
	if (extPos == string::npos)
		extPos = str.size() - 1;
/////////////////////////////////////////////////////////////////////////////////		
	/*int errnum;*/
	//int errval; 
	//_get_errno(&errval);
	//std::cout << "Error number = " << errnum << ", " << errval << std::endl;

	errnum = _spawnl(/*_P_WAIT*/_P_NOWAIT, GetPrgName(), GetPrgName(), "-v", "1", GetArg(0), NULL);
/////////////////////////////////////////////////////////////////////////////////		
	/*leda::node_array<int> dist(dag, -1);
	SmartArray<leda::node> roots = dag.GetAllRoots();
	leda::list<leda::node> nodes;
	leda::node v;

	for (int r = 0; r < roots.GetSize(); r++)
	{
		nodes = BFS(dag, roots[r], dist);
		int d = 0;

		forall(v, nodes)
		{
			if (dist[v] > d)
				d = dist[v];
		}

		for (; d >= 0; d--)
		{
			forall(v, nodes)
			{
				if (dist[v] == d)
					DrawNodeOrderedInfo(dag.GetNode(v), si);
			}
		}
	}*/
/////////////////////////////////////////////////////////////////////////////////		
	// define possible pixel colors
	leda::color color[] = {leda_black, leda_red, leda_brown, leda_blue, leda_violet, leda_grey3};
	const int NUM_COLORS = (sizeof(color) / sizeof(color[0]));
	
/////////////////////////////////////////////////////////////////////////////////		

if (m_corners.index1 >= 0)
{
	sg::Point cornerPt;

	s_pBndryPtFinder->GetBoundaryPoint(m_corners.index1, &cornerPt);
	m_corners.valid1 = sqrt(wi.SquaredDistance(last, cornerPt)) + 0.5 < sqrt(wi.SquaredDistance(first, cornerPt));

	DBG_C_LOG(DBG_VAL(m_pBranch->getFluxPoint(last)) << DBG_VAL(m_pBranch->getFluxPoint(first)) << DBG_VAL(cornerPt) <<
		DBG_VAL(wi.SquaredDistance(last, cornerPt)) << DBG_VAL(wi.SquaredDistance(first, cornerPt)))
}
else
{
	m_corners.valid1 = false;
}

if (m_corners.index2 >= 0)
{
	sg::Point cornerPt;

	s_pBndryPtFinder->GetBoundaryPoint(m_corners.index2, &cornerPt);
	m_corners.valid2 = sqrt(wi.SquaredDistance(last, cornerPt)) + 0.5 < sqrt(wi.SquaredDistance(first, cornerPt));

	DBG_C_LOG(DBG_VAL(m_pBranch->getFluxPoint(last)) << DBG_VAL(m_pBranch->getFluxPoint(first)) << DBG_VAL(cornerPt) <<
		DBG_VAL(wi.SquaredDistance(last, cornerPt)) << DBG_VAL(wi.SquaredDistance(first, cornerPt)))
}
else
{
	m_corners.valid2 = false;
}

/////////////////////////////////////////////////////////////////////////////////		

/*!
	@brief Finds the endpoins of the ligature gap around a joint

	Let b0 and b0' be the boundary points on either side of the
	ligament segment associated with joint point p0; and let b1
	and b1' be the boundary point associated with the estimated
	ligature segment endpoint s1, as shown in Figure 4c. We
	are interested in knowing skeletal points s2 and s3, with
	corresponding boundary points b2 and b3' on the attachment
	side. The assumption of the model is that the distance from
	b1 to b0, is equal to that between b0 and b2. And similarly,
	the distance from b1' to b0' is said to be equal to that between
	b0' and b3'.
*/
void LigatureSegment::FindGapLigature(SkelBranch* pBranch, SkelJoint* pJoint,
									  const std::list<LigatureSegment>& ligSegs)
{
	// Declare aliases to deal with nicer names
	const sg::FluxPoint& fp = pJoint->fp;
	const sg::FluxPointList& fpl = pBranch->getFluxPoints();
	const sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();
	unsigned int& i = m_first;  // note that i is an 'out' variable
	unsigned int& j = m_last;   // note that j is an 'out' variable

	m_pBranch = pBranch; // save the pointer to the branch in the ligature info
	m_pJoint = pJoint;  // save the pointer to the joint in the ligature info

	ASSERT(fpl[0].p == fp.p || fpl[fpl.size() - 1].p == fp.p);
	ASSERT(fpl.size() > 1 && fpl.size() == bil.size());

	DBG_C_LOG(DBG_VAL(pJoint->fp.p))

	unsigned int last;
	int inc;

	if (fpl[0].p == fp.p) // set params to move forward
	{
		i = 0;
		last = fpl.size() - 1;
		inc = 1;
	}
	else                  // set params to move backwards
	{
		i = fpl.size() - 1;
		last = 0;
		inc = -1;
	}

	const LigatureSegment& ls = ligSegs.front();
	ASSERT(!ls.IsEmpty());

	const sg::BoundaryInfoList& ligBil = ls.m_pBranch->getBoundaryInfoList();

	char brSide, ligSide;
	SkelPtIndex brIdx, ligIdx;
	
	GetCommonBndryPoint(pBranch, ls.m_pBranch, &brIdx, &ligIdx, &brSide, &ligSide);

	//DBG_MSG3(fp.p, fpl[0].p, i)
	//DBG_MSG4(brIdx, ligIdx, brSide, ligSide)

	ASSERT(ligIdx == ls.m_first || ligIdx == ls.m_last);
	ASSERT(i == brIdx);

	const double r0 = fabs(fpl[i].dist);       // radius at common joint point
	const SkelPtCoord& p0 = bil[i][brSide].pt; // bndry point at common joint point

	// Get the squared distance between the pair of bndry poins on the ligature segment
	const double dist2 = ligBil[ls.m_first][ligSide].pt.sqDist(ligBil[ls.m_last][ligSide].pt);

	j = i + inc;

	/*r0 >= fabs(fpl[j].dist) &&*/
	double maxDist = MIN(ls[ls.m_first].radius(), ls[ls.m_last].radius());
	double maxDist2 = maxDist * maxDist;

	while (j != last && fpl[i].p.sqDist(fpl[j].p) <= maxDist2 && p0.sqDist(bil[j][brSide].pt) <= dist2)
	{
		j += inc;
	}

	// Remember, i and j are return variables. We need to make sure that i < j
	if (i != 0) // we read in reverse order, so swap the values of i and j
	{
		ASSERT(i == fpl.size() - 1);
		unsigned int x = i; i = j; j = x; // swap operation in "one line"
	}
}

/////////////////////////////////////////////////////////////////////////////////		

const double r0 = (m_dRadiusRatio > 0) ? m_dEndptRadius / m_dRadiusRatio : 2;
const double dMaxSqDist = r0 * r0;
		
/////////////////////////////////////////////////////////////////////////////////		
	// If we found a full ligature segment, we are done. If not, we need to keep
	// searching for semiligature
	if (j != wi.Last() && !bFullLigature && 
		((m_cumBAR.normal1 <= MAX_CUM_BAR && ) || 
		 (m_cumBAR.normal2 <= MAX_CUM_BAR)))
	{
		const unsigned int old_j = j;
		double minBAR = MIN(m_cumBAR.normal1, m_cumBAR.normal2);
		bool bIsSemiLigature = IsSemiLigature();
		CumulativeBAR cbar;

		for (unsigned int k = j + wi.Inc(); wi.SizeToLast(k) >= 2; k += wi.Inc())
		{
			if (wi.SquaredDistance(i, k) < r0r0)
				continue;

			wi.ComputeBAR(i, k, &cbar);
			
			if (cbar.normal1 < minBAR || cbar.normal2 < minBAR || !bIsSemiLigature)
			{
				j = k;
				minBAR = MIN(cbar.normal1, cbar.normal2);
				bIsSemiLigature = true;
			}
			else //if (wi.SquaredDistance(old_j, k) >= r0r0)
				break;
		}

		// Update attributes if j changed
		if (j != old_j)
			SetLigatureAttributes(wi, i, j);
	}

/////////////////////////////////////////////////////////////////////////////////	
/*!
	@brief Computes the angles between the tangents at both endpoints of
	the segment. The tangents are given in the direction of deacresing angle.
*/
void LigatureSegment::FindBoundaryCorner(char side, double& minAngle, int& cornerIndex) const
{
	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
	//const sg::FlucPointList& fpl = m_pBranch->getFluxPoints();

	int firstIdx = bil[m_first][side].index;
	int lastIdx  = bil[m_last][side].index;

	// Set valid values in case we do not get to set the output parameters
	minAngle = M_PI;
	cornerIndex = -1;

	if (firstIdx < 0 || lastIdx < 0)
		return;

	const SkelPtCoord& firstPt = bil[m_first][side].pt;
	const SkelPtCoord& lastPt  = bil[m_last][side].pt;

	double cad = bil[m_last].cumAxisDist - bil[m_first].cumAxisDist;

	const double r0 = (m_dRadiusRatio > 0) ? m_dEndptRadius / m_dRadiusRatio : 2;
	const double dMaxSqDist = r0 * r0;

	double alpha;
	int lastIndex = -1;

	for (unsigned int i = m_first + 1; i < m_last; i++)
	{
		const sg::BoundaryPoint& bp = bil[i][side];

		if (bp.index >= 0 && bp.index != lastIndex)
		{
			alpha = s_pBndryPtFinder->ComputeBoundaryAngle(bp.index, dMaxSqDist);
			lastIndex = bp.index;

			if (alpha < minAngle)
			{
				minAngle = alpha;
				cornerIndex = i;
			}
		}
	}

	DBG_C_LOG(DBG_VAL(minAngle) << DBG_VAL(dMaxSqDist))
}
/////////////////////////////////////////////////////////////////////////////////	
/*!
	@brief 
*/
double BoundaryPointFinder::ComputeBoundaryAngle(int i, double maxSqDist)
{
	POINT p0, p1, p2; //, p3;
	double alpha, min_alpha, avg_alpha, p1Norm2, p2Norm2, n;
	int l, r, alphaCount;

	KDTree& bndryPts = m_smoothBndryPts; //m_origBndryPts;
	const int sz = bndryPts.Size();
	ASSERT(sz > 0);

	min_alpha = -1;
	avg_alpha = 0;
	alphaCount = 0;
	bndryPts.GetDataPoint(i, p0.x, p0.y);

	for (l = (i > 0) ? i - 1 : sz - 1; l != i; (l > 0) ? l-- : l = sz - 1)
	{
		bndryPts.GetDataPoint(l, p1.x, p1.y);
		p1 = p1 - p0;
		p1Norm2 = p1.SqNorm();

		if (p1Norm2 > maxSqDist && alphaCount > 0)
			break;

		if (p1Norm2 < s_dBndryCornerMinSqDist)
			continue;

		for (r = (i + 1 < sz) ? i + 1 : 0; r != i; (r + 1 < sz) ? r++ : r = 0)
		{
			bndryPts.GetDataPoint(r, p2.x, p2.y);
			p2 = p2 - p0;
			p2Norm2 = p2.SqNorm();

			//DBG_PRINT1(p2Norm2)

			// We need to see at least one valid point of the right arm
			if (p2Norm2 > maxSqDist && alphaCount == 0)
				maxSqDist = p2Norm2; // update max so that the left arm has a chance too

			if (p2Norm2 > maxSqDist)
				break;

			if (p2Norm2 < s_dBndryCornerMinSqDist)
				continue;

			//p3 = p2 - p1;

			//n = (p1Norm2 + p2Norm2 - p3.SqNorm()) / (2 * sqrt(p1Norm2) * sqrt(p2Norm2));
			n = p1.Dot(p2) / (sqrt(p1Norm2) * sqrt(p2Norm2));
			ASSERT(fabs(n) <= 1.01);

			if (n < -1)
				n = -1;

			if (n > 1)
				n = 1;

			//n = (ax * bx + ay * by) / (sqrt(a2) * sqrt(b2));
			
			alpha = acos(n);
			ASSERT(alpha >= 0);

			if (alphaCount == 0 || alpha < min_alpha)
			{
				min_alpha = alpha;
				//isconvex = (p1.x * p3.y - p1.y * p3.x < 0);
			}

			avg_alpha += alpha;
			alphaCount++;
		}
	}

	//DBG_C_LOG(DBG_VAL(i) << DBG_VAL(s_dBndryCornerMinSqDist) << DBG_VAL(maxSqDist) << DBG_VAL(alphaCount))

	ASSERT(min_alpha >= 0);

	if (alphaCount == 0)
		return M_PI;

	// Make convex angles positive and concave angles negative
	//if (isconvex)
	//	min_alpha = -min_alpha;

	return min_alpha;
	//return avg_alpha / alphaCount;
}

/////////////////////////////////////////////////////////////////////////////////	

				/*if (ls.IsFullLigature())
				{
					bAngleCondition = true;
				}
				else if (bSide1Lig || bSide2Lig)
				{
					// See if we can improve BAR
					if (bOverlappingState && 
						wi.IsGreaterThan(ls.First(), bestLigSeg.First()) &&
						wi.IsGreaterThan(ls.Last(), bestLigSeg.Last()) &&
						ls.m_dEndptRadius <= bestLigSeg.m_dEndptRadius)
					{
						LigatureSegment ls2;
						double prevBAR, currBAR;

						ls2 = ls; //.m_pBranch = bs.m_pBranch;

						ls2.FindLigature(wi, bestLigSeg.Source(), ls.Target());

						prevBAR = MIN(bestLigSeg.m_cumBAR.normal1, bestLigSeg.m_cumBAR.normal2);
						currBAR = MIN(ls2.m_cumBAR.normal1, ls2.m_cumBAR.normal2);

						if (currBAR <= prevBAR) // since current segment is larger
						{
							ls = ls2;
						}
					}
					
					if (ls.m_dRadiusRatio <= MAX_RAD_RATIO)
						bAngleCondition = ls.TestSemiLigatureAngle();
					else
						bAngleCondition = true; // pretend is true by now
				}
				else
				{
					bAngleCondition = false;
				}*/
				
/////////////////////////////////////////////////////////////////////////////////	
					/*if (bOverlappingState)
					{
						DBG_MSG5("Replacing", 
							bestLigSeg[bestLigSeg.First()].p, 
							bestLigSeg[bestLigSeg.Last()].p, 
							bestLigSeg.First(), bestLigSeg.Last())

						DBG_MSG5("with", 
							ls[ls.First()].p, ls[ls.Last()].p, ls.First(), ls.Last())
					}*/
					
/////////////////////////////////////////////////////////////////////////////////	

/*!
	@brief Computes the angles between the boundary points associated with origin 
	of the ligature segment	and the ligature line formed by conecting both 
	endpoints of the segment.

	The origin of the ligature is the endpoint with greatest radius.
*/
bool LigatureSegment::TestFullLigatureAngles() const
{
	double angle, index;

	FindBoundaryCorner('1', angle, index);

	if (angle <= 2.62)
	{
		m_nCornerIndex1 = index;

		FindBoundaryCorner('2', angle, index);

		if (angle <= 2.62)
		{
			m_nCornerIndex2 = index;
			return true;
		}
	}

	m_nCornerIndex1 = -1;
	m_nCornerIndex2 = -1;

	return false;
}

/*!
	@brief Computes the angles between the tangents at both endpoints of
	the segment. The tangents are given in the direction of deacresing angle.
*/
bool LigatureSegment::TestSemiLigatureAngle() const
{
	char side = (m_cumBAR.normal1 < m_cumBAR.normal2) ? '1' : '2';
	double angle, index;

	FindBoundaryCorner(side, angle, index);

	return angle <= 2;
}

/////////////////////////////////////////////////////////////////////////////////	

DBG_C_LOG(DBG_VAL(m_first) << DBG_VAL(m_last))
DBG_C_LOG(DBG_VAL(side))

/////////////////////////////////////////////////////////////////////////////////	

	/*const sg::FluxPointList& fpl = m_pBranch->getFluxPoints();
	sg::Vector v1, v2;
	unsigned int i, j, di, dj, N;

	GetLigatureEndpoints(&i, &j);

	N  = fpl.size() - 1;
	
	if (i < j)
	{
		di = MIN(3, N - i);
		dj = MIN(3, N - j);
		v1 = fpl[i + di].p - fpl[i].p;
		v2 = fpl[j + dj].p - fpl[j].p;
	}
	else
	{
		di = MIN(3, i);
		dj = MIN(3, j);
		v1 = fpl[i - di].p - fpl[i].p;
		v2 = fpl[j - dj].p - fpl[j].p;
	}
	v1.normalize();
	v2.normalize();

	return (acos(v1.dot(v2)) >= MIN_SEMI_LIG_ANGLE);*/

/////////////////////////////////////////////////////////////////////////////////	

	/*const sg::FluxPointList& fpl    = m_pBranch->getFluxPoints();
	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();
	unsigned int i, j;

	GetLigatureEndpoints(&i, &j);

	sg::Vector v = fpl[j].p - fpl[i].p; // ligature line vector
	v.normalize();

	sg::Vector b1 = bil[i].first.pt - fpl[i].p;
	sg::Vector b2 = bil[i].second.pt - fpl[i].p;

	return (acos(v.dot(b1) / b1.norm()) < MAX_FULL_LIG_ANGLE && 
		    acos(v.dot(b2) / b2.norm()) < MAX_FULL_LIG_ANGLE);*/
		    
/////////////////////////////////////////////////////////////////////////////////	
const unsigned int minLigSegSize, const unsigned int minNonLigSegSize

/*
		// Remove small non-lig segments at the front of the list
		if (front().m_first - bs.First() + 1 < minNonLigSegSize)
		{
			front().m_first = bs.First();
			DBG_C_LOG("removing front non-lig")
		}

		// Remove small non-lig segments at the back of the list
		if (bs.Last() - back().m_last + 1 < minNonLigSegSize)
		{
			back().m_last = bs.Last();
			DBG_C_LOG("removing back non-lig")
		}*/

/////////////////////////////////////////////////////////////////////////////////	

//! Copies branches from src to tgt and deletes src
		void mergeNodes(DiscreteDivergenceSkeletonNode *tgt,
                        const DiscreteDivergenceSkeletonNode *src)
		{
			DDSEdgeVect::const_iterator edgeIt;
			DDSNodeVect::iterator nodeIt;
			DDSEdge* pEdge;

			if (tgt != src)
			{
				for (edgeIt = src->edges.begin(); edgeIt != src->edges.end(); edgeIt++)
				{
					pEdge = *edgeIt;
					FluxPointList& fpl = pEdge->getFluxPoints();

					if (pEdge->n1 == src)
						pEdge->n1 = tgt;

					if (pEdge->n2 == src)
						pEdge->n2 = tgt;

					if (fpl.front().p == src->fp.p)
						fpl.front() = tgt->fp;

					if (fpl.back().p == src->fp.p)
						fpl.back() = tgt->fp;

					tgt->edges.push_back(pEdge);
				}

				for (nodeIt = nodes.begin(); nodeIt != nodes.end(); nodeIt++)
				{
					if (*nodeIt == src)
					{
						nodes.erase(nodeIt);
						break;
					}
				}

				delete src;
			}
		}
		
/////////////////////////////////////////////////////////////////////////////////	
	// There is nothing special about semi-ligature now, so make them non-ligature
	nonLig.splice(nonLig.end(), semiLigSegs);
/////////////////////////////////////////////////////////////////////////////////	
	/*(m_dRadiusRatio <= MAX_RAD_RATIO &&
		m_cumBAR.normal1 <= MAX_CUM_BAR && m_cumBAR.normal2 <= MAX_CUM_BAR
		&& TestFullLigatureAngles());*/
/////////////////////////////////////////////////////////////////////////////////	
friend LogFile& operator<<(LogFile& lf, int val)
	{ 
		if (lf.m_pLogStatus == NULL || *lf.m_pLogStatus)
		{
			if (!lf.IsOpen())
				lf.OpenFile();

			const std::ostream& fs = os;
			operator<<(os, val); 
		}

		return os;
	}
	
	friend std::istream& operator>>(std::istream &is, LogFile& lf)
	{ 
		if (lf.m_pLogStatus == NULL || *lf.m_pLogStatus)
		{
			if (!lf.IsOpen())
				lf.OpenFile();

			return operator>>(is, lf); 
		}

		return is; 
	}
	
/////////////////////////////////////////////////////////////////////////////////

LogFile::LogFile(const char* szFileName)
{
	open(szFileName, ios::out | ios::trunc);
}
 
/////////////////////////////////////////////////////////////////////////////////

	const sg::BoundaryInfoList& bil = m_pBranch->getBoundaryInfoList();

	char side = (m_cumBAR.normal1 < m_cumBAR.normal2) ? '1' : '2';

	//const SkelPtCoord& firstPt = bil[m_first][s].pt;
	//const SkelPtCoord& lastPt  = bil[m_last][s].pt;

	//double leftMaxSqDist, rigthMaxSqDist;

	double minAlpha = M_PI;

	unsigned int a, b, d = (m_last - m_first);

	if (d == 0)
	{
		return M_PI;
	}
	if (d % 2 == 0)
	{
		a = m_first + d - 1;
		b = m_first + d;
	}
	else
	{
		a = m_first + d - 1;
		b = m_first + d + 1;
	}

	//for (unsigned int i = m_first + 1; i < m_last; i++)
	//for (unsigned int i = a; i <= b; i++)
	for (unsigned int i = m_first; i <= m_last; i++)
	{
		const sg::BoundaryPoint& bp = bil[i][side];

		if (bp.index >= 0 && bp.dtValue < minAlpha)
				minAlpha = bp.dtValue;

		/*if (bi.index >= 0)
		{
			leftMaxSqDist  = firstPt.sqDist(bi.pt);
			rigthMaxSqDist = lastPt.sqDist(bi.pt);
			alpha = s_pBndryPtFinder->ComputeBoundaryAngle(bi.index, leftMaxSqDist, rigthMaxSqDist);
		}
		else
		{
			alpha = M_PI;
		}

		if (alphaCount++ == 0 || alpha < minAlpha)
			minAlpha = alpha;*/
	}

	return minAlpha <= 2;//2.62;
}

/////////////////////////////////////////////////////////////////////////////////

if (dist2 < r0r0 && 
				(m_cumBAR.normal1 <= MAX_CUM_BAR || m_cumBAR.normal2 <= MAX_CUM_BAR))
			{
				unsigned int k;
				CumulativeBAR cbar;

				for (k = j + wi.Inc(); k != wi.Last(); k += wi.Inc())
				{
					if (wi.SquaredDistance(i, k) >= r0r0)
						break;
					
					wi.ComputeBAR(i, k, &cbar);

					if (cbar.normal1 > MAX_CUM_BAR || cbar.normal2 > MAX_CUM_BAR)
					{
						j = k;
						m_cumBAR = cbar;
						break;
					}
				}
			}

/////////////////////////////////////////////////////////////////////////////////

	BezierSegmentArray m_axisFunction; //<! debugging info
	LineSegmentArray m_radiusFunction; //<! debugging info
	
/////////////////////////////////////////////////////////////////////////////////

'pos' should not fall outside the two extreme endpoints of the 
	bone array, sice nested ligature in thos places should be
	already handled by the GSG graph construction.
	
/////////////////////////////////////////////////////////////////////////////////
if (!m_params.m_nSubtractLigatureFromJunctions)
{
}
else
{
	GSGEdge ed(pJoint);
	ed.m_ligature.FindRootedPseudoLigature(pBranch, pJoint);
	new_edge(j, GetNode(pBranch), ed);
}
				
/////////////////////////////////////////////////////////////////////////////////

		/*else // find grand parent TODO: change to a recursive call
		{
			leda::edge e2;
			leda::node u;

			// v is the parent not
			//ASSERT(indeg(v) > 0 && indef(v) <= 2);
			ASSERT(indeg(v) == 1); //TODO: change this whole thing
			
			e2 = m_genSkelGraph.first_in_edge(v);

			GSGEdge& gsgParentEdge = m_genSkelGraph.GetEdge(e2);

			u = source(m_genSkelGraph.first_in_edge(source(e))); //TODO: write a shortcut
			const BoneArray& baGrandParent = m_gsgNodeToBones[u];

			srcPos = FindSourceNode(baGrandParent, gsgParentEdge.m_position);

			ASSERT(srcPos.valid); //else we are in trouble

			i = srcPos.pos;

			j = FindTargetNode(baChild, 
				baGrandParent[i].second[gsgParentEdge.m_position].p);

			AddBGEdge(baGrandParent[i].first, baChild[j].first);
		}*/
		
/////////////////////////////////////////////////////////////////////////////////

void BGC::SetBGElementAttributes(BGElement* pBGElem, const BranchSegment& bs)
{
	if (bs.IsEmpty())
	{
		pBGElem->m_simpleAttributes.m_dLength = 0;
		pBGElem->m_simpleAttributes.m_dAvgRadius = 0;
		pBGElem->m_shocks.Clear();
	}
	// See if we have the special case of repeated two points
	else if (bs.Size() == 2 && bs[bs.First()].p == bs[bs.First() + 1].p)
	{
		pBGElem->m_simpleAttributes.m_dLength = 0;
		pBGElem->m_simpleAttributes.m_dAvgRadius = bs[bs.First()].radius();
		pBGElem->m_shocks.Resize(1);

		ShockPoint& bp = pBGElem->m_shocks[0];

		CopyFluxPointInfo(bs[bs.First()], bs(bs.First()), bp);
		bp.axisDist = 0;
	}
	else
	{
		SkelPtIndex j;
		int i;

		pBGElem->m_simpleAttributes.m_dLength = 0;
		pBGElem->m_simpleAttributes.m_dAvgRadius = 0;

		pBGElem->m_shocks.Resize(bs.Size());

		for (i = 0, j = bs.First(); j <= bs.Last(); i++, j++)
		{ 
			ShockPoint& bp = pBGElem->m_shocks[i];
			
			CopyFluxPointInfo(bs[j], bs(j), bp);

			bp.axisDist = (i == 0) ? 0 : bp.pt.L2(pBGElem->m_shocks[i-1].pt);

			pBGElem->m_simpleAttributes.m_dLength    += bp.axisDist;
			pBGElem->m_simpleAttributes.m_dAvgRadius += bp.radius;

			if (bp.axisDist >= 1.5)
			{
				DBG_LINE
				DBG_PRINT2(bp.pt, pBGElem->m_shocks[i-1].pt)
			}

			ASSERT(i == 0 ||
				(bs.Size() == 2 && bp.pt == pBGElem->m_shocks[i-1].pt) ||
				bp.pt != pBGElem->m_shocks[i-1].pt);

			//ASSERT(i == 0 || bp.pt.L2(pBGElem->m_shocks[i-1].pt) < 1.5);
		}

		pBGElem->m_simpleAttributes.m_dAvgRadius /= pBGElem->m_shocks.Size();
	}
}

/////////////////////////////////////////////////////////////////////////////////

leda::edge BGC::AddBGEdge(leda::node u, leda::node v, 
						  const LigatureSegment& ls, unsigned int pos)
{
	if (indeg(v) == 0) // u is first parent
	{
		const BGNode* pSrcNode = m_pBoneGraph->GetBGNode(u);
		BGNode* pTgtNode = m_pBoneGraph->UnsafeGetBGNode(v);

		if (pSrcNode->Type() == BGNode::BACK_BONE)
		{
			pTgtNode->m_simpleAttributes.m_nFlowsFrom = -1;
		}
		else if (pTgtNode->NumPoints() > 0)
		{
			ShockPoint bp;
			double d0, dN;

			d0 = pSrcNode->FindClosestPoint(pTgtNode->FirstShockPoint().pt, &bp);
			dN = pSrcNode->FindClosestPoint(pTgtNode->LastShockPoint().pt, &bp);

			pTgtNode->m_simpleAttributes.m_nFlowsFrom = (d0 < dN) ? 0 : 1;
		}
		else
		{
			pTgtNode->m_simpleAttributes.m_nFlowsFrom = 0;
		}
	}

	const BGNode* pSrcNode = m_pBoneGraph->GetBGNode(u);

	ASSERT((!pSrcNode->m_shocks.IsEmpty() && pos >= 0) ||
		    (pSrcNode->m_shocks.IsEmpty() && pos == 0));

	double dNormalizedPos = pos;

	if (pos > 0)
		dNormalizedPos /= pSrcNode->m_shocks.Size() - 1;

	BGEdge* pBGEdge = new BGEdge(dNormalizedPos * 2 - 1);

	SetBGElementAttributes(pBGEdge, ls);

	return m_pBoneGraph->NewEdge(u, v, pBGEdge);
}

/////////////////////////////////////////////////////////////////////////////////

const POINT& GetFirstPt() const 
	{ 
		ASSERT(!m_shocks.IsEmpty());
		return m_shocks.GetHead().pt;
	}

	const POINT& GetLastPt() const 
	{ 
		ASSERT(!m_shocks.IsEmpty());
		return m_shocks.GetTail().pt;
	}
	
/////////////////////////////////////////////////////////////////////////////////

BranchSegment bs0 = nodeBS; // ie, init branch info
		unsigned int i, j, pos;
		leda::node u, v;
		
		ba.reserve(lsl.size() + 1);

		LigatureSegmentList::iterator it0, it = lsl.begin();

		ASSERT(it->First() >= nodeBS.First());

		// If the list begins with a ligature segment, skip it... 
		if (it->First() == nodeBS.First())
		{
			gsgnode.SubtractAttachmentLigature(*it);
			i = it->Last() + 1;
			it++;
		}
		else
			i = nodeBS.First();
		
		for (u = nil; it != lsl.end(); it++)
		{
			j = it->First() - 1;

			bs0.SetLimits(i, j);
			v = AddBGNode(bs0);

			// If we partitioned a prior bone, connect it to v
			if (u != nil)
			{
				ASSERT(!ba.back().IsEmpty());

				if (bs0[i].radius() > bs0[j].radius())
					AddBGEdge(u, v, it0, ba.back().Size() - 1);
				else
					AddBGEdge(v, u, it0, 0);
			}

			// Add a new entry to the mapping between branch and bones
			ba.push_back(std::make_pair(v, bs0));

			u = v;
			i = it->Last() + 1;
			it0 = it;
		}

		// The ending points of the branch segment are either bone or ligamnet
		if (lsl.back().Last() == nodeBS.Last())
		{
			gsgnode.SubtractAttachmentLigature(lsl.back());
		}
		else // there is a trailing non-ligature segment (ie, a bone)
		{
			ASSERT(i <= nodeBS.Last());

			j = nodeBS.Last();

			bs0.SetLimits(i, j);
			v = AddBGNode(bs0);

			// If we partitioned a prior bone, connect it to v
			if (u != nil) 
			{
				ASSERT(!ba.back().IsEmpty());

				if (bs0[i].radius() > bs0[j].radius())
					AddBGEdge(u, v, it0, ba.back().Size() - 1);
				else
					AddBGEdge(v, u, it0, 0);
			}

			// Add a new entry to the mapping between branch and bones
			ba.push_back(std::make_pair(v, bs0));
		}
		
/////////////////////////////////////////////////////////////////////////////////

//DBG_MSG4(bs0[bs0.First()].p, bs0[bs0.Last()].p, bs0.First(), bs0.Last())

/////////////////////////////////////////////////////////////////////////////////

	//std::list< std::pair<leda::edge, leda::edge> > m_pendingEdges;

	//leda::node_map<BranchSegment> m_boneToSegment;

	//leda::node_array<leda::node> m_nodeMap;

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Adds edges between the parent of the given attachment/junction/crossing
	node and its children
*/
void BGC::AddEdgesFromGSGNode(leda::node t)
{
	GSGNodeType type = m_genSkelGraph.GetNode(t).m_type;

	ASSERT(m_genSkelGraph.GetNode(t).m_type != GSG_BRANCH);
	ASSERT(indeg(t) == 1);

	// Select the parent node of the attachment/junction/crossing node 
	leda::node v = source(m_genSkelGraph.first_in_edge(t));

	const BoneArray& baParent = m_gsgNodeToBones[v];
	leda::edge e;
	Position srcPos;
	unsigned int i, j;

	// Add edge from source to each target node
	forall_out_edges(e, t)
	{
		GSGEdge& gsgEdge = m_genSkelGraph.GetEdge(e);
		const BoneArray& baChild = m_gsgNodeToBones[target(e)];

		srcPos = FindSourceNode(baParent, gsgEdge.m_position);

		//if (srcPos.valid)
		//{
			i = srcPos.pos;
			j = FindTargetNode(baChild, baParent[i].second[gsgEdge.m_position].p);
			AddBGEdge(baParent[i].first, baChild[j].first);
		//}
		/*else // find grand parent TODO: change to a recursive call
		{
			leda::edge e2;
			leda::node u;

			// v is the parent not
			//ASSERT(indeg(v) > 0 && indef(v) <= 2);
			ASSERT(indeg(v) == 1); //TODO: change this whole thing
			
			e2 = m_genSkelGraph.first_in_edge(v);

			GSGEdge& gsgParentEdge = m_genSkelGraph.GetEdge(e2);

			u = source(m_genSkelGraph.first_in_edge(source(e))); //TODO: write a shortcut
			const BoneArray& baGrandParent = m_gsgNodeToBones[u];

			srcPos = FindSourceNode(baGrandParent, gsgParentEdge.m_position);

			ASSERT(srcPos.valid); //else we are in trouble

			i = srcPos.pos;

			j = FindTargetNode(baChild, 
				baGrandParent[i].second[gsgParentEdge.m_position].p);

			AddBGEdge(baGrandParent[i].first, baChild[j].first);
		}*/
	}
}

/////////////////////////////////////////////////////////////////////////////////

switch (val)
			{
			case 'a': ShowGraph(*(DAG*)GetSGInfo1()->pSG); break; // @TODO clone graph 
			case 'b': if (GetSGInfo2()->pSG->GetNodeCount() > 0) 
						  ShowGraph(*(DAG*)GetSGInfo2()->pSG); 
				      break; // @TODO clone graph
			case 'c': m_bShowCoords = !m_bShowCoords; break;
			case 'd': m_bShowPointData = !m_bShowPointData; break;
			case 'e': m_bShowEdgeInfo = !m_bShowEdgeInfo; breakl
			case 'g': m_nShowLigature = !m_nShowLigature; break;
			case 'h': ShowWindowCommandHelp(); break;
			case 'k': m_bDrawDisks = !m_bDrawDisks; break;
			case 'n': m_bShowLinApprox = !m_bShowLinApprox; break;
			case 'l': m_bShowLabels = !m_bShowLabels; break;
			case 'r': m_pWnd->reset_clipping(); break;
			case 's': m_bShowBGSpokes = !m_bShowBGSpokes; break; // bone graph only @TODO change this
			case 't': m_bShowNodeType = !m_bShowNodeType; break;
			case 'x': m_bShowBGAxis = !m_bShowBGAxis; break; // bone graph only @TODO change this
			case 'y': m_nShowRays++; if (m_nShowRays > 2) m_nShowRays = 0; break;
			case 'z': m_bShowBezApprox = !m_bShowBezApprox; break;
			default:
				if (isdigit(val))
					m_nShowColorLines = val - '0';
				else
					bReadNextEvent = false;
			}
			
/////////////////////////////////////////////////////////////////////////////////

leda::node_array<int> dfsnum(dag);
			leda::node_array<int> compnum(dag);
			leda::list<leda::edge> allEdges;
			
			allEdges = DFS_NUM(dag, dfsnum, compnum);

			DBG_PRINT1(allEdges.size())

			forall(e, allEdges)
			{
				DBG_MSG4(dfsnum[source(e)], dfsnum[target(e)], compnum[source(e)], compnum[target(e)])

				DrawNodeInfo(dag.GetNode(source(e)), info[i], nodeColorIdx++);
				DrawNodeInfo(dag.GetNode(target(e)), info[i], nodeColorIdx++);
				DrawEdgeInfo(dag.GetEdge(e), info[i], edgeColorIdx++);
			}
			
/////////////////////////////////////////////////////////////////////////////////

void DAGView::DrawInDFSOrder(const DAG& dag) 
{
	SmartArray<leda::node> roots = dag.GetAllRoots();
	leda::node_array visited(dag, -1);
	leda::node_array level(dag, -1);
	int i, nDFSIndex;
	leda::node v;
	
	for (i = 0; i < roots.GetSize(); i++)
		nDFSIndex = ComputeNodesInfo(roots[i], visited);
}

int DAG::ComputeNodesInfo(leda::node v, int nLevel, int nDFSIndex)
{
	leda::node u;
	DAGNodePtr& ptrNode = GetNode(v);

	// Default level is -1. Loopy nodes should have their greatest height
	if (ptrNode->GetLevel() < nLevel)
		ptrNode->SetLevel(nLevel);		
	
	if (ptrNode->GetDFSIndex() == -1)
		ptrNode->SetDFSIndex(nDFSIndex++);

	nLevel++;
	
	forall_adj_nodes(u, v)
		nDFSIndex = ComputeNodesInfo(u, nLevel, nDFSIndex);

	return nDFSIndex;
}

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Draws the shape of the object. The base class implementation simply 
	reads the original file (if it still around) and copies it to the screen.
	Derived classed should use the data store in the shape representation to
	"recreate" the original image.

	Note: It is assumed that the DAG label is in fact the path to the original file.
*/
void DAGView::DrawSilhouette(const SGInfo* si) const
{
	const DAG* pDAG = si->pSG;
	FILE* fp = fopen(pDAG->GetDAGLbl(), "r");
		
	if (fp != NULL)
	{
		fclose(fp);
	
		cimg_library::CImg<float> shapeImg(pDAG->GetDAGLbl());

		if (shapeImg.dimy() > 0 && shapeImg.dimx() > 0)//(!shapeImg.is_empty())
		{
			int r,c;
			
			for (r = 0; r < shapeImg.dimy(); r++)
				for (c = 0; c < shapeImg.dimx(); c++) 
					if (shapeImg(c,r) == 0)
						m_pWnd->draw_pixel(ReMapPt(leda_point(c, r), si), leda_grey1);
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////

/*!
	\brief Wrapper class of a pointer to class DAGEdge. It handles the 
	destruction of the DAGEdge object.

	This class wraps a pointer to an object of class DAGEdge, an keeps track
	of the number of references to the same object. When the number of references
	becomes zero, the referenced object is destroyed.
*/
class DAGEdgePtr : public SmartPtr<dml::DAGEdge>
{
public:	
	//! This is the only special constructor (ie, from double to DAGEdge) 
	DAGEdgePtr(const double& w = DEFAULT_DAG_EDGE_WEIGHT) 
		: SmartPtr<dml::DAGEdge>(dml::DAGEdge(w))
	{
		// there is nothing else to do
	}

	DAGEdgePtr(dml::DAGEdge* p) : SmartPtr<dml::DAGEdge>(p)
	{ 
		// there is nothing else to do
	}

	DAGEdgePtr(const dml::DAGEdge* p) : SmartPtr<dml::DAGEdge>(p) 
	{
		// there is nothing else to do
	}
	
	DAGEdgePtr(const dml::DAGEdge& obj) : SmartPtr<dml::DAGEdge>(obj)
	{
		// there is nothing else to do
	}

	DAGEdgePtr(const SmartPtr<dml::DAGEdge>& x) : SmartPtr<dml::DAGEdge>(x)
	{ 
		// there is nothing else to do
	}

	//! Allows for using the pointer as an edge weight
	/*operator const double&() const
	{ 
		return SmartPtr<dml::DAGEdge>::operator->()->GetWeight();
	}*/
};

/////////////////////////////////////////////////////////////////////////////////

//! Removes the trailing ligature around a gap joint
void SubtractGapLigature(const LigatureSegment& ls)
{
	ASSERT(!HasFixedBranch()); // should NOT be a repaired branch
	m_segments.SubtractLigatureInterval(ls);
}
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 
*/
double BGC::ComputeNodeSaliency(leda::node v, const GSGNode& gsgnode)
{
	// Using the gsgnode info, we can get the DDS branch and then the GSG node
	const BGNode* pBGNode = m_pBoneGraph->GetBGNode(v);
	double sal = 0;

	for (int i = 0; i < pBGNode->m_shocks.Size(); i++)
		sal += pBGNode->m_shocks[i].radius;

	return sal;
}

/////////////////////////////////////////////////////////////////////////////////


/*!
	@brief It returns true iff the boundaed BAR on one or both sides is smaller 
	or equal to LIGATURE_CUM_BAR_TAU and the radius ratio between the segment's
	endpoints is smaller or equal to MAX_RAD_RATIO.
*/
bool LigatureSegment::IsLigature() const
{
	return ((m_dCumBAR1 <= MAX_CUM_BAR || m_dCumBAR2 <= MAX_CUM_BAR)
		    && m_dRadiusRatio <= MAX_RAD_RATIO);
}

/*!
	@brief It returns true iff the boundaed BAR on both sides is smaller or 
	equal to LIGATURE_CUM_BAR_TAU and the radius ratio between the segment's
	endpoints is smaller or equal to MAX_RAD_RATIO.
*/
bool LigatureSegment::IsFullLigature() const
{
	if (m_bIsSpuriousBranch)
		return true; // we want to get rid of these branches

	bool bLigatureBAR       = m_dCumBAR1 <= MAX_CUM_BAR && m_dCumBAR2 <= MAX_CUM_BAR;
	bool bLigatureRadChange = m_dRadiusRatio <= MAX_RAD_RATIO;
	bool bLigatureAlpha1    = fabs(m_dAlpha1) < 1;
	bool bLigatureAlpha2    = fabs(m_dAlpha2) < 1;

	WARNING1((!bLigatureAlpha1 || !bLigatureAlpha2) && bLigatureBAR && bLigatureRadChange,
			"We have a ligature angle case\n", m_pJoint->fp.p);

	return (bLigatureBAR && bLigatureRadChange && bLigatureAlpha1 && bLigatureAlpha2);
}

/*!
	@brief It returns true iff the boundaed BAR on EXACTLY one side is smaller or  
	equal to LIGATURE_CUM_BAR_TAU and the radius ratio between the segment's
	endpoints is smaller or equal to MAX_RAD_RATIO.
*/
bool LigatureSegment::IsSemiLigature() const
{
	bool bLigatureBAR1      = m_dCumBAR1 <= MAX_CUM_BAR;
	bool bLigatureBAR2      = m_dCumBAR2 <= MAX_CUM_BAR;
	bool bLigatureRadChange = m_dRadiusRatio <= MAX_RAD_RATIO;
	bool bLigatureAlpha1    = fabs(m_dAlpha1) < 1;
	bool bLigatureAlpha2    = fabs(m_dAlpha2) < 1;

	bool bLigSide1 = (bLigatureBAR1 && bLigatureRadChange && bLigatureAlpha1);
	bool bLigSide2 = (bLigatureBAR2 && bLigatureRadChange && bLigatureAlpha2);

	return ((bLigSide1 && !bLigSide2) || (!bLigSide1 && bLigSide2));
}

double ComputeDiskOverlap(const SkelPt& fp0, const SkelPt& fp1);

/////////////////////////////////////////////////////////////////////////////////
/*!
	@brief Computes the boundary-to-axis ratio up to the point in which the circle
	defined by the data of pJoint and the circle defined by the data of a flux point
	in pBranch intersect and the intersection points form an angle of PI wrt the line
	that connects the circles. The flux points are searched by starting from the one
	that es equal to the given joint point. Call IsFullLigature() or IsSemiLigature()
	to find out whether the segment is full or semi ligature.

	Note: spurious branches caused by the AFMM algorithm can result in strange
	conditions that affect the ligature computation. For example, this branches
	tend to be shorter than their true length and may be related to "weak" boundary
	deformations. It is then important to deal with them as a special case. We define 
	spurious branch as "a terminal branch whose endpoints greatly overlaps". 
	Solution: a spurius branch should still be labeled as ligature but may fail in
	been selected as the ligature branch in cases of joints with multiple ligatures. 
	We solve this by setting the m_dEndptRadius of a spurious branch to zero, which
	should make it rank first among all ligature branches.
*/
void LigatureSegment::FindRootedLigature(SkelBranch* pBranch, SkelJoint* pJoint)
{
	// Declare aliases to deal with nicer names
	const sg::FluxPoint& fp = pJoint->fp;
	const sg::FluxPointList& fpl = pBranch->getFluxPoints();
	const sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();
	unsigned int& i = m_first;  // note that i is an 'out' variable
	unsigned int& j = m_last;   // note that j is an 'out' variable

	m_pBranch = pBranch; // save the pointer to the branch in the ligature info
	m_pJoint = pJoint;  // save the pointer to the joint in the ligature info

	ASSERT(fpl[0].p == fp.p || fpl[fpl.size() - 1].p == fp.p);
	ASSERT(fpl.size() > 1 && fpl.size() == bil.size());

	// We need to decide how we'll move along the branch: forward or backwards 
	unsigned int last;
	double db1, db2, da;
	int inc;
	
	if (fpl[0].p == fp.p) // set params to move forward
	{
		i = 0;
		last = fpl.size() - 1;
		inc = 1;

		db1 = 0; // delta boundary for side 1
		db2 = 0; // delta boundary for side 2
		da = 0;  // delta axis 
	}
	else                  // set params to move backwards
	{
		i = fpl.size() - 1;
		last = 0;
		inc = -1;

		db1 = bil[i].first.cumBndryDist;  // delta boundary for side 1
		db2 = bil[i].second.cumBndryDist; // delta boundary for side 2
		da = bil[i].cumAxisDist;          // delta axis
	}

	// Make sure that the info of first point is properly initialize to zero
	ASSERT(bil[0].first.cumBndryDist == 0 && bil[0].second.cumBndryDist == 0 && bil[0].cumAxisDist == 0);

	// Find the point "at" the limit defined by the radius of the branch's endpoint
	// REMEMBER: j is an 'out' variable and must end up equal to 'last' if the point is not found
	double dx, dy, r1, dist2, cosAlpha;
	const double r0 = fabs(fp.dist);
	const double r0r0 = fp.dist * fp.dist;

	for (j = i; j != last; j += inc)
	{
		r1 = fabs(fpl[j + inc].dist);   // get radius of the NEXT point (j +- 1)

		dx = fp.p.x - fpl[j + inc].p.x; // get horizontal dist to the NEXT point (j +- 1)
		dy = fp.p.y - fpl[j + inc].p.y; // get vertical dist to the NEXT point (j +- 1)
		dist2 = dx * dx + dy * dy;      // get squared distance to the NEXT point

		cosAlpha = (r1 * r1 + dist2 - r0r0) / (2 * r1 * sqrt(dist2));

		//DBG_PRINT5(fp.p, fpl[j + inc], dist2, r0r0, cosAlpha)

		// The end of the ligature segment must be a point with smaller radius and with a 
		// circle that intersects that of the root at pi/2 angle wrt the line conecting the
		// center of the circles. We don't need to search through points at distance > r0.
		if ((r1 < r0 && cosAlpha >= 0) || dist2 >= r0r0)
		{
			// Note: we want the current point j, since j + inc is outside the ligature segment
			m_dCumBAR1 = fabs(bil[j].first.cumBndryDist - db1) / fabs(bil[j].cumAxisDist - da);
			m_dCumBAR2 = fabs(bil[j].second.cumBndryDist - db2) / fabs(bil[j].cumAxisDist - da);

			break;	
		}
	}

	bool bIsWholeBranch = (j == last);

	// If we have a whole ligature branch, it means we haven't set the cumBARs yet.
	if (bIsWholeBranch)
	{
		last = fpl.size() - 1; // make sure that we are at the true last element
		m_dCumBAR1 = bil[last].first.cumBndryDist / bil[last].cumAxisDist;
		m_dCumBAR2 = bil[last].second.cumBndryDist / bil[last].cumAxisDist;
	}

	// Set the radius of the endpoint opposite to the joint point (before swapping i and j!!!!)
	m_dEndptRadius = fabs(fpl[j].dist);
	m_dRadiusRatio = m_dEndptRadius / r0;
	m_dEndptOverlap = ComputeDiskOverlap(fpl[i], fpl[j]);

	// Set the angle between joint bndry points and the ligature line
	sg::Vector a = fpl[j].p - fpl[i].p;
	a.normalize();

	sg::Vector b1 = bil[i].first.pt - fpl[i].p;
	sg::Vector b2 = bil[i].second.pt - fpl[i].p;

	m_dAlpha1 = acos(a.dot(b1) / b1.norm());
	m_dAlpha2 = acos(a.dot(b2) / b2.norm());

	// Set the spurious branch flag. See Notes above.
	if (bIsWholeBranch && m_dEndptOverlap >= MIN_ENDPT_OVERLAP &&
		(pBranch->n1->degree() == 1 || pBranch->n2->degree() == 1) &&
		(m_dCumBAR1 < 1 && m_dCumBAR2 < 1) &&
		((m_dCumBAR1 + m_dCumBAR2) / 2 <= MAX_CUM_BAR))
	{
		m_dEndptRadius = 0; // so that it ranks first in operator<()
		m_bIsSpuriousBranch = true;
	}
	else
	{
		m_bIsSpuriousBranch = false;
	}

	// Remember, i and j are return variables. We need to make sure that i < j
	if (i != 0) // we read in reverse order, so swap the values of i and j
	{
		ASSERT(i == fpl.size() - 1);

		unsigned int x = i; 

		i = j; 
		j = x;
	}
}

/////////////////////////////////////////////////////////////////////////////////

	/*pBGNode->m_shocks.Resize(gsgnode.m_segments.Size());

	int i = 0;
	unsigned int j;
	BranchSegmentList::const_iterator it = gsgnode.m_segments.begin();

	// Copy all skeleton points associated with the bone
	for (; it != gsgnode.m_segments.end(); it++)
	{
		const BranchSegment& bs = *it;

		for (j = bs.First(); j <= bs.Last(); j++, i++) 
		{ 
			ShockPoint& bp = pBGNode->m_shocks[i];
			CopyFluxPointInfo(bs[j], bs(j), bp);

			//ASSERT(i == 0 || bp.pt.L2(pBGNode->m_shocks[i-1].pt) < 1.5); //~< sqrt(2)
		}
	}*/

/////////////////////////////////////////////////////////////////////////////////

/*void dml::GetObjectAnglesAtJoint(const SkelJoint* pJoint, const sg::Vector& t, 
								 ObjectAngles* pAngles, 
								 SkelBranch* pExcludeBranch)
{
	sg::BoundaryInfoList bil;

	GetBoundaryInfoAtJoint(pJoint, &bil, pExcludeBranch);

	pAngles->resize(bil.size());

	for (unsigned int i = 0; i < bil.size(); i++)
	{
		(*pAngles)[i].first  = ComputeObjectAngle(t, bil[i].first.pt  - pJoint->fp.p);
		(*pAngles)[i].second = ComputeObjectAngle(t, bil[i].second.pt - pJoint->fp.p);
	}
}*/

/////////////////////////////////////////////////////////////////////////////////

// Copy the pointers to the non-ligature branches
	LigatureSegmentList::iterator it;

	nonLigBranches.clear();
	nonLigBranches.reserve(nonLig.size());

	for (it = nonLig.begin(); it != nonLig.end(); it++)
		nonLigBranches.push_back(it->m_pBranch);

/////////////////////////////////////////////////////////////////////////////////

GSGNodeType GSG::LabelJoint(SkelJoint* pJoint, SkelEdges& nonLigBranches,  
                            LigatureSegmentList& ligSegs, bool bUseFixedBranch)
{
	LigatureSegmentList nonLig;
	LigatureSegment ls;
	SkelBranch* pBranch;
	bool bIsCrossing = false;
	int nSemiLig = 0;

	ASSERT(pJoint->degree() >= 3);

	nonLigBranches.clear();
	ligSegs.clear();

	forall_branches(pBranch, pJoint->edges)
	{
		if (bUseFixedBranch && GetNodeData(pBranch).HasFixedBranch())
			pBranch = GetNodeData(pBranch).GetFixedBranch();

		ls.FindRootedLigature(pBranch, pJoint);

		if (ls.IsFullLigature())
			ligSegs.push_back(ls);
		else
			nonLig.push_back(ls);

		if (ls.IsSemiLigature())
			nSemiLig++;

		//DBG_PRINT7(ls.m_first, ls.m_last, ls.m_pBranch->size(), ls.m_dCumBAR1, 
		//	ls.m_dCumBAR2, ls.m_dRadiusChange, ls.m_dEndptOverlap)
	}

	//DBG_PRINT4(pJoint->fp.p, pJoint->degree(), nonLig.size(), nSemiLig)

	// If we don't have a single ligature branch, the joint may be either a crossing
	// or simply a ambiguous case of an attachment. See if it's a crossing first...
	if (nonLig.size() < 2 || nSemiLig > 0)
	{
		if (pJoint->degree() > 3 && nonLig.size() < 2)
		{
			bIsCrossing = true;

			// All branches are ligature
			ligSegs.splice(ligSegs.end(), nonLig);

			DBG_MSG2("Is a non-generic crossing", pJoint->fp)
		}
		else
		{
			SkelBranch* pBranchX = FindCrossingMiddleBranch(pJoint);
			bIsCrossing = (pBranchX != NULL);

			if (bIsCrossing)
			{
				// Make sure all branches are ligature
				ligSegs.splice(ligSegs.end(), nonLig); 

				LigatureSegmentList::iterator it;

				// Look for the ls of the middle branch in the crossing
				for (it = ligSegs.begin(); it->m_pBranch != pBranchX; it++);

				// Add it as a non-lig branch
				nonLig.push_back(*it);
				ligSegs.erase(it);

				DBG_MSG2("Is a crossing", pJoint->fp)
			}
		}

		// If it's not a crossing and has not enough non-lig branches...
		if (!bIsCrossing && nonLig.size() < 2) 
		{
			// ...we need exactly two non-lig branches to form a gap
			ligSegs.sort(); // sorts ligature segments by ending radius size
			ASSERT(ligSegs.front().m_dEndptRadius <= ligSegs.back().m_dEndptRadius);

			do {
				nonLig.push_back(ligSegs.back());
				ligSegs.pop_back();
			} while (nonLig.size() < 2); // find 2 non-lig branches
		}
	}

	// Check for non-generic jucntion
	if (pJoint->degree() > 3 && nonLig.size() > 2) 
	{
		// All branches must be non-ligature
		nonLig.splice(nonLig.end(), ligSegs);

		DBG_MSG2("Is a non-generic junction", pJoint->fp)
	}

	// This are the only valid cases
	ASSERT((!bIsCrossing && nonLig.size() == pJoint->degree() && ligSegs.size() == 0) ||
		   (bIsCrossing  && nonLig.size() == 0 && ligSegs.size() == pJoint->degree()) ||
		   (bIsCrossing  && nonLig.size() == 1 && ligSegs.size() == pJoint->degree() - 1) ||
		   (!bIsCrossing && nonLig.size() == 2 && ligSegs.size() == pJoint->degree() - 2));

	// Copy the pointers to the non-ligature branches
	LigatureSegmentList::iterator it;
	nonLigBranches.reserve(nonLig.size());

	for (it = nonLig.begin(); it != nonLig.end(); it++)
		nonLigBranches.push_back(it->m_pBranch);

	// Return the type of the joint
	if (nonLig.size() == pJoint->degree()) 
		return GSG_JUNCTION;
	else if (bIsCrossing)
		return GSG_CROSSING;
	else
		return GSG_ATTACHMENT;
}


/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 

*/
SkelBranch* GSG::FindSourceBranch(SkelJoint* pJoint, const SkelEdges& branches)
{
	SkelBranch* pBranch;
	SkelPtIndex idx, N, d;
	double alpha, alpha1, alpha2;
	sg::Vector t, v1, v2;
	std::vector< std::pair<double, SkelBranch*> > alphas;
	
	alphas.reserve(branches.size());

	forall_const_branches(pBranch, branches)
	{
		const sg::FluxPointList& fpl    = pBranch->getFluxPoints();
		const sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();

		N = fpl.size() - 1;
		d = MIN(3, N);
		idx = (fpl[0].p == pJoint->fp.p) ? 0 : N;

		ASSERT(fpl[idx].p == pJoint->fp.p);

		v1 = bil[idx].first.pt - fpl[idx].p;
		v2 = bil[idx].second.pt - fpl[idx].p;

		if (idx == 0)
			t.set(fpl[d].p.x - fpl[0].p.x, fpl[d].p.y - fpl[0].p.y);
		else
			t.set(fpl[N - d].p.x - fpl[N].p.x, fpl[N - d].p.y - fpl[N].p.y);

		v1.normalize();
		v2.normalize();
		t.normalize();

		alpha1 = ComputeObjectAngle(t, v1);
		alpha2 = ComputeObjectAngle(t, v2);

		std::cerr << "\n-----------------------------------\n";
		DBG_PRINT2(bil[idx].first.pt, bil[idx].second.pt)
		DBG_PRINT3(v1, v2, t)
		DBG_PRINT2(alpha1, alpha2)

		alpha = (fabs(alpha1) + fabs(alpha2)) / 2.0;

		alphas.push_back(make_pair(alpha, pBranch));
	}

	std::sort(alphas.begin(), alphas.end());

	if (alphas[0].first - alphas[1].first < 0.5)
	{
		for (unsigned int i = 0; i < alphas.size(); i++)
		{
			pBranch = alphas[i].second;
			area = BranchSegmentArea(pBranch->getFluxPoints(),
				0, pBranch->size() - 1);
		}
	}

	std::cerr << "***************************************\n";
	DBG_PRINT3(alphas[0].first, alphas[1].first, alphas[2].first)

	//TODO: check if all alphas are tied up and return nil if the do
	// or else consider threshold on maximum alpha
	if (pJoint->degree() > 3) // by now, just check degree
		return nil;

	return alphas.back().second;
}

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Ensures that all invariant properties of a skeletal graph are
	satisfied
*/
void SkeletalGraph::Regularize()
{
	SkelJoint* pJoint;

	if (!m_pDDSGraph)
		return;

	std::vector< std::pair<SkelJoint*, SkelJoint*> > nodePairs;

	forall_joints(pJoint, m_pDDSGraph->getNodes())
	{
		if (pJoint->degree() < 3)
		{	
			SkelBranch* pBranch;
			SkelJoint* pJoint2;
			bool bProblemFixed = false;

			WARNING1(true, "Joint has less than 3 branches", pJoint->fp);

			DBG_PRINT3(pJoint, pJoint->fp, pJoint->degree())

			forall_branches(pBranch, pJoint->edges)
			{
				DBG_PRINT2(pBranch->n1, pBranch->n2) 
				DBG_PRINT3(pBranch->size(), pBranch->getFirstFluxPoint(), 
					pBranch->getLastFluxPoint())
			}

			// Look for a compatible joint to merge with...
			forall_joints(pJoint2, m_pDDSGraph->getNodes())
			{
				if (pJoint2 != pJoint && pJoint2->fp.p.dist(pJoint->fp.p) < 2)
				{
					DBG_PRINT3(pJoint2, pJoint2->fp, pJoint2->degree())

					forall_branches(pBranch, pJoint2->edges)
					{
						DBG_PRINT2(pBranch->n1, pBranch->n2) 
						DBG_PRINT3(pBranch->size(), pBranch->getFirstFluxPoint(), 
							pBranch->getLastFluxPoint())
					}

					//nodePairs.push_back(make_pair(pJoint2, pJoint));
					bProblemFixed = true;
					break;
				}
			}

			ASSERT(bProblemFixed);
		}
	}

	for (unsigned int i = 0; i < nodePairs.size(); i++)
		m_pDDSGraph->`(nodePairs[i].first, nodePairs[i].second);
}

/////////////////////////////////////////////////////////////////////////////////

	//! Creates a new skeletal graph edge and stores 'v' as the edge's data
	SkelBranch* NewSkelBranch(leda::node v)
	{
		m_extraSkelEdges.push_back(new SkelBranch(v));

		return m_extraSkelEdges.back();
	}
	
/////////////////////////////////////////////////////////////////////////////////

	//DBG_PRINT4(fpl[i].p, fpl[j].p, bil[i].first.pt, bil[i].second.pt)
	//DBG_PRINT2(alpha1, alpha2)
	
	
	if (bIsSpuriousBranch)
		return true; // we want to get rid of these branches

	bool bLigatureBAR = m_dCumBAR1 <= MAX_CUM_BAR && m_dCumBAR2 <= MAX_CUM_BAR;
	bool bLigatureRadChange = m_dRadiusChange <= MAX_RAD_CHANGE;
	bool bLigatureAlpha1 = fabs(alpha1) < 1;
	bool bLigatureAlpha2 = fabs(alpha2) < 1;

	//DBG_MSG5(pJoint->fp.p, bLigatureBAR, bLigatureRadChange, bLigatureAlpha1, bLigatureAlpha2)
	//DBG_MSG4("Final j =", j, pInfo->cumBAR1, pInfo->cumBAR2)
#ifdef _DEBUG
	if ((!bLigatureAlpha1 || !bLigatureAlpha2) && bLigatureBAR && bLigatureRadChange)
	{
		DBG_MSG2("We have a ligature angle case:", pJoint->fp.p)
	}
#endif

	return (bLigatureBAR && bLigatureRadChange && bLigatureAlpha1 && bLigatureAlpha2);
	
/////////////////////////////////////////////////////////////////////////////////

	DBG_PRINT2(t.norm(), v.norm())
	
	DBG_PRINT7(n, pJoint->fp.p, firstTanPt1, lastTanPt1, lp0, lp1, cb.p2)
	
	DBG_PRINT7(n, pJoint->fp.p, firstTanPt0, lastTanPt0, lp0, lp1, cb.p1)
	
	DBG_PRINT4(cb.p0, cb.p1, cb.p2, cb.p3)
	CubicBezierParams cbp(cb);
	if (cbp.GetTangent(-1).x == 0 && cbp.GetTangent(-1).y == 0)
	{
		DBG_PRINT1(cbp.GetTangent(-1))
	}
	
/////////////////////////////////////////////////////////////////////////////////

int TBBInterval::Side(SkelBranch* pBranch) const
{
	int indices[4] = {
		pBranch->getFirstBndryInfo().first.index,
		pBranch->getLastBndryInfo().first.index,
		pBranch->getFirstBndryInfo().second.index,
		pBranch->getLastBndryInfo().second.index,
	};

	bool bIncInSide1 = true;
	int i;

	for (i = 0; i < 4 && bIncInSide1; i++)
		if (!firstSideInt.Includes(indices[i]))
			bIncInSide1 = false;

	if (bIncInSide1)
		return 1;

	bool bIncInSide2 = true;

	for (i = 0; i < 4 && bIncInSide2; i++)
		if (!secondSideInt.Includes(indices[i]))
			bIncInSide2 = false;
			
	return (bIncInSide2) ? 2 : 0;
}

/////////////////////////////////////////////////////////////////////////////////
DBG_STREAM_IF(fp0 << tangent << fp1 << n, bi0.first.index < 0 || bi0.second.index < 0)

void BoundaryPointFinder::FindExtremeBoundaryPoints(const sg::FluxPoint& fp0, const sg::Vector& tangent, 
													bool bDecreasingRadius, const sg::FluxPoint& fp1,
													sg::BoundaryInfo& bi0)
{
	double alpha, dist0, dist1, dist01, minDistA = -1, minDistB = -1, minDistAp = -1, minDistBp = -1;
	double epsilon = INIT_EPSILON;
	double* annPt;
	int idxAp, idxBp, n;

	// Use the un-smooth (original) points to find the pair of external bounadry points
	// in order to avoid strange effects due to false distance between true centers and bndry pts.
	KDTree& bndryPts = m_origBndryPts;

	//static int times = 0;
	//times++;

	sg::Vector tan2 = tangent;
	bool bInc = (fabs(fp1.dist) - fabs(fp0.dist)) > 0;
	double alpha2;

	//if ((bFirstPt && bInc) || (!bFirstPt && !bInc))
	if (bFirstPt)
		tan2.scale(-1);

	//DBG_PRINT4(fp0.p, fp1.p, bFirstPt, bInc)

	do {
		n = bndryPts.RangeSearch(fp0.p.x, fp0.p.y, fabs(fp0.dist), &epsilon, 
			EPSILON_INC, MIN_PTS_RETURNED);

		//if (times == 4)
		//	DBG_MSG6("\nClosest points to", fp0, "with reference point", fp1, "and tangent", tangent)

		for (int i = 0; i < n; i++)
		{
			annPt = bndryPts.GetNNPoint(i);
			alpha = ComputeAlphaAngle(fp0, annPt, tangent);

			// Get distance from fp0 to boundary points
			dist0 = bndryPts.GetNNDistance(i);

			// Compute distance from fp1 to boundary point
			dist1 = sg::Vector(annPt[0] - fp1.p.x, annPt[1] - fp1.p.y).norm();

			alpha2 = ComputeAlphaAngle(fp0, annPt, tan2);

			if (fabs(alpha2) > M_PI_2 && dist0 < dist1)
				continue;

			dist01 = dist0;

			// Get a weighted average of both distances and choose the best one seen
			//dist01 = 0.55 * dist0 + 0.45 * dist1;

			//if (times == 4)
			//	DBG_PRINT6(annPt[0], annPt[1], alpha, dist0, dist1, dist01)

			// Choose the closest to both fp0 and fp1 on each side
			if (alpha >= 0 && (minDistA == -1 || dist01 < minDistA))
			{
				minDistA = dist01;
				bi0.first.index = bndryPts.GetNNIndex(i);
			}
			else if (alpha < 0 && (minDistB == -1 || dist01 < minDistB))
			{
				minDistB = dist01;
				bi0.second.index = bndryPts.GetNNIndex(i);
			}

			// We also want to know who's the closest to fp1 alone (on each side)
			if (alpha >= 0 && (minDistAp == -1 || dist1 < minDistAp))
			{
				minDistAp = dist1;
				idxAp = bndryPts.GetNNIndex(i);
			}
			else if (alpha < 0 && (minDistBp == -1 || dist1 < minDistBp))
			{
				minDistBp = dist1;
				idxBp = bndryPts.GetNNIndex(i);
			}
		}
	} while ((minDistA == -1 || minDistB == -1) && n < bndryPts.Size());

	DBG_STREAM_IF(fp0 << tangent << fp1 << n, bi0.first.index < 0 || bi0.second.index < 0)
	ASSERT(bi0.first.index >= 0 && bi0.second.index >= 0);
/*
	// Check that we are not choosing a point that is too far from fp1's closest on side 1
	if (bi0.first.index != idxAp && bndryPts.DataPointDistance(bi0.first.index, idxAp) > 8)
	{	
		bi0.first.index = idxAp;
	}

	// Check that we are not choosing a point that is too far from fp1's closest on side 2
	if (bi0.second.index != idxBp && bndryPts.DataPointDistance(bi0.second.index, idxBp) > 8)
	{
		bi0.second.index = idxBp;
	}
*/
	//DBG_MSG3("--------------------------\nBest points", bi0.first.index, bi0.second.index)

	// Done. Just copy the points' coordinates
	bndryPts.GetDataPoint(bi0.first.index, bi0.first.pt.x, bi0.first.pt.y);
	bndryPts.GetDataPoint(bi0.second.index, bi0.second.pt.x, bi0.second.pt.y);

	DBG_PRINT2(bi0.first.pt, bi0.second.pt)
}

/////////////////////////////////////////////////////////////////////////////////

		//DBG_PRINT6(1, bi0.first.index, idxAp, bndryPts.GetDataXCoord(bi0.first.index), 
		//	bndryPts.GetDataYCoord(bi0.first.index), bndryPts.DataPointDistance(bi0.first.index, idxAp))
		
		//DBG_PRINT6(2, bi0.second.index, idxBp, bndryPts.GetDataXCoord(bi0.second.index), 
		//	bndryPts.GetDataYCoord(bi0.second.index), bndryPts.DataPointDistance(bi0.second.index, idxBp))
		
/////////////////////////////////////////////////////////////////////////////////

//pWnd->draw_box(x, y - 30, x + 100, y, leda_white);

/////////////////////////////////////////////////////////////////////////////////

		if (ls.m_first > 0)
			m_last = ls.m_first - 1;
		else
		{
			ASSERT(m_last == m_pBranch->size() - 1);
			// we have an empty bone segment. We label it as such by making first = size()
			m_first = m_pBranch->size();
		}
		
/////////////////////////////////////////////////////////////////////////////////
	ObjectAngles angles;
	ObjectAngle a1, a2;
	sg::Vector t;
	
	if (!bIsCrossing)
			continue;

		// Now, we need some extra testing in order to be sure that we really have 
		// a crossing point

		// The spokes of the each joint must be on either side of the line formed
		// by the two endpoints of the middle branch of the crossing
		t = pJoint->fp - pJoint2->fp.p;
		t.normalize;

		// Find the angles of protrusion 1
		GetJointObjectAngles(pJoint, t, &angles, pBranch);
		ASSERT(angles.size() == 2);
		
		if (SIGN(angles[0].first) == SIGN(angles[0].second) 
			&& SIGN(angles[1].first) != SIGN(angles[1].second))
		{
			a1 = angles[0];
		}
		else if	(SIGN(angles[0].first) != SIGN(angles[0].second) 
			&& SIGN(angles[1].first) == SIGN(angles[1].second));
		{
			a1 = angles[1];
		}
		else
			continue;

		// Find the angles of protrusion 2
		GetJointObjectAngles(pJoint2, t, &angles, pBranch);
		ASSERT(angles.size() == 2);

		if (SIGN(angles[0].first) == SIGN(angles[0].second) 
			&& SIGN(angles[1].first) != SIGN(angles[1].second))
		{
			a2 = angles[0];
		}
		else if	(SIGN(angles[0].first) != SIGN(angles[0].second) 
			&& SIGN(angles[1].first) == SIGN(angles[1].second));
		{
			a2 = angles[1];
		}
		else
			continue;

		// The two protrusions should be on oposite sides
		if (SIGN(a1) == SIGN(a2))
			continue;

		// If we made it all the way here, then we found a crossing
		return pBranch;

/////////////////////////////////////////////////////////////////////////////////

forall_branches(pBranch2, pJoint2->edges)
		{
			idx = (pBranch2->getFirstXYPoint() == pJoint2->fp.p) 
				? 0 : pBranch2->size() - 1;

			ASSERT(pBranch2->getFluxPoint(idx).p == pJoint2->fp.p);

			const sg::BoundaryInfo& bi = pBranch2->getBoundaryInfo(idx);

			if (!DoSegmentCircleIntersect(pJoint2->fp.p, bi.first.pt, pJoint->fp) &&
				!DoSegmentCircleIntersect(pJoint2->fp.p, bi.second.pt, pJoint->fp))
			{
				bIsCrossing = false;
			}
		}

/////////////////////////////////////////////////////////////////////////////////

SkelBranch* pBranch2;
		SkelJoint* pJoint2;
		SkelPtIndex idx;
		
		forall_branches(pBranch, pJoint->edges)
		{
			pJoint2 = (pBranch->n1 == pJoint) ? pBranch->n2 : pBranch->n1;
			bIsCrossing = (pJoint2->edges.size() > 2); // init to true if it's not terminal node

			forall_branches(pBranch2, pJoint2->edges)
			{
				idx = (pBranch2->getFirstXYPoint() == pJoint2->fp.p) 
					? 0 : pBranch2->size() - 1;

				ASSERT(pBranch2->getFluxPoint(idx).p == pJoint2->fp.p);

				const sg::BoundaryInfo& bi = pBranch2->getBoundaryInfo(idx);

				if (!DoSegmentCircleIntersect(pJoint2->fp.p, bi.first.pt, pJoint->fp) &&
					!DoSegmentCircleIntersect(pJoint2->fp.p, bi.second.pt, pJoint->fp))
					bIsCrossing = false;
			}

			if (bIsCrossing)
			{
				pBranchX = pBranch; // or collect all crossing branches...
				break;
			}
		}
		
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 
*/
void BGC::AddJunctionEdges(leda::node j)
{
	std::list< std::pair<double, leda::node> > bgnl;
	double sal;
	leda::node a, b;
	leda::edge e;

	// Sort nodes by increasing order of saliency
	forall_in_edges(e, j)
	{
		a = m_genSkelGraph.GetNode(source(e)).m_mappingNode;
		sal = m_pBoneGraph->GetBGNode(a)->m_dSaliency;
		bgnl.push_back(std::make_pair(sal, a));
	}

	bgnl.sort();

	// Select the most salient node as the source node
	a = bgnl.back().second;

	// Add edge from source to each target node
	forall_in_edges(e, j)
	{
		b = m_genSkelGraph.GetNode(source(e)).m_mappingNode;

		if (a != b)
			AddBGEdge(a, b, m_genSkelGraph.GetEdge(e));
	}
}

/////////////////////////////////////////////////////////////////////////////////

	//! Computes the indeg of the node wrt the given node type
	int InDegree(leda::node v, GSGTYPE type) const
	{
		leda::edge e;
		int n = 0;

		forall_in_edges(e, v)
			if ((GetNode(source(e)).m_type == type)
				n++;

		return n;
	}

/////////////////////////////////////////////////////////////////////////////////

	ASSERT(indeg(u) == 0 || indeg(u) == 1);   // at most one attachment
	ASSERT(indeg(v) == 0 || indeg(v) == 1);   // at most one attachment
	ASSERT(outdeg(u) == 0 || outdeg(u) == 1); // at most one endpoint
	ASSERT(outdeg(v) == 0 || outdeg(v) == 1); // at most one endpoint

/////////////////////////////////////////////////////////////////////////////////

		ASSERT(indeg(v) <= 1);
		leda::edge e = first_in_edge(v);
		return (e != nil) ? source(e):nil;

/////////////////////////////////////////////////////////////////////////////////

/*!
   @brief Checks if the a line segment and a circle intersect

   The line segment is defined from p1 to p2
   The sphere is of radius r and centered at sc

   A fast check to determine whether a segment does NOT intersect a circle 
   can be achieved by noting that the closest point on the line through P1P2 
   to the circle's center point P3 is along a perpendicular from P3 to 
   the line. In other words if P is the closest point on the line then 

                         (P3 - P) dot (P2 - P1) = 0 

   Substituting P by the equation of the line P = P1 + u (P2 - P1) we get  

                    [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0 

   Then, if u is not between 0 and 1, the closest point is not between P1 and P2.

   The converse is not true because the segment may be outside the circle and still have
   its closest point to the center be withing the segment. Also, the segment can be 
   small enough to be entirely within the circle.

   Then, one extra condition is that the distance from the closest point on the segment
   to P3 must be smaller or equal to the radius r. However, this is not a sufficient
   condition and cheking it is almost as expensive as calling FindLineCircleIntersection().
   
   Then, of u is within [0,1], we return FindLineCircleIntersection(), and otherwise
   return false.

   @return false if the segment doesn't intersect the circle.
*/
bool dml::DoSegmentCircleIntersect(const POINT& p1, const POINT& p2, const POINT& sc,
								   const double& r)
{
	double dx = p2.x - p1.x;
	double dy = p2.y - p1.y;

	double b = (sc.x - p1.x) * dx + (sc.y - p1.y) * dy;
	double a = dx * dx + dy * dy;

	if (fabs(a) < 0.0001)
		return false;

	double u = b / a;

	if (u < 0 && u > 1)
		return false;

	double u1, u2;

	return FindLineCircleIntersection(p1, p2, sc, r, &u1, &u2);
}

/////////////////////////////////////////////////////////////////////////////////	

typedef std::list<LigatureSegment> LigatureSegmentList;

/////////////////////////////////////////////////////////////////////////////////	

DBG_MSG4(indices[0], indices[1], indices[2], indices[3])
DBG_MSG2(firstSideInt.First(), firstSideInt.Last())
DBG_MSG2(secondSideInt.First(), secondSideInt.Last())
	
	
DBG_MSG4(bs0.IsInverted(), bs1.IsInverted(), bs0[bs0.BranchFirst()].p, bs1[bs1.BranchLast()].p)
DBG_MSG3(ge.m_pAttachJoint->fp.p, ge.m_nSide, bSwapSides)

if (!bs0.IsEmpty())
	DBG_MSG3("bs0", bs0(bs0.First()), bs0(bs0.Last()))
else
	DBG_MSG1("empty bs0")

if (!bs1.IsEmpty())
	DBG_MSG3("bs1", bs1(bs1.First()), bs1(bs1.Last()))
else
	DBG_MSG1("empty bs1")	
	
	
DBG_MSG1(nSide)
DBG_MSG3(bil[0], bil[sz/2], bil[sz - 1])
/////////////////////////////////////////////////////////////////////////////////	
			DBG_MSG4("Tangent:", t, "slope", m);
			DBG_MSG2("New tangent:", t);
			DBG_MSG2("Alpha:", alpha);
			
			if (i > 0)
				DBG_MSG2("Dist to prev pt:", ptTan0.dist(fpl[i - 1].p));

			if (i < sz - 1)
				DBG_MSG2("Dist to next pt:", ptTan0.dist(fpl[i + 1].p));
				
			//DBG_PRINT5(fpl[i].p, m, t, alpha, bil[i][as].pt)
			DBG_MSG3(fpl[i].p, alpha, bil[i][as].pt)
				
/////////////////////////////////////////////////////////////////////////////////

			alphaX = ComputeAlphaAngle(t, v);
			
			if (alpha - alphaX > alpha + alphaX) 
			{
				alpha = -alpha;
				DBG_MSG2("New alpha:", alpha);
			}
			
/////////////////////////////////////////////////////////////////////////////////
DBG_MSG2(bil.back().first.cumBndryDist, bil.back().second.cumBndryDist)
DBG_MSG2(prevCBD[j], bi[s].cumBndryDist)
DBG_MSG2(m_pBranch->size() - 1, m_pBranch->size() - i)
DBG_MSG4(bN.cumAxisDist, bi.cumAxisDist, bN.first.cumBndryDist, bi.first.cumBndryDist)

/////////////////////////////////////////////////////////////////////////////////

//! Find the closest boundary points between the branches 
inline double GetCommonBndryPoint(const SkelBranch* b0, const SkelBranch* b1,
								  SkelPtIndex* pIdx0, SkelPtIndex* pIdx1,
								  char* pSide0, char* pSide1)
{
	const sg::BoundaryInfoList& bil0 = b0->getBoundaryInfoList();
	const sg::BoundaryInfoList& bil1 = b1->getBoundaryInfoList();
	ASSERT(bil0.size() > 0 && bil1.size() > 0);

	const unsigned int n0 = bil0.size() - 1;
	const unsigned int n1 = bil1.size() - 1;

	SkelPtCoord b0pts[] = {bil0[0]['1'].pt, bil0[n0]['1'].pt,
	                       bil0[0]['2'].pt, bil0[n0]['2'].pt};

	SkelPtCoord b1pts[] = {bil1[0]['1'].pt, bil1[n1]['1'].pt,
	                       bil1[0]['2'].pt, bil1[n1]['2'].pt};

	double d, md;
	int i, j, mi, mj;

	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 4; j++)
		{
			d = b0pts[i].sqDist(b1pts[j]);

			if ((i == 0 && j == 0) || d < md)
			{
				md = d;
				mi = i;
				mj = j;
			}
		}
	}

	*pSide0 = (mi < 2) ? '1' : '2';
	*pSide1 = (mj < 2) ? '1' : '2';

	*pIdx0 = (mi % 2 == 0) ? 0 : n0;
	*pIdx1 = (mj % 2 == 0) ? 0 : n1;

	return md;
}

/////////////////////////////////////////////////////////////////////////////////

/*
	@brief Computes the tangent of the axis function at either the first or
	the last point of the segment using a linear total least squares approach.
*/
void BranchSegment::ComputeEndpointTangent(bool bFirstPt, POINT* p0, POINT* p1) const
{
	int nPts = MIN(Size(), 4);
	POINTS pts(nPts);

	SkelPtIndex j = (bFirstPt) ? First() : (Last() + 1 ) - nPts;

	for (int i = 0; i < nPts; i++, j++)
		AssignPtCoord(pts[i], (*this)[j].p);

	double a, b, c; // coefficient of the line: a * x + b * y + c = 0
	LinearTotalLeastSquares(pts, nPts, a, b, c);

	*p0 = GetClosestPointOnLine(a, b, c, pts[0]);
	*p1 = GetClosestPointOnLine(a, b, c, pts[nPts - 1]);

	DBG_MSG2(p0->L2(pts[0]), fabs(a * pts[0].x + b * pts[0].y + c))
	DBG_MSG2(p1->L2(pts[nPts - 1]), fabs(a * pts[nPts - 1].x + b * pts[nPts - 1].y + c))
}

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Fills gaps on the medial axis formed around attachment points.

	In the ideal case, an cubic bezier starting spanning the gap endpoints is
	set. The angles of the inner "handles" of the curve are determined by 
	the tangents at the gap endpoints. The magnitued of the "handle" vectors
	is defined to be the distance to the intersection point between the line formed
	by each handle and the ligature segment associated with the attachment.

	There are many cases for which these conditions don't apply. For example, there
	may be multiple ligature segments, or there may be no intersection point. For
	this cases, the joint point is used as inner control point instead. This provides 
	a reasonable heuristic under lack of enough data.

	If either bs0 or bs1 are empty, there gap itself is unconstraned. The natural solution
	in this case is to choose the middle point of the branch associated with the empty
	segment. However, there are several important detal to account for when doing this. 
	1) If the empty segment is "shared" by to attachment points, then the branch middle
	   point would be repeated. Then, we choose (size / 2 + 1) for bs0, and (size / 2)
	   for bs1.
    2) If the empty branch segment is at the extremes of the list of segments forming
	   a GSG branch, then choosing the middle point of the branch would leave a pice
	   of gap unfilled.
*/
void GSG::FillMedialAxisGap(const BranchSegment& bs0, bool bIsFirstSeg0,
							const BranchSegment& bs1, bool bIsLastSeg1,
							const AttachEdges& attchs, CubicBezier& cb)
{ 
	bool bHaveCtrlPoints01 = false; 
	bool bHaveCtrlPoints23 = false;

	SkelJoint* pJoint = GetCommonSkelJoint(bs0.m_pBranch, bs1.m_pBranch);
	
	ASSERT(!attchs.empty());
	ASSERT(GetEdge(attchs.front()).m_pBranch0 == bs0.m_pBranch || 
		GetEdge(attchs.front()).m_pBranch0 == bs1.m_pBranch);
	ASSERT(GetEdge(attchs.front()).m_pBranch1 == bs1.m_pBranch || 
		GetEdge(attchs.front()).m_pBranch1 == bs0.m_pBranch);

	// The way more common case is to have a single ligature branch. However,
	// in theory we could have more than one. If we have only one we do... 
	if (attchs.size() == 1)
	{
		POINT lp0, lp1, lp2, firstPt, lastPt;
		int n;

		// Find the ligature line segment if needed
		if (bs0.Size() > 2 || bs1.Size() > 2)
		{
			// Use the joint to retrieve the attachment information
			const LigatureSegment& ls = GetEdge(attchs.front()).m_ligature;

			// Get the line segment determined by the ligature endpoints
			// to use as reference for the inner ctrl points MAGNITUDES
			AssignPtCoord(lp0, ls[ls.First()].p);
			AssignPtCoord(lp1, ls[ls.Last()].p);
		}

			//// Get a segment that deffines the lowwer and upper bounds of
			//// the valid handle locations along the ligature line
			//AssignPtCoord(firstPt, bs0[bs0.Last()].p);
			//AssignPtCoord(lastPt, bs1[bs1.First()].p);
			//n = FindLineSegmentIntersection(firstPt, lastPt, lp0, lp1, &lp2);
			//ASSERT(n > 0);

			//if (lp0.SqDist(lp2) < lp1.SqDist(lp2))
			//	lp0 = lp2;
			//else
			//	lp1 = lp2;

		// Find valid first tangent and set first two ctrl points
		if (bs0.Size() > 2) // we can compute first tangent
		{	
			//AssignPtCoord(firstPt, bs0[bs0.Last() - 2].p);
			//AssignPtCoord(cb.p0, bs0[bs0.Last()].p);
			//int n = FindLineSegmentIntersection(firstPt, cb.p0, lp0, lp1, &cb.p1);

			AssignPtCoord(cb.p0, bs0[bs0.Last()].p);
			bs0.ComputeEndpointTangent(false, &firstPt, &lastPt);
			n = FindLineSegmentIntersection(firstPt, lastPt, lp0, lp1, &cb.p1);

			//DBG_PRINT4(firstPt, cb.p0, lp0, lp1)
			//DBG_PRINT4(pJoint->fp.p, cb.p0, cb.p1, n)

			bHaveCtrlPoints01 = (n == 1 || n == 4);
		}

		// Find valid second tangent and set last two ctrl points
		if (bs1.Size() > 2) // we can compute second tangent
		{
			//AssignPtCoord(lastPt,  bs1[bs1.First() + 2].p);
			//AssignPtCoord(cb.p3, bs1[bs1.First()].p);
			//int n = FindLineSegmentIntersection(cb.p3, lastPt, lp0, lp1, &cb.p2);

			AssignPtCoord(cb.p3, bs1[bs1.First()].p);
			bs1.ComputeEndpointTangent(true, &firstPt, &lastPt);
			n = FindLineSegmentIntersection(firstPt, lastPt, lp0, lp1, &cb.p2);

			//DBG_PRINT4(cb.p3, lastPt, lp0, lp1)
			//DBG_PRINT4(pJoint->fp.p, cb.p2, cb.p3, n)

			bHaveCtrlPoints23 = (n == 1 || n == 4);
		}
	}

	// If we don't have the first two ctrl point, use a heuristic to set them...
	if (!bHaveCtrlPoints01)
	{
		if (bs0.Size() > 0) // at least we have a valid endpoint
		{
			AssignPtCoord(cb.p0, bs0[bs0.Last()].p);
		} 
		else // the segment is empty. Choose UPPER middle point or FIRST point
		{
			if (bIsFirstSeg0)
				AssignPtCoord(cb.p0, bs0[bs0.BranchFirst()].p);
			else
				AssignPtCoord(cb.p0, bs0[bs0.BranchSize() / 2].p);
		}

		AssignPtCoord(cb.p1, pJoint->fp.p);

		//DBG_PRINT4(pJoint->fp.p, cb.p0, cb.p1, "from heuristic")
	}

	// If we don't have the last two ctrl point, use a heuristic to set them...
	if (!bHaveCtrlPoints23)
	{
		if (bs1.Size() > 0) // at least we have a valid endpoint
		{
			AssignPtCoord(cb.p3, bs1[bs1.First()].p);
		}
		else // the segment is empty. Choose LOWER middle point or LAST point
		{
			if (bIsLastSeg1)
				AssignPtCoord(cb.p3, bs1[bs1.BranchLast()].p);
			else
				AssignPtCoord(cb.p3, bs1[bs1.BranchSize() / 2].p); // do not add 1
		}

		AssignPtCoord(cb.p2, pJoint->fp.p);

		//DBG_PRINT4(pJoint->fp.p, cb.p2, cb.p3, "from heuristic")
	}

	//DBG_PRINT4(cb.p0, cb.p1, cb.p2, cb.p3)
}

/////////////////////////////////////////////////////////////////////////////////
			/*
			if (m < 0)
			{
				t.scale(-1);
				alpha = acos(m);
			}
			else
				alpha = -acos(m);
			*/
				
				
DBG_PRINT2(t, -t + sg::Vector(1,1));

			if (i > 0)
			{
				u = fpl[i].p;
				v = fpl[i-1].p;

				if (v.sqDist(t + u) < v.sqDist(-t + u))
					t.scale(-1);
			}
			else
			{
				u = fpl[i].p;
				v = fpl[i+1].p;

				if (v.sqDist(t + u) > v.sqDist(-t + u))
					t.scale(-1);
			}
			
/////////////////////////////////////////////////////////////////////////////////

sg::BoundaryInfo& bi = bil[i];

			//if (i > 0 && 

			/*t.normalize();
			v.normalize();
			
			alpha = acos(t.dot(v));*/

			//alpha = ComputeAlphaAngle(t, v);
		
			//v.normalize();
			//v.rotate(2 * alpha);

			//t.rotate((ls.m > 0) ? alpha:-alpha);

			//DBG_MSG3(fpl[i].p, t, t.norm())
			
			//DBG_MSG3(bi[as].pt, t, t.norm())
			
			DBG_NEWLINE
			
/////////////////////////////////////////////////////////////////////////////////

		// Before merging, append a placeholder for the attachment edge info
		AttachEdges& attchs = AppendAttachmentInfoPlaceholder(u);
		
/////////////////////////////////////////////////////////////////////////////////

	AttachEdges& AppendAttachmentInfoPlaceholder(leda::node u)
	{
		GetNode(u).m_attachments.push_back(AttachEdges());
		return GetNode(u).m_attachments.back();
	}
	
/////////////////////////////////////////////////////////////////////////////////

From : merge nodes
// Make sure that the joint knows its corresponding attachment node
SJDL::SetNodeInfo(pJoint, a1);


	// Add an empty SkelJointData element for the current joint
	SkelJointData* pJointData = m_jointDataList.InitJointData(pJoint);
	
	//
	
	pJointData->gsgnode = j;
	
	//
	
	pJointData->gsgedges.push_back(e); // assoc the joint to the new edge
	
	//
	
	SkelJoint* pJoint = GetCommonSkelJoint(bs0.m_pBranch, bs1.m_pBranch);
	std::list<leda::edge>& gedges = SJDL::GetJointData(pJoint)->gsgedges;
	std::list<leda::edge>::iterator it;


/////////////////////////////////////////////////////////////////////////////////

//! Data in the GSG associated with a skeletal graph joint
	struct SkelJointData 
	{
		leda::node gsgnode;
		std::list<leda::edge> gsgedges;

		SkelJointData() { }
		SkelJointData(const SkelJointData& d) 
			: gsgnode(d.gsgnode), gsgedges(d.gsgedges) { }
	};

	class SkelJointDataList : public std::list<SkelJointData> 
	{
	public:
		SkelJointData* InitJointData(SkelJoint* pJoint) 
		{ 
			push_back(SkelJointData()); 
			SkelJointData* p = &back();
			pJoint->pNodeData = p;
			return p;
		}
		static void SetNodeInfo(SkelJoint* pJoint, leda::node v)
		{
			((SkelJointData*) pJoint->pNodeData)->gsgnode = v;
		}
		static void AddEdgeInfo(SkelJoint* pJoint, leda::edge e)
		{
			((SkelJointData*) pJoint->pNodeData)->gsgedges.push_back(e);
		}
		static SkelJointData* GetJointData(SkelJoint* pJoint)
		{
			return ((SkelJointData*) pJoint->pNodeData);
		}
	};

	typedef SkelJointDataList SJDL;
		
	SkelJointDataList m_jointDataList;//! Data in the GSG associated with a skeletal graph joint
	struct SkelJointData 
	{
		leda::node gsgnode;
		std::list<leda::edge> gsgedges;

		SkelJointData() { }
		SkelJointData(const SkelJointData& d) 
			: gsgnode(d.gsgnode), gsgedges(d.gsgedges) { }
	};

	class SkelJointDataList : public std::list<SkelJointData> 
	{
	public:
		SkelJointData* InitJointData(SkelJoint* pJoint) 
		{ 
			push_back(SkelJointData()); 
			SkelJointData* p = &back();
			pJoint->pNodeData = p;
			return p;
		}
		static void SetNodeInfo(SkelJoint* pJoint, leda::node v)
		{
			((SkelJointData*) pJoint->pNodeData)->gsgnode = v;
		}
		static void AddEdgeInfo(SkelJoint* pJoint, leda::edge e)
		{
			((SkelJointData*) pJoint->pNodeData)->gsgedges.push_back(e);
		}
		static SkelJointData* GetJointData(SkelJoint* pJoint)
		{
			return ((SkelJointData*) pJoint->pNodeData);
		}
	};

	typedef SkelJointDataList SJDL;
		
	SkelJointDataList m_jointDataList;
	
/////////////////////////////////////////////////////////////////////////////////

	//SkelJoint* m_pAttachJoint; //<! joint at the break point
	//SkelBranch* m_pBranch0;    //<! first half of the broken branch
	//SkelBranch* m_pBranch1;    //<! second half of the broken branch
	
// Set data that is common to all edges. Here we add some info that
// is redundant but that it simplifies writting ASSERT conditions later
edgeData.m_pAttachJoint = pJoint;        
edgeData.m_pBranch0 = nonLigBranches[0];
edgeData.m_pBranch1 = nonLigBranches[1];
		
/////////////////////////////////////////////////////////////////////////////////

void GSG::FillMedialAxisGap(const BranchSegment& bs0, bool bIsFirstSeg0,
							const BranchSegment& bs1, bool bIsLastSeg1,
							const AttachEdges& attchs, CubicBezier& cb)
{ 
	POINT lp0, lp1, firstPt, lastPt;
	bool bHaveCtrlPoints01 = false; 
	bool bHaveCtrlPoints23 = false;

	SkelJoint* pJoint = GetCommonSkelJoint(bs0.m_pBranch, bs1.m_pBranch);
	
	ASSERT(!SJDL::GetJointData(pJoint)->gsgedges.empty());

	// The way more common case is to have a single ligature branch. However,
	// in theory we could have more than one. If we have only one we do... 
	if (SJDL::GetJointData(pJoint)->gsgedges.size() == 1)
	{
		// Use the joint to retrieve the attachment information
		leda::edge e = SJDL::GetJointData(pJoint)->gsgedges.front();
		const LigatureSegment& ls = GetEdge(e).m_ligature;
		
		// Get the line segment determined by the ligature endpoints
		// to use as reference for the inner ctrl points MAGNITUDES
		AssignPtCoord(lp0, ls[ls.First()].p);
		AssignPtCoord(lp1, ls[ls.Last()].p);

		// Find valid first tangent and set first two ctrl points
		if (bs0.Size() > 2) // we can compute first tangent
		{	
			AssignPtCoord(firstPt, bs0[bs0.Last() - 2].p);
			AssignPtCoord(cb.p0, bs0[bs0.Last()].p);

			int n = FindLineSegmentIntersection(firstPt, cb.p0, lp0, lp1, &cb.p1);

			//DBG_PRINT4(firstPt, cb.p0, lp0, lp1)
			//DBG_PRINT4(pJoint->fp.p, cb.p0, cb.p1, n)

			bHaveCtrlPoints01 = (n == 1 || n == 4);
		}

		// Find valid second tangent and set last two ctrl points
		if (bs1.Size() > 2) // we can compute second tangent
		{
			AssignPtCoord(lastPt,  bs1[bs1.First() + 2].p);
			AssignPtCoord(cb.p3, bs1[bs1.First()].p);

			int n = FindLineSegmentIntersection(cb.p3, lastPt, lp0, lp1, &cb.p2);

			//DBG_PRINT4(cb.p3, lastPt, lp0, lp1)
			//DBG_PRINT4(pJoint->fp.p, cb.p2, cb.p3, n)

			bHaveCtrlPoints23 = (n == 1 || n == 4);
		}
	}

	// If we don't have the first two ctrl point, use a heuristic to set them...
	if (!bHaveCtrlPoints01)
	{
		if (bs0.Size() > 0) // at least we have a valid endpoint
		{
			AssignPtCoord(cb.p0, bs0[bs0.Last()].p);
		} 
		else // the segment is empty. Choose UPPER middle point or FIRST point
		{
			if (bIsFirstSeg0)
				AssignPtCoord(cb.p0, bs0[bs0.BranchFirst()].p);
			else
				AssignPtCoord(cb.p0, bs0[bs0.BranchSize() / 2].p);
		}

		AssignPtCoord(cb.p1, pJoint->fp.p);

		//DBG_PRINT4(pJoint->fp.p, cb.p0, cb.p1, "from heuristic")
	}

	// If we don't have the last two ctrl point, use a heuristic to set them...
	if (!bHaveCtrlPoints23)
	{
		if (bs1.Size() > 0) // at least we have a valid endpoint
		{
			AssignPtCoord(cb.p3, bs1[bs1.First()].p);
		}
		else // the segment is empty. Choose LOWER middle point or LAST point
		{
			if (bIsLastSeg1)
				AssignPtCoord(cb.p3, bs1[bs1.BranchLast()].p);
			else
				AssignPtCoord(cb.p3, bs1[bs1.BranchSize() / 2].p); // do not add 1
		}

		AssignPtCoord(cb.p2, pJoint->fp.p);

		//DBG_PRINT4(pJoint->fp.p, cb.p2, cb.p3, "from heuristic")
	}
}

/////////////////////////////////////////////////////////////////////////////////

struct AttachEdges : public std::vector<leda::edge>
{
	void SetPosition(int pos)
	{
		for (unsigned int i = 0; i < size(); i++)
			(*this)[i] = pos;
	}

	void IncrementPosition(int pos);
};

/////////////////////////////////////////////////////////////////////////////////

if (i > 0)
			cumDist += fpl[i].p.distanceToPt(fpl[i - 1].p);
			
/////////////////////////////////////////////////////////////////////////////////

POINT CubicBezier::GetTangent(const double& u) const
{
	CubicBezierParams p(*this);

	double dx = p.a1 + u * (2 * p.a2 + u * 3 * p.a3);
	double dy = p.b1 + u * (2 * p.b2 + u * 3 * p.b3);

	return POINT(dx, dy);
}

/////////////////////////////////////////////////////////////////////////////////

void CubicBezierParams::Rasterize(double u, const XYCoord& endCoord, double stepsize, 
							      POINTS& pts, XYCoord& coord0)
{
	XYCoord coord1;
	POINT pt;

	int sz = pts.Size();

	// If not the first point, then cb(u) is already in the array
	if (sz > 0) 
		u += stepsize;

	do
	{
		GetCurvePoint(u, &pt.x, &pt.y);

		coord1 = pt; // rounds the point values

		if (sz == 0 || coord0 != coord1)
		{
			// check if we have two disconnected points
			if (sz > 1 && 
				(abs(coord1.x - coord0.x) > 1 || abs(coord1.y - coord0.y) > 1))
			{
				Rasterize(u - stepsize, coord1, stepsize / 2, pts, coord0);
			}
			else if (sz > 2 && 
				(abs(coord1.x - pts[sz - 2].x) > 1 || abs(coord1.y - pts[sz - 2].y) > 1))
			{
				pts[sz - 1] = POINT(coord1.x, coord1.y);
				coord0 = coord00;
			}
			else // first iteration enters here ALWAYS
			{
				pts.AddTail(POINT(coord1.x, coord1.y));
				coord0 = coord1;
			}
		}

		sz = pts.Size(); // update current size of the pts array
		u += stepsize;   // step to the next point

		ASSERT(u <= 3); // cannot be greater than 1 + max stepsize

	} while (coord1 != endCoord);
}

/////////////////////////////////////////////////////////////////////////////////

if (i > 0)
{
	DBG_PRINT2(pBGNode->m_shocks[i-1].pt, bp.pt)
}
		
/////////////////////////////////////////////////////////////////////////////////

const SkelBranch* GetGSGBranch() const
{
	ASSERT(!m_bIsBroken);
	return (m_pFixedBranch) ? m_pFixedBranch : m_segments.front().m_pBranch;
}
	
/////////////////////////////////////////////////////////////////////////////////

void GSG::RestoreAxisFunction(GSGNode& gnode)
{
	sg::FluxPointList& fpl = gnode.m_pFixedBranch->getFluxPoints();
	sg::BoundaryInfoList& bil = gnode.m_pFixedBranch->getBoundaryInfoList();
	BranchSegmentList::const_iterator it0, it1;
	unsigned int i, j, maxGapSize, maxVectSize;
	//sg::FluxPointList gapFluxPts;
	POINTS gapPts;
	CubicBezier cb;
	sg::FluxPoint fp;
	int k;
	
	ASSERT(gnode.m_segments.size() >= 2);

	// Copy flux points from all branch segments. Reserve enough space 
	// for segments and gaps by counting ALL branch points.
	maxVectSize = gnode.m_segments.TotalBranchSize() + 4 * gnode.m_segments.size();
	fpl.reserve(maxVectSize);

	const unsigned int M = gnode.m_segments.size() - 2;
	it1 = gnode.m_segments.begin();
	i = 0;

	for (it0 = it1++; it0 != gnode.m_segments.end(); it0++, i++)
	{
		for (j = it0->First(); j <= it0->Last(); j++) 
		{
			fpl.push_back((*it0)[j]);
			bil.push_back((*it0)(j));
		}

		if (it1 != gnode.m_segments.end())
		{	
			FillMedialAxisGap(*it0, i == 0, *it1, i == M, cb);
			
			// Save the curve so that we can look at it later
			gnode.m_axisFunction.AddTail(cb);

			// Find an approximation to the size of the gap
			maxGapSize = it0->RightMarginSize() + it1->LeftMarginSize() + 2;

			// Rasterize the curve that "fills" the gap
			CubicBezierParams cbp(cb);
			gapPts = cbp.Rasterize(maxGapSize * 2);

			// The radius of the joint is a good upper bound to init ALL dist values
			fp.dist = GetCommonSkelJoint(it0->m_pBranch, it1->m_pBranch)->fp.dist;

			// If ftp is empty, its last point should be the same than the gap's first
			ASSERT(fpl.empty() || ArePtsEqual(fpl.back().p, gapPts[0]));

			// Ignore gap's first point if already in the array
			k = (fpl.empty()) ? 0 : 1;

			//gapFluxPts.resize(gapPts.GetSize() - k);

			// Add the gap points to the new "fixed" branch.
			for (; k < gapPts.GetSize(); k++)
			{
				AssignPtCoord(fp.p, gapPts[k]);
				fpl.push_back(fp);
			}
			
			// We can know assign the boundary point info and also the true radius
			// values to each skeleton point in the gap
			//m_pSkeletalGraph->AssignBoundaryPoints(boneGap.fpl, boneGap.bil);
			//m_pSkeletalGraph->AssignRadiusValues(boneGap.bil, boneGap.fpl);

			it1++;
		}
	}

	WARNING(fpl.size() > maxVectSize, "Consider increasing init vector size");
}

/////////////////////////////////////////////////////////////////////////////////

	DBG_LINE
	DBG_PRINT5(u, stepsize, pt, coord1.x, coord1.y)
				
	DBG_LINE
	DBG_PRINT3(pt, endCoord.x, endCoord.y)
	
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Returns an array with all the points on the curve between input points 
	nFirstPtIdx and nFirstPtIdx + 1. The gap is filled with up to nMaxSize
	unique points.
*/
POINTS PolyBezierApprox::FillPointGap(int nFirstPtIdx, int nMaxSize)
{
	ASSERT(nFirstPtIdx - 1 < m_points.GetSize());

	double u0 = GetCurveParam(nFirstPtIdx);
	double u1 = GetCurveParam(nFirstPtIdx + 1);

	const CubicBezier& seg0 = GetPointSegment(nFirstPtIdx);

	// Both gap endpoints should belong to the same curve segment
	ASSERT(seg0 == GetPointSegment(nFirstPtIdx + 1));

	POINTS gapPts(0, nMaxSize);
	POINT pt;
	CubicBezierParams cbp(seg0);
	double stepsize = (u1 - u0) / (nMaxSize - 1);
	int i = 0;
	
	for (double u = u0; u <= u1; u += stepsize)
	{
		cbp.GetCurvePoint(u, &pt.x, &pt.y);

		if (i == 0 || gapPts[i - 1] != pt)
		{
			WARNING(i > 0 && pt.L2(gapPts[i - 1]) >= 1.5, 
				"Disconnected skeletal point");

			gapPts.AddTail(pt);
			i++;
		}
	}

	return gapPts;
}

/////////////////////////////////////////////////////////////////////////////////

	// First, set valid deltas for computing the tangents
	SkelPtIndex delta0 = (bs0.Size() > 2) ? 2 : 1;
	SkelPtIndex delta1 = (bs1.Size() > 2) ? 2 : 1;

	// Get two point before each endpoints defining the gap
	AssignPtCoord(firstPt, bs0[bs0.Last() - delta0].p);
	AssignPtCoord(lastPt,  bs1[bs1.First() + delta1].p);

	// Make the gap endpoint be the cubic Bezier curve endpoint
	AssignPtCoord(cb.p0, bs0[bs0.Last()].p);
	AssignPtCoord(cb.p3, bs1[bs1.First()].p);

	// Find the two inner control points of the cubic Bezier curve
	int a = FindLineSegmentIntersection(firstPt, cb.p0, lp0, lp1, &cb.p1);
	int b = FindLineSegmentIntersection(cb.p3, lastPt, lp0, lp1, &cb.p2);

	WARNING(a != 3 || b != 3, "There is a strange intersection point");

	// Set a valid point for this strange case. Use the joint as an ok approx
	if (!a || !b) 
	{
		AssignPtCoord(cb.p1, pJoint->fp.p);
		AssignPtCoord(cb.p2, pJoint->fp.p);
	}
	
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 
*/
void GSG::RestoreAxisFunction(GSGNode& gnode)
{
	const unsigned int numPts = gnode.m_segments.Size();
	POINTS xypts(numPts), gapPts;
	BranchSegmentList::const_iterator it0, it1;
	unsigned int j;
	int i, k, gapMaxSize;

	// Copy points from all branch segments
	it0 = gnode.m_segments.begin();
	i = 0;

	for (; it0 != gnode.m_segments.end(); it0++)
		for (j = it0->First(); j <= it0->Last(); j++, i++) 
			AssignPtCoord(xypts[i], (*it0)[j].p);
	
	ASSERT(i == numPts); // no empty slots in the array

	// Approx points
	PolyBezierApprox polyBA(numPts / 4.0, 2);	
	polyBA.Fit(xypts);

	// Save the cubic Bezier as the axis function of the node
	gnode.m_axisFunction.Resize(polyBA.m_knots.GetSize());

	for (i = 0; i < polyBA.m_knots.GetSize(); i++)
		gnode.m_axisFunction[i] = polyBA.m_knots[i].seg;

	// Copy known points and new points into fixed branch info
	sg::FluxPointList& fpl = gnode.m_pFixedBranch->flux_points;
	sg::FluxPoint fp;
	
	it1 = gnode.m_segments.begin();
	it0 = it1++;
	i = 0; // indexes over input point for curve approximation

	fpl.reserve(gnode.m_segments.TotalBranchSize());

	for (; it0 != gnode.m_segments.end(); it0++)
	{
		for (j = it0->First(); j <= it0->Last(); j++, i++)
			fpl.push_back((*it0)[j]);

		// If we are not at the last segment, we know that there is a large
		// "gap" between points k and k+1, so we use the curve to fill it.
		if (it1 != gnode.m_segments.end())
		{
			gapMaxSize = it0->RightMarginSize() + it1->LeftMarginSize();

			if (gapMaxSize > 0)
			{
				gapPts = polyBA.FillPointGap(i, gapMaxSize);

				// Add the gap points
				for (k = 0; k < gapPts.GetSize(); k++)
				{
					AssignPtCoord(fp.p, gapPts[k]);
					fpl.push_back(fp);
				}

				it1++;
			}
		}
	}
}


/////////////////////////////////////////////////////////////////////////////////

	leda::node a, b, v, w;
	leda::edge e, f;
	double dSaliencyU, dSaliencyW;

	ASSERT(m_genSkelGraph.GetNode(u).m_type == GSG_BRANCH);
	ASSERT(indeg(u) <= 1);
	ASSERT(outdeg(u) <= 2);

	a = m_genSkelGraph.GetNode(u).m_mappingNode;
	
	forall_out_edges(e, u)
	{
		v = target(e); // v is either a junction or an attachment node

		if (m_genSkelGraph.GetNode(v).m_type == GSG_JUNCTION)
		{
			forall_in_edges(f, v)
			{
				w = source(f);
				ASSERT(m_genSkelGraph.GetNode(w).m_type == GSG_BRANCH);

				b = m_genSkelGraph.GetNode(w).m_mappingNode;
				dSaliencyW = m_pBoneGraph->GetBGNode(b)->m_dSaliency;

				if (u != w && dSaliencyU > dSaliencyW)
					AddBGEdge(a, b, m_genSkelGraph.GetEdge(f));

				WARNING(u != w && dSaliencyU == dSaliencyW, "DO SOMETHING!");
			}
		}
	}
	
/////////////////////////////////////////////////////////////////////////////////


	forall_nodes(v, m_genSkelGraph)
	{
		if (m_genSkelGraph.GetNode(v).m_type == GSG_BRANCH)
			AddBGEdgesFromGSGNode(v);
	}
	
/////////////////////////////////////////////////////////////////////////////////
dSaliencyU = m_pBoneGraph->GetBGNode(a)->m_dSaliency;

forall_out_edges(e, u)
	{
		v = target(e); // v is either a junction or an attachment node

		if (m_genSkelGraph.GetNode(v).m_type == GSG_JUNCTION)
		{
			forall_in_edges(f, v)
			{
				w = source(f);
				ASSERT(m_genSkelGraph.GetNode(w).m_type == GSG_BRANCH);

				b = m_genSkelGraph.GetNode(w).m_mappingNode;
				dSaliencyW = m_pBoneGraph->GetBGNode(b)->m_dSaliency;

				if (u != w && dSaliencyU > dSaliencyW)
					AddBGEdge(a, b, m_genSkelGraph.GetEdge(f));

				WARNING(u != w && dSaliencyU == dSaliencyW, "DO SOMETHING!");
			}
		}
	}
/////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////
// Typedefs for pointers to nodes and edges in a DDSGrpah

//! Natural name for a branch pointer in a DDSGraph
typedef sg::DDSEdge* BranchPtr;

//! Natural name for a const branch pointer in a DDSGraph
typedef const sg::DDSEdge* BranchConstPtr;

//! Natural name for an endpoint pointer in a DDSGraph
typedef sg::DDSNode* EndptPtr;

//! Natural name for a const endpoint pointer in a DDSGraph
typedef const sg::DDSNode* EndptConstPtr;

//! Natural name for a joint pointer in a DDSGraph
typedef sg::DDSNode* JointPtr;

//! Natural name for a const joint pointer in a DDSGraph
typedef const sg::DDSNode* JointConstPtr;

/////////////////////////////////////////////////////////////////////////////////

	SkelJoint* pJoint;
	std::vector<SkelBranch*> nonLigBranches;
	std::list<LigatureSegment> ligSegs;
	NodeType type;


	forall_joints(pJoint, m_pSkeletalGraph->getNodes())
	{
		std::cout << "\nJoint: " << pJoint->fp << std::endl;

		type = LabelJoint(pJoint, nonLigBranches, ligSegs);

		if (type == JUNCTION)
			std::cout << "\tis a JUNCTION" << std::endl;
		else
		{
			std::cout << "\tis an ATTACHMENT" << std::endl;

			std::list<LigatureSegment>::iterator it;

			for (it = ligSegs.begin(); it != ligSegs.end(); it++)
			{
				//const sg::BoundaryInfoList& bil = it->m_pBranch->getBoundaryInfoList();

				//std::cout << "\t\t" << bil[0] << ", " << bil[bil.size() - 1] << std::endl;

				std::cout << "\t\t" << it->m_pBranch->n1->fp << ", " << 
					it->m_pBranch->n2->fp << std::endl;
			}
		}
	}

/////////////////////////////////////////////////////////////////////////////////

// Add dependecies between joints based on the labels of their
	// adjacent joints
	forall_joints(pJoint, m_pSkeletalGraph->getNodes())
	{
		const DGNodePtr& ptrNode = m_dependencyGraph.GetNode(pJoint);

		for (it = ptrNode->begin(); it != ptrNode->end(); it++)
		{
			pAdjNode = (it->pBranch->n1 != pJoint) ? it->pBranch->n1:it->pBranch->n2;

			if  (m_dependencyGraph.GetNodeType(pAdjNode) == ATTACHMENT)
				m_dependencyGraph.NewEdge(pAdjNode, pJoint);
		}
	}
	
/////////////////////////////////////////////////////////////////////////////////

typedef std::list<LigatureSegment>::iterator iterator;
		iterator begin() { return ligSegs.begin(); }
		iterator end()   { return ligSegs.end(); }

/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief 
*/
void GSG::CreateDependencyGraph()
{
	for (each join)
	{
		CreateNode();
		LabelJoint();
	}

	for (each join)
	{
		for (each insident branch)
			if (other endpoint is a Junction)
				AddDependecyFromJointToJunction();
	}
}

/////////////////////////////////////////////////////////////////////////////////

void GSG::LabelJoint(SkelJoint* pJoint)
{
	int bndryLen = (int)m_pSkeletalGraph->GetBoundarySize();
	ASSERT(bndryLen > 0);

	BoundaryInterval bi1, bi2;
	SkelBranch* pBranch;
	int n;

	std::cout << "Joint: " << pJoint->fp << std::endl;

	forall_branches(pBranch, pJoint->edges)
	{
		const sg::BoundaryInfoList& bil = pBranch->getBoundaryInfoList();

		n = bil.size();
		ASSERT(n > 0);

		bi1.Set(bndryLen, bil[0].first.index, bil[n - 1].first.index);
		bi2.Set(bndryLen, bil[0].second.index, bil[n - 1].second.index);

		std::cout << "\t" << bi1 << ", " << bi2 << std::endl;
	}

	TBBIntervalList intervals(m_pSkeletalGraph);

	intervals.FindAllIntervals(pJoint->edges.begin(), pJoint->edges.end());

	TBBIntervalList::iterator it;
	int nIncluded;

	int nFreeBranches = pJoint->degree() - 2;

	std::cout << "All intervals: " << std::endl;

	for (it = intervals.begin(); it != intervals.end(); it++)
	{
		std::cout << "\t" << it->firstSideInt << ", " << it->secondSideInt << std::endl;

		nIncluded = 0;

		forall_branches(pBranch, pJoint->edges)
			if (pBranch != it->pBranch0 && pBranch != it->pBranch1 && it->Includes(pBranch))
				nIncluded++;
		
		if (nIncluded == nFreeBranches)
			std::cout << "\t\tIt's an ATTACHMENT POINT" << std::endl;
		else if (nIncluded == 0)
			std::cout << "\t\tIt's an JUNCTION POINT" << std::endl;
		else
			std::cout << "\t\tIt's a WEIRD POINT" << std::endl;
	}
}

/////////////////////////////////////////////////////////////////////////////////

void SkeletalGraph::SetBoundaryPointsUsingNNSearch(int nSmoothIter /*= 0*/)
{
	ShapeBoundary c = GetShapeBoundary(m_pDDSGraph);

	if (c == NULL)
	{
		std::cerr << "Unknown curve type" << std::endl;
		return;
	}

	unsigned int nSegments = c->segments.size();
	BoundaryPointFinder bpf(nSegments);
	std::vector<sg::Point> boundaryPts(nSegments);

	for (unsigned int i = 0; i < nSegments; i++)
	{
		const Point& pt = static_cast<LineSeg*>(c->segments[i])->startPt;
		//bpf.AddBoundaryPoint(pt.x, pt.y);
		boundaryPts[i].set(pt.x, pt.y);
	}

	ASSERT(nSmoothIter >= 0);

	bpf.AddBoundaryPoints(boundaryPts, nSmoothIter);

	DDSEdgeVect& edges = m_pDDSGraph->getEdges();
	DDSEdgeVect::iterator edgeIt;

	for(edgeIt = edges.begin(); edgeIt != edges.end(); edgeIt++)
		bpf.AssignBoundaryPoints((*edgeIt)->getFluxPoints(), (*edgeIt)->getBoundaryInfoList());
}

/////////////////////////////////////////////////////////////////////////////////

	A ligature branch should also meet the "within-boundary" criterium defined 
	by the 2 non-ligature branches. That is, all their associated boundary points
	must be included in one side of the interval defined be the 2 non-ligature 
	branches.
	
/////////////////////////////////////////////////////////////////////////////////

	// If needed, swap the sides of one (any) branch so that sides agree 
	// between both branches. 
	/*if (bSwapSides)
	{
		extPt1.SwapSides();
		intPt1.SwapSides();
	}*/
	BoundaryInterval test(bndryLength, extPt0.first.index, intPt1.first.index);

	DBG_PRINT1(b0i0); DBG_PRINT_NEWLINE
	DBG_PRINT1(b0iN); DBG_PRINT_NEWLINE
	DBG_PRINT1(b1i0); DBG_PRINT_NEWLINE
	DBG_PRINT1(b1iN); DBG_PRINT_NEWLINE

	DBG_MSG1("Testing:");

	DBG_PRINT1(extPt0); DBG_PRINT_NEWLINE
	DBG_PRINT1(intPt0); DBG_PRINT_NEWLINE
	DBG_PRINT1(extPt1); DBG_PRINT_NEWLINE
	DBG_PRINT1(intPt1); DBG_PRINT_NEWLINE
	DBG_PRINT1(test); DBG_PRINT_NEWLINE

	bool incExtPt0 = test.Includes(extPt0.second.index);
	bool incIntPt1 = test.Includes(intPt1.second.index);

	DBG_PRINT1(incExtPt0); DBG_PRINT_NEWLINE
	DBG_PRINT1(incIntPt1); DBG_PRINT_NEWLINE

	if ((incExtPt0 && !incIntPt1) || (!incExtPt0 && incIntPt1) ||
		(extPt0.second.index == intPt1.first.index))
	{
		extPt1.SwapSides();
		intPt1.SwapSides();
		DBG_LINE
		DBG_PRINT1(extPt0); DBG_PRINT_NEWLINE
		DBG_PRINT1(intPt0); DBG_PRINT_NEWLINE
		DBG_PRINT1(extPt1); DBG_PRINT_NEWLINE
		DBG_PRINT1(intPt1); DBG_PRINT_NEWLINE
	}

	// Set the interval defined by the two branches
	firstSideInt.Set(bndryLength, extPt0.first.index, extPt1.first.index);
	secondSideInt.Set(bndryLength, extPt0.second.index, extPt1.second.index);

	DBG_PRINT1(firstSideInt); DBG_PRINT_NEWLINE
	DBG_PRINT1(secondSideInt); DBG_PRINT_NEWLINE

	// Make sure that the first interval includes the internal points
	if (firstSideInt.Includes(intPt0.second.index))
	{
		ASSERT(firstSideInt.Includes(intPt1.second.index));
		firstSideInt.Swap();
		DBG_LINE
		DBG_PRINT1(firstSideInt); DBG_PRINT_NEWLINE
		DBG_PRINT1(secondSideInt); DBG_PRINT_NEWLINE
	}

	ASSERT(firstSideInt.Includes(intPt0.first.index) && 
		   firstSideInt.Includes(intPt1.first.index));

	// Make sure that the second interval includes the internal points
	if (secondSideInt.Includes(intPt0.first.index))
	{
		ASSERT(secondSideInt.Includes(intPt1.first.index));
		secondSideInt.Swap();
	}

	ASSERT(secondSideInt.Includes(intPt0.second.index) && 
		   secondSideInt.Includes(intPt1.second.index));
/////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Initializes array of nearest neighbor lists
*/
void ViewClustering::InitializeConnections()
{
	int i, j;

	m_nnla.clear();
	m_nnla.resize(m_numShapes);

	for (i = 0; i < m_numShapes; i++)
		m_nnla[i].SetMaxSize(m_maxNNCount);

	for (i = 1; i <= m_numShapes; i++)
		for (j = 1; j <= m_numShapes; j++)
			if (i != j)
				m_nnla[i-1].Push(m_simMat(i,j), j);

	// Check how things look
	//for (i = 0; i < m_numShapes; i++)
	//	cout << m_nnla[i] << endl;	
}

void ViewClustering::FindPrototypes()
{
	int i, j, numEdges;
	double sim;

	// 1. Create Graph
	edge* edges = new edge[m_numShapes * m_maxNNCount];

	for (i = 0, numEdges = 0; i < m_numShapes; i++)
	{
		while (m_nnla[i].PopMin(sim, j))
		{
			edges[numEdges].a = (int) m_dagIds(1, i + 1); //i;
			edges[numEdges].b = (int) m_dagIds(1, j); //j;
			edges[numEdges].w = (1 - sim) * 255; // ie, like pixel intensity diff
			numEdges++;
		}
	}

	ASSERT(numEdges <= m_numShapes * m_maxNNCount);

	// 2. Cluster graph
	cout << "\t- clustering graph with " << m_numShapes << " nodes and " 
		<< numEdges << " edges (tau = " << m_groupSizeTau << ")..." << endl;

	universe* u = segment_graph(m_numShapes, numEdges, edges, m_groupSizeTau);

	// 3. Find prototypes
	cout << "\t- finding prototypes" << endl;
	int group, numSets = u->num_sets();
	std::vector<NearestNeighborsList> prots(numSets);
	double cumDist, groupSize;

	// Init. the priority queues to a size of 1 (ie, a prototype per group)
	for (i = 0; i < numSets; i++)
		prots[i].SetMaxSize(1);

	// Compute average distance betweeen each shape and all the 
	// other shapes in the same group
	for (i = 0; i < m_numShapes; i++)
	{
		group = u->find(i);
		groupSize = u->size(group);

		ASSERT(group >= 0 && group < numSets);
		ASSERT(groupSize > 0 && groupSize <= m_numShapes);

		cumDist = 0;

		for (j = 0; j < m_numShapes; j++)
			if (i != j && u->find(j) == group)
				cumDist += m_simMat(i + 1, j + 1);

		prots[group].Push(cumDist / groupSize, i);

		cout << '.' << flush;
	}

	// Print info/stats
	cout << "Number of sets: " << numSets << endl;
	cout << "Prototypes: " << flush;

	for (i = 0; i < numSets; i++)
		cout << prots[i] << endl;

	delete[] edges;
	delete u;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////	
	for (i = 0; i < N; i++)
	{
		while (m_nnla[i].PopMin(sim, idx))
		{
			edges[num].a = (int) dagIds(1, i + 1);
			edges[num].b = (int) dagIds(1, idx);
			edges[num].w = (1 - sim) * 255; // ie, like pixel intensity diff
			num++;
		}
	}
		
////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Copy all skeleton points associated with the bone
	for (i = 0, cumAxisDist = 0, gapIdx = 0, it = bsl.begin(); it != bsl.end(); it++, gapIdx++)
	{
		const BranchSegment& bs = *it;
		const sg::FluxPointList& fpl = bs.pBranch->getFluxPoints();
		const sg::BoundaryInfoList& bil = bs.pBranch->getBoundaryInfoList();

		for (j = bs.First(); j <= bs.Last(); j++, i++) 
		{ 
			const sg::FluxPoint& fp = bs[j]; 
			const sg::BoundaryInfo& bi = bs(j);
			ShockPoint& bp = pBGNode->m_shocks[i];

			bp.pt.Set(fp.p.x, fp.p.y);
			bp.radius = fabs(fp.dist);
			bp.bndryPt1.Set(bi.first.pt.x, bi.first.pt.y);
			bp.bndryPt2.Set(bi.second.pt.x, bi.second.pt.y);

			if (i > 0)
				cumAxisDist += bp.pt.L2(xydata[i - 1]);

			xydata[i] = bp.pt;
			rdata[i].Set(cumAxisDist, bp.radius);
		}

		for (j = 0, gapPtsCount = bga[gapIdx].fpl.size(); j < gapPtsCount; j++)
		{
		}
	}
	
////////////////////////////////////////////////////////////////////////////////////////////////////////

		//! Returns the cumAxisDist while accounting for the 'inverted' flag
		double GetCumulativeAxisDistance(SkelPtIndex i) const
		{
			if (inverted)
			{
				double totalCumDist = pBranch->getBoundaryInfo(pBranch->size() - 1).cumAxisDist;
				return totalCumDist - pBranch->getBoundaryInfo(pBranch->size() - i).cumAxisDist;
			}
			else
				return pBranch->getBoundaryInfo(i).cumAxisDist;
		}
		
////////////////////////////////////////////////////////////////////////////////////////////////////////

		first = (it->inverted) ? (int)fpl.size()-1:0;
		last  = (it->inverted) ? -1:(int)fpl.size();
		inc   = (it->inverted) ? -1:1;

		distOffset = (it->inverted) ? bil[bil.size()-1].cumAxisDist:0;

		//DBG_PRINT2(it->inverted, distOffset)

		for (j = first; j != last; i++, j += inc)
		{
			xydata[i].Set(fpl[j].p.x, fpl[j].p.y);

			cumDist = fabs(bil[j].cumAxisDist - distOffset);

			rdata[i].Set(cumDist, fabs(fpl[j].dist));

			//DBG_PRINT2(cumDist, fabs(fpl[j].dist))
		}

////////////////////////////////////////////////////////////////////////////////////////////////////////

	const ShockInfo& s0 = pNode->m_shocks[0];
	const ShockInfo& sN = pNode->m_shocks[size - 1];
	double x1, y1, m;

	if (s0.xcoord != sN.xcoord)
		m = (s0.ycoord - sN.ycoord) / (s0.xcoord - sN.xcoord);
	else
		m = 1;

////////////////////////////////////////////////////////////////////////////////////////////////////////

bool IsFracturedBone(BoneIndex i)
{
	return m_branchSegments[i].size() > 1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
	
			/*for (ligIt = lsl.begin(); ligIt != lsl.end(); ligIt++)
			{
				bFound = BoneLookUp(ligIt->pBranch, &boneIdx);

				if (!bFound)
					std::cout << "\nNot found: \t(branch:" << ligIt->pBranch->n1->fp.p 
						<< ", " << ligIt->pBranch->n2->fp.p
						<< ", size:" << ligIt->pBranch->size() 
						<< ", first:" << ligIt->first 
						<< ", last:" << ligIt->last << ")" << std::endl;

				ASSERT(bFound);

				m_pBoneGraph->NewEdge(m_bgnodes[i], m_bgnodes[boneIdx]);
			}*/
			
////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	sg::DDSNode* joints[2];

	for (i = 0; i < m_branchSegments.size(); i++)
	{
		GetBoneEndpoints(i, &joints[0], &joints[1]);

		for (j = 0; j < 2; j++)
		{
			const DDSEdgeVect& skelEdges = joints[j].edges;


		}
	}
	
////////////////////////////////////////////////////////////////////////////////////////////////////////

if (m_pDDSGraph)
{
	pDDSGraph->computeFluxPointBoundaryInfo(); // This is Pavel's stuff. Don't needed it anymore

	ApproxSkeletonWithLines(m_compParams.dMinLinearError, m_compParams.dMaxLineSegments);
	ApproxSkeletonWithCubicBeziers(m_compParams.dMinBezierError, m_compParams.dMaxBezierSegments);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Creates a shock graph from an image file
*/
bool ShockGraph::Create(const char* szFileName, const SGParams& sgparams, 
                        const SkeletalGraph::SkelParams& skelparams)
{
	Clear(); //make sure the current shock graph is empty

	m_compParams = sgparams;
	
	SetDAGLbl(szFileName);

	m_pSkeleton = new SkeletalGraph();

	m_pSkeleton->Create(szFileName, skelparams);

	return ComputeSGFromDDSGraph(m_pSkeleton->GetDDSGraph());
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

void ShowShockGraph(const DAG* pDag)
{
	const ShockGraph* pSG = dynamic_cast<const ShockGraph*>(pDag);

	if (pSG)
	{
		ShockGraph dummy;
		ShockGraphView sgview;
		sgview.Create(pSG, &dummy);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

	DAGPtr ptrCpDag1 = pDag1->CreateObject();
	DAGPtr ptrCpDag2 = pDag2->CreateObject();

	ShowGraph(*ptrCpDag1 = *pDag1);
	ShowGraph(*ptrCpDag2 = *pDag2);
	
////////////////////////////////////////////////////////////////////////////////////////////////////////

/*!
	@brief Draws the infor of each node and edge in the DAG on top of the
	skeleton graph information displayed by DrawSkeletonGraphInfo()
*/
void DAGMatchWnd::DrawDAGInfo() const
{
	const SGNode* pNode;
	leda_node v;
	int i, j, size;
	const SGInfo* info[] = {GetSGInfo1(), GetSGInfo2()};
	double x1, y1, m;
	char cEndPt;
	leda::color c;
	int t, colorIdx;

	// define possible pixel colors
	leda_color color[] = {leda_black, leda_red, leda_brown, leda_blue, leda_violet, leda_grey3};

	m_pWnd->start_buffering();

	m_pWnd->clear(leda_white);
	
	for (i = 0; i < 2; i++)
	{
		FILE* fp = fopen(info[i]->pSG->GetDAGLbl(), "r");
		
		if (fp != NULL)
		{
			fclose(fp);
		
			cimg_library::CImg<float> shapeImg(info[i]->pSG->GetDAGLbl());

			if (shapeImg.dimy() > 0 && shapeImg.dimx() > 0)//(!shapeImg.is_empty())
			{
				int r,c;
				
				for (r = 0; r < shapeImg.dimy(); r++)
					for (c = 0; c < shapeImg.dimx(); c++) 
						if (shapeImg(c,r) == 0)
							m_pWnd->draw_pixel(ReMapPt(leda_point(c, r), info[i]), leda_grey1);
			}
		}
    	
    	DrawSkeletonGraphInfo(info[i]);

		colorIdx = 0;

		forall_nodes(v, *(info[i]->pSG))
		{
			pNode = info[i]->pSG->GetSGNode(v);
			cEndPt = pNode->GetEndPt();

			t = pNode->m_nType;

			if (t == SHOCK_1 || t == SHOCK_2 || t == SHOCK_3 || t == SHOCK_4)
			{
					size = pNode->m_shocks.GetSize();

					if (size == 0)
					{
						//WARNING(pNode->m_shocks.GetSize() == 0, "Node has no shocks");
						continue;
					}

					const ShockInfo& s0 = pNode->m_shocks[0];
					const ShockInfo& sN = pNode->m_shocks[size - 1];

					if (s0.xcoord != sN.xcoord)
						m = (s0.ycoord - sN.ycoord) / (s0.xcoord - sN.xcoord);
					else
						m = 1;

					for (j = 0; j < size; j++)
					{
						const ShockInfo& s1 = pNode->m_shocks[j];

						x1 = s1.xcoord - info[i]->delta_x;
						y1 = (info[i]->reflex_y - s1.ycoord) - info[i]->delta_y;
						c = color[colorIdx % (sizeof(color) / sizeof(color[0]))];

						m_pWnd->draw_pixel(x1, y1, c);

						if (m_bShowLabels)
						{
							if ((cEndPt == 'a' && j == 0) ||
								(cEndPt == 'b' && j == 0) ||
								(cEndPt != 'a' && cEndPt != 'b' && j == size / 2))
							{
								/*if (m < 0 || m == 1)
									x1 += 4;
								else if (m > 0)
									x1 -= 12;*/
								
								if (m_bShowNodeType)
									m_pWnd->draw_text(x1, y1, (const char*)info[i]->pSG->GetNodeLbl(v),
										c/*leda_color(255, 0, 0)*/);
								else
									m_pWnd->draw_text(x1, y1, (const char*)((const DAG*)(const ShockGraph*)info[i]->pSG)->GetNodeLbl(v),
										c/*leda_color(255, 0, 0)*/);									
							}
						}
					}

					colorIdx++;

					/*for (j = 0; j < size - 1; j++)
					{
						const ShockInfo& s1 = pNode->m_shocks[j];
						const ShockInfo& s2 = pNode->m_shocks[j + 1];

						x1 = s1.xcoord - info[i]->delta_x;
						y1 = (info[i]->reflex_y - s1.ycoord) - info[i]->delta_y;
						x2 = s2.xcoord - info[i]->delta_x;
						y2 = (info[i]->reflex_y - s2.ycoord) - info[i]->delta_y;

						m_pWnd->draw_segment(x1, y1, x2, y2);

						if (j == size / 2)
							m_pWnd->draw_text(x1, y1, info[i]->pSG->GetNodeLbl(v), leda_color(255, 0, 0));
					}*/
			}
			else if (t != ROOT) // There's no info in the root
				cerr << "\nERROR: Unknown node type." << endl;
		}
	}

	m_pWnd->flush_buffer();
	m_pWnd->stop_buffering();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	struct SGInfo
	{
		ShockGraph* pSG;
		double delta_x;
		double delta_y;
		double reflex_y;

		// It clones p into pSG. i.e., it makes a copy of *p
		SGInfo(const ShockGraph* p, double dx, double dy, double ry) /*: pSG(*p)*/
		{
			pSG = new ShockGraph();
			*pSG = *p;
			
			// Let's steal the skeleton from p (yes, this IS nasty)
			pSG->SetSkeleton((BlumSkeleton*)p->GetSkeleton());
			((DAG*)p)->SetSkeleton(NULL);

			delta_x = dx;
			delta_y = dy;
			reflex_y = ry;
		}
		~SGInfo() { delete pSG; }
	};
	
////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	const sg::FluxPoint& fp0 = bs0[first0];
	u0 = cbp.GetClosestPointParam(fp0.p.x, fp0.p.y);

	const sg::FluxPoint& fpN = bs1[last1];
	uN = cbp.GetClosestPointParam(fpN.p.x, fpN.p.y);

inline double GetClosestPointParam(const double& x, const double& y) const;

/*!
	@brief Finds the parameter 'u' correspoinding to the point in the curve
	that is closest to point (x,y). The search is done by discretizing the
	curve in 'n' equal segments.
*/
double CubicBezierParams::GetClosestPointParam(const double& x0, const double& y0, int n) const
{
	double x, y, dx, dy, u, u1, stepsize, dist2, minDist2;

	stepsize = 2.0 / n; // remember, we go from -1 to 1 => length 2

	for (u = -1; u <= 1.01; u += stepsize)
	{
		GetCurvePoint(u, &x, &y);

		dx = x - x0;
		dy = y - y0;
		dist2 = dx * dx + dy * dy;

		// Find minimum
		if (u == -1 || dist2 < minDist2)
		{
			u1 = u;
			minDist2 = dist2;
			if (minDist2 == 0) break; // we found it already
		}
	}

	if (u1 > 1) u1 = 1; // make sure tha we have a valid parameter

	return u1;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

// Add gap information by rasterizing the curve
		BoneGap& boneGap = bga[gapIdx];

		// There should be a joint point common to both branches
		ASSERT((*it0)[it0->BranchLast()].p == (*it1)[it1->BranchFirst()].p);

		// Get the interval that defines the gap on each branch
		first0 = it0->Last();
		last0  = it0->BranchLast();
		first0 = it1->BranchFirst() + 1; //+1 ignores duplicated 'joint' point
		last1  = it1->First();

		N = last0 - first0 + last1 + 1;  //would be +2 if we didn't ignore a point

		sg::FluxPoint& fp0 = (*it0)[first0];
		u0 = GetClosestPointParam(fp0.x, fp0.y);

		sg::FluxPoint& fpN = (*it1)[last1];
		uN = GetClosestPointParam(fpN.x, fpN.y);

		stepsize = (uN - u0) / N;
		boneGap.fpl.resize(N);

		// We rasterize the curve for the
		// We need some radius upper bound to help the NN search later so
		// we assign the one in the current gap points.
		k = 0;
		u = u0;

		for (j = first0; j <= last0; j++, u += stepsize, k++)
		{
			sg::FluxPoint& fp = boneGap.fpl[k];

			fp.dist = (*it0)[j].dist; 
			cbp.GetCurvePoint(u, &fp.x, &fp.y);
		}

		for (j = 0; j <= last1; j++, u += stepsize, k++)
		{
			ASSERT(u <= 1);

			sg::FluxPoint& fp = boneGap.fpl[k];

			fp.dist = (*it1)[j].dist; 
			cbp.GetCurvePoint(u, &fp.x, &fp.y);
		}

		// We can know assign the boundary point info and also the true radius
		// values to each skeleton point in the gap
		m_pBoundaryPointFinder->AssignBoundaryPoints(boneGap.fpl, boneGap.bil);
		m_pBoundaryPointFinder->AssignRadiusValues(boneGap.bil, boneGap.fpl);
		
////////////////////////////////////////////////////////////////////////////////////////////////////////

		/*if (branchSegIt->first == ligSeg.first)
			branchSegIt->first = ligSeg.last + 1;
		else
			branchSegIt->last = ligSeg.first - 1;*/
			
////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BoneGraphConstructor::LigamentLookUp(sg::DDSNode* pJoint, sg::DDSEdge* pBranch,  
                                          SkelPtIndex first, SkelPtIndex last, LigamentIndex* pIdx)
{
	LigamentIndex& i = *pIdx;
	LigatureSegmentList::const_iterator it;

	for (i = 0; i < m_ligatureSegments.size(); i++)
	{
		const LigatureSegmentList& lsl = m_ligatureSegments[i];

		for (it = lsl.begin(); it != lsl.end(); it++)
		{
			if (it->pJoint == pJoint)
			{
				return true;
			}
			else if (it->pBranch == pBranch && (it->first == first || it->last == last))
			{
				ASSERT(it->first == first && it->last == last);
				return true;
			}
		}
	}

	return false;
}
			
////////////////////////////////////////////////////////////////////////////////////////////////////////			

	struct BoneSegment
	{
		BoneIndex boneIdx;
		SkelPtIndex from, to;
	};
	
	std::vector<BoneSegmentList> m_branchToBoneSegmentsMap;
////////////////////////////////////////////////////////////////////////////////////////////////////////

/*double dOverlap;

for(edgeIt = edges.begin(); edgeIt != edges.end(); edgeIt++)
{
	dOverlap = BoundaryPointFinder::ComputeEndPointOverlap((*edgeIt)->getFluxPoints());

	sg::FluxPointList& fpl = (*edgeIt)->getFluxPoints();

	DBG_PRINT3(fpl[0], fpl[fpl.size() - 1], dOverlap)
}*/

DDSEdgeListPtr AFMMSkeleton::GetExternalBranches()
{
	DDSEdgeListPtr ptrExternalEdges = new DDSEdgeList;
	
	for(int i = 0; i < int(nodes.size()); i++)
		if(nodes[i]->edges.size() == 1 && ...)
			ptrExternalEdges->push_back(nodes[i]->edges[0]);
	
	return ptrExternalEdges;
}

/*!
	@brief Removes branches of very little saliency in the skeleton.

	This operation is necesary for AFMM skeletons, which some times may
	include external branches that have very little contribution to the 
	shape reconstruction. In contrast, Flux skeletons remove these types of
	branches by uing a thresholds on the radius function of flux points, that
	is different from that used in the AFMM skeletons. In particular, the threshold 
	in the Flux skeleton is basen on the angle, wrt the tangent at the flux point, 
	and the associated boundary point (on either each side).

	Here we remove a branch if: (1) it has exactly one terminal endpoint, (2)
	the circle difened by that endpoint is almas completely overlapped by the
	circle defined by the other endpoint of the branch, (3) the radius at the terminal
	endpoint is considerably smaller than the radius at the other endpoint.

	We proceed by (1) identifying the "spurious" branches, (2) removing all them from the
	skeleton graph (without merging nodes), (3) merging all "broken" branches, (4) recursing
	to eliminate any new "external" branch that looks spurious.

	Note: its important to remove all spurious brabches BEFORE merging nodes, because otherwise
	the order in which we see the branches would matter.
*/
void SkeletalGraph::RemoveSpuriousBranches()
{
	//forall_branches, if external and low saliency, remove

	DDSEdgeListPtr ptrExternalEdges = new DDSEdgeList;
	
	for(int i = 0; i < int(nodes.size()); i++)
		if(nodes[i]->edges.size() == 1 && ...)
			ptrExternalEdges->push_back(nodes[i]->edges[0]);

	forall_elem_in_list
		RemoveNode((*itEAEL).first->n1);
}

/*!
*/
void AFMMSkeleton::RemoveNode(sg::DDSNode* pNode)
{
	bool bNodeRemoved = false;

	for(int i = int(pNode->edges.size()) - 1; i >= 0; i--)
		 RemoveEdge(pNode->edges[i]);
	
	std::vector<sg::DDSNode*>::iterator itNode;
	
	for(itNode = nodes.begin(); itNode != nodes.end() && !bNodeRemoved; ++itNode)
		if(*itNode == pNode)
		{
			nodes.erase(itNode);
			bNodeRemoved = true;
			break;
		}
	ASSERT(bNodeRemoved);

	delete pNode;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

// New functionality (18/Oct/2006)
	if (m_nShowRays > 0 && sk != NULL)
	{
		sg::DDSEdgeVect& edges = sk->getEdges();
		sg::DDSEdgeVect::iterator I;
		sg::FluxPointList::const_iterator II;
		sg::BoundaryInfoList::const_iterator III;
		leda::color col;

		for(I = edges.begin(); I != edges.end(); I++)
		{
			const sg::FluxPointList& fpl    = (*I)->getFluxPoints();
			const sg::BoundaryInfoList& bil = (*I)->getBoundaryInfoList();

			if (fpl.size() >= bil.size())
			{
				for (II = fpl.begin(), III = bil.begin(); III != bil.end(); II++, III++)
				{
					if (m_nShowRays == 2 && II != fpl.begin())
					col = (fabs(III->first.dtValue) <= 1.5) ? leda::blue:leda::red;

					if (III->first.index >= 0 /*&& fabs(III->first.dtValue) < 1*/)
						m_pWnd->draw_segment(ReMapPt(II->p, si), ReMapPt(III->first.pt, si), col);

					col = (fabs(III->second.dtValue) < 1.5) ? leda::green:leda::pink;

					if (III->second.index >= 0 /*&& fabs(III->second.dtValue) < 1*/)
						m_pWnd->draw_segment(ReMapPt(II->p, si), ReMapPt(III->second.pt, si), col);
				}
			}
			else
				cerr << "Branch has no boundary information" << endl;
		}
	}
	
////////////////////////////////////////////////////////////////////////////////////////////////////////

void BoundaryPointFinder::FindLigatureSegments(const sg::FluxPointList& fpl, 
											   const BoundaryInterval& side1, 
											   const BoundaryInterval& side2,
											   sg::BoundaryInfoList& bil)
{
	int nSize = fpl.size() - 1; // we do not include the first point

	int nPrevIndexSide1 = bil[0].first.index;
	int nPrevIndexSide2 = bil[0].second.index;

	double x = 0, cumulBar1 = 20, cumulBar2 = 20;
	int idx1, idx2;

	bool bSwapSide1 = bil[0].first.index != side1.First();
	bool bSwapSide2 = bil[0].second.index != side2.First();

	dml::POINTS data1(nSize), data2(nSize);

	for (int i = 0; i < nSize; i++)
	{
		const sg::FluxPoint& fp = fpl[i + 1];
		sg::BoundaryInfo& bi = bil[i + 1];

		x += sg::Vector(fp.p.x - fpl[i].p.x, fp.p.y - fpl[i].p.y).norm();

		idx1 = bi.first.index;
		idx2 = bi.second.index;

		if (idx1 != nPrevIndexSide1)
		{
			if (bSwapSide1)
				bi.bar1 = BoundaryDistance(idx1, nPrevIndexSide1);
			else
				bi.bar1 = BoundaryDistance(nPrevIndexSide1, idx1);

			cumulBar1 += bi.bar1;
			nPrevIndexSide1 = idx1;
		}
		else
			bi.bar1 = 0;

		if (idx2 != nPrevIndexSide2)
		{
			if (bSwapSide2)
				bi.bar2 = BoundaryDistance(idx2, nPrevIndexSide2);
			else
				bi.bar2 = BoundaryDistance(nPrevIndexSide2, idx2);

			cumulBar2 += bi.bar2;
			nPrevIndexSide2 = idx2;
		}
		else
			bi.bar2 = 0;

		DBG_PRINT_IF(fp, bi.bar1 > 100 || bi.bar2 > 100)
		DBG_PRINT_IF(bi, bi.bar1 > 100 || bi.bar2 > 100)

		data1[i].Set(x, cumulBar1);
		data2[i].Set(x, cumulBar2);

		//DBG_PRINT3(x, cumulBar1, bil[i].bar1)
		//DBG_PRINT3(x, cumulBar2, bil[i].bar2)
		//DBG_PRINT_NEWLINE
	}

	//DBG_PRINT_NEWLINE
	//DBG_PRINT_NEWLINE

	PolyLineApprox poly1(nSize / 2.0, 0.05, 4, -1);
	PolyLineApprox poly2(nSize / 2.0, 0.05, 4, -1);

	/*poly1.SetDbgMode(true);
	poly2.SetDbgMode(true);

	std::cout << "disp('First side: " << bil[0].first.pt << bil[nSize - 1].first.pt 
		<< ", " << bSwapSide1 << "')" << std::endl;*/

	poly1.Fit(data1);

	//std::cout << "disp('Second side: " << bil[0].second.pt << bil[nSize - 1].second.pt 
	//	<< ", " << bSwapSide2 << "')" << std::endl;

	poly2.Fit(data2);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////

return (a > b && !(a >= start && b < start)) || (a < b && (a < start && b >= start));

return (a < b && !(a < start && b >= start)) || (a > b && (a >= start && b < start));

///////////////////////////////////////////////////////////////////////////

void BoundaryPointFinder::FindLigatureSegments(const sg::FluxPointList& fpl, sg::BoundaryInfoList& bil)
{
	int nSize = fpl.size();
	double dx, dy, x = 0, cumulBar1 = 20, cumulBar2 = 20;

	dml::POINTS data1(nSize), data2(nSize);

	// Ignore endpoints
	for (int i = 1; i < nSize - 1; i++)
	{
		const sg::FluxPoint& fp = fpl[i];

		if (i > 1)
		{
			dx = fp.p.x - fpl[i-1].p.x;
			dy = fp.p.y - fpl[i-1].p.y;

			x += sqrt(dx * dx + dy * dy);
		}

		cumulBar1 += bil[i].bar1;
		cumulBar2 += bil[i].bar2;

		data1[i-1].Set(x, cumulBar1);
		data2[i-1].Set(x, cumulBar2);

		//DBG_PRINT3(x, cumulBar1, bil[i].bar1)
		//DBG_PRINT3(x, cumulBar2, bil[i].bar2)
	}

	PolyLineApprox poly1(nSize / 2.0, 0.05, 1, -1);
	PolyLineApprox poly2(nSize / 2.0, 0.05, 1, -1);

	poly1.SetDbgMode(true);
	poly2.SetDbgMode(true);

	poly1.Fit(data1);

	std::cout << "disp('Second side')" << std::endl;

	poly2.Fit(data2);
}

///////////////////////////////////////////////////////////////////////////

	DBG_PRINT_NEWLINE
	DBG_MSG4("Side 1 start", bil[0].first.index, m_dataPts[bil[0].first.index][0], m_dataPts[bil[0].first.index][1])
	DBG_MSG4("Side 1 end", bil[N].first.index, m_dataPts[bil[N].first.index][0], m_dataPts[bil[N].first.index][1])

	DBG_MSG4("Side 2 start", bil[0].second.index, m_dataPts[bil[0].second.index][0], m_dataPts[bil[0].second.index][1])
	DBG_MSG4("Side 2 end", bil[N].second.index, m_dataPts[bil[N].second.index][0], m_dataPts[bil[N].second.index][1])

	DBG_PRINT2(bil[0].second.index, side1.Includes(bil[0].second.index))
	DBG_PRINT2(bil[0].first.index, side2.Includes(bil[0].first.index))

///////////////////////////////////////////////////////////////////////////
	
	sg::Vector v, t;
	double radius_i, alpha, d1, d2, skelDist, a, b, currDist1, currDist2;
	int nPts, j, idx, prevIdx1, prevIdx2, currIdx1, currIdx2;

	std::vector<sg::Point> smoothPts;
	GetSmoothFluxPointCoordinates2(fpl, smoothPts, 1);

	for (unsigned int i = 0; i < fpl.size(); i++)
	{
		// Compute tangent at the current flux point using smooth points
		if (i == 0)
		{
			t.x = smoothPts[i+1].x - smoothPts[i].x;
			t.y = smoothPts[i+1].y - smoothPts[i].y;
		}
		else if (i == fpl.size() - 1)
		{
			t.x = smoothPts[i].x - smoothPts[i-1].x;
			t.y = smoothPts[i].y - smoothPts[i-1].y;
		}
		else
		{
			t.x = smoothPts[i+1].x - smoothPts[i-1].x;
			t.y = smoothPts[i+1].y - smoothPts[i-1].y;
		}

		//t = bil[i].tangent;

		t.normalize();

		const sg::FluxPoint& fp = fpl[i];
		sg::BoundaryInfo& bi = bil[i];

		m_queryPt[0] = fp.p.x; 
		m_queryPt[1] = fp.p.y;
		radius_i = fabs(fp.dist);

		if (i > 0)
		{
			a = fp.p.x - fpl[i - 1].p.x;
			b = fp.p.y - fpl[i - 1].p.y;
			skelDist = sqrt(a * a + b * b);
		}

		// If everything is normal, we should be doing the next do-loop only once.
		// However, in some weird cases, we may need to iterate several times
		DBG_CODE_LINE(int dbg_num_iter = 0)
		do
		{
			DBG_CODE_LINE(dbg_num_iter++)

			radius_i += DELTA_RADIUS;

			nPts = m_kdTree->annkFRSearch(m_queryPt, radius_i * radius_i, m_nPts, m_indices, m_distances);

			// Set sides for each point returned
			for (j = 0, currIdx1 = -1, currIdx2 = -1; j < nPts; j++)
			{
				idx = m_indices[j];

				v.x = m_dataPts[idx][0] - fp.p.x;
				v.y = m_dataPts[idx][1] - fp.p.y;

				v.normalize();

				alpha = acos(t.dot(v));
			
				// We don't know whether is alpha or -alpha, so simply check by
				v.rotate(alpha);
				d1 = (t.x - v.x) * (t.x - v.x) + (t.y - v.y) * (t.y - v.y);

				v.rotate(-2 * alpha);
				d2 = (t.x - v.x) * (t.x - v.x) + (t.y - v.y) * (t.y - v.y);

				if (endpoint)
				{
					dist = sqrt(m_distances[j]);

					if (d1 < d2 && (currIdx1 == -1 || (d1 > alpha1 && dist <= minDist + 1.5))
					{
						currIdx1 = idx;
						alpha1 = d1;
					}
				}
				else
				{
					if (d1 < d2 && currIdx1 == -1)
					{
						currIdx1 = idx;
						currDist1 = sqrt(m_distances[j]);
						if (currIdx2 >= 0) break; //leave for-loop -> we have one point on each side!
					}
					else if (d1 >= d2 && currIdx2 == -1)
					{
						currIdx2 = idx;
						currDist2 = sqrt(m_distances[j]);
						if (currIdx1 >= 0) break; //leave for-loop -> we have one point on each side!
					}
				}
			}
		} while((currIdx1 == -1 || currIdx2 == -1) && nPts < m_nPts);

		DBG_MSG_IF("Multiple iterations for skeleton point required", dbg_num_iter > 1)
		DBG_PRINT_IF(dbg_num_iter, dbg_num_iter > 1)

		ASSERT(currIdx1 >= 0 && currIdx2 >= 0);

		if (currIdx1 >= 0)
		{
			bi.first.pt.x = m_dataPts[currIdx1][0];
			bi.first.pt.y = m_dataPts[currIdx1][1];
			bi.first.valid = true;
			bi.first.dtValue = fabs(fp.dist) - currDist1;
			//if (i > 0) DBG_MSG6("Side 1:", fp, currIdx1, prevIdx1, MeasureBoundaryDistance(currIdx1, prevIdx1), skelDist)
			bi.bar1 = (i > 0) ? MeasureBoundaryDistance(currIdx1, prevIdx1) / skelDist:0;
			prevIdx1 = currIdx1;
		}

		if (currIdx2 >= 0)
		{
			bi.second.pt.x = m_dataPts[currIdx2][0];
			bi.second.pt.y = m_dataPts[currIdx2][1];
			bi.second.valid = true;
			bi.second.dtValue = fabs(fp.dist) - currDist2;
			//if (i > 0) DBG_MSG6("Side 2:", fp, prevIdx2, currIdx2, MeasureBoundaryDistance(prevIdx2, currIdx2), skelDist)
			bi.bar2 = (i > 0) ? MeasureBoundaryDistance(prevIdx2, currIdx2) / skelDist:0;
			prevIdx2 = currIdx2;
		}
	}

///////////////////////////////////////////////////////////////////////////

		// Compute tangent at the current flux point using smooth points
		if (i == 0)
		{
			t.x = fpl[i+1].p.x - fp.p.x;
			t.y = fpl[i+1].p.y - fp.p.y;
		}
		else if (i == fpl.size() - 1)
		{
			t.x = fp.p.x - fpl[i-1].p.x;
			t.y = fp.p.y - fpl[i-1].p.y;
		}
		else
		{
			t.x = fpl[i+1].p.x - fpl[i-1].p.x;
			t.y = fpl[i+1].p.y - fpl[i-1].p.y;
		} 

///////////////////////////////////////////////////////////////////////////

void BoundaryPointFinder::FindBoundaryPoints(const sg::FluxPointList& fpl, sg::BoundaryInfoList& bil)
{
	if (!m_bIsKDTreeBuilt)
		BuildKDTree();

	sg::Vector v, t;
	double radius_i, alpha, d1, d2, skelDist, a, b;
	int nPts, nPtsSide1, nPtsSide2, j, idx, prevIdx1, prevIdx2;
	bool bSide1Set, bSide2Set;

	for (unsigned int i = 0; i < fpl.size(); i++)
	{
		const sg::FluxPoint& fp = fpl[i];
		sg::BoundaryInfo& bi = bil[i];

		// Compute tangent at the point
		if (i == 0)
		{
			t.x = fpl[i+1].p.x - fp.p.x;
			t.y = fpl[i+1].p.y - fp.p.y;
		}
		else if (i == fpl.size() - 1)
		{
			t.x = fp.p.x - fpl[i-1].p.x;
			t.y = fp.p.y - fpl[i-1].p.y;
		}
		else
		{
			t.x = fpl[i+1].p.x - fpl[i-1].p.x;
			t.y = fpl[i+1].p.y - fpl[i-1].p.y;
		} 

		t.normalize();

		m_queryPt[0] = fp.p.x; 
		m_queryPt[1] = fp.p.y;
		radius_i = fabs(fp.dist);

		if (i > 0)
		{
			a = fp.p.x - fpl[i - 1].p.x;
			b = fp.p.y - fpl[i - 1].p.y;
			skelDist = sqrt(a * a + b * b);
		}

		// If everiting is normal, we should be doing the next do-loop only once.
		// However, in some weird cases, we may need to iterate several times
		DBG_CODE_LINE(int dbg_num_iter = 0)
		do
		{
			DBG_CODE_LINE(dbg_num_iter++)

			radius_i += DELTA_RADIUS;

			nPts = m_kdTree->annkFRSearch(m_queryPt, radius_i * radius_i, m_nPts, m_indices, m_distances);

			// Set sides for each point returned
			for (j = 0, nPtsSide1 = 0, nPtsSide2 = 0; j < nPts; j++)
			{
				idx = m_indices[j];

				v.x = m_dataPts[idx][0] - fp.p.x;
				v.y = m_dataPts[idx][1] - fp.p.y;

				v.normalize();

				alpha = acos(t.dot(v));
			
				// We don't know whether is alpha or -alpha, so simply check by
				v.rotate(alpha);
				d1 = (t.x - v.x) * (t.x - v.x) + (t.y - v.y) * (t.y - v.y);

				v.rotate(-2 * alpha);
				d2 = (t.x - v.x) * (t.x - v.x) + (t.y - v.y) * (t.y - v.y);

				if (d1 < d2)
				{
					nPtsSide1++;
					m_sides[idx] = true;
					if (nPtsSide2 > 0) break; //have at least one point on each side!
				}
				else
				{
					nPtsSide2++;
					m_sides[idx] = false;
					if (nPtsSide1 > 0) break; //have at least one point on each side!
				}
			}
		} while((nPtsSide1 == 0 || nPtsSide2 == 0) && nPts < m_nPts);

		DBG_MSG_IF("Multiple iterations for skeleton point required", dbg_num_iter > 1)
		DBG_PRINT_IF(dbg_num_iter, dbg_num_iter > 1)

		// Find the first point on each side
		for (bSide1Set = false, bSide2Set = false, j = 0; 
			 (!bSide1Set || !bSide2Set) && j < nPts; j++)
		{
			idx = m_indices[j];

			if (!bSide1Set && m_sides[idx])
			{
				bSide1Set = true;
				bi.first.pt.x = m_dataPts[idx][0];
				bi.first.pt.y = m_dataPts[idx][1];
				bi.first.valid = true;
				bi.first.dtValue = fabs(fp.dist) - sqrt(m_distances[j]);

				bi.bar1 = (i > 0) ? MeasureBoundaryDistance(prevIdx1, currIdx1)/skelDist:0;
			}
			else if (!bSide2Set && !m_sides[idx])
			{
				bSide2Set = true;
				bi.second.pt.x = m_dataPts[idx][0];
				bi.second.pt.y = m_dataPts[idx][1];
				bi.second.valid = true;
				bi.second.dtValue = fabs(fp.dist) - sqrt(m_distances[j]);

				bi.bar2 = (i > 0) ? MeasureBoundaryDistance(currIdx2,prevIdx2)/skelDist:0;
			}
		}

		prevIdx1 = currIdx1;
		prevIdx2 = currIdx2;
	}
}

///////////////////////////////////////////////////////////////////////////

/*#define DBG_PRINT1(A)        { std::cerr << (A) << std::flush; }
#define DBG_PRINT2(A,B)      { std::cerr << (A) << ' ' << (B) << std::flush; }
#define DBG_PRINT3(A,B,C)    { std::cerr << (A) << ' ' << (B) << ' ' << (C) << std::flush; }
#define DBG_PRINT4(A,B,C,D)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) << std::flush; }
#define DBG_PRINT5(A,B,C,D,E)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << std::flush; }
#define DBG_PRINT6(A,B,C,D,E,F)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << ' ' << (F) << std::flush; }

#define DBG_PRINTL1(A)       { std::cerr << (A) << std::endl; }
#define DBG_PRINTL2(A,B)     { std::cerr << (A) << ' ' << (B) << std::endl; }
#define DBG_PRINTL3(A,B,C)   { std::cerr << (A) << ' ' << (B) << ' ' << (C) << std::endl; }
#define DBG_PRINTL4(A,B,C,D) { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) << std::endl; }
#define DBG_PRINTL5(A,B,C,D,E)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << std::endl; }
#define DBG_PRINTL6(A,B,C,D,E,F)  { std::cerr << (A) << ' ' << (B) << ' ' << (C) << ' ' << (D) \
	<< ' ' << (E) << ' ' << (F) << std::endl; }*/

#define DBG_MSG2(A,B)  { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << (A) << " (" << (B) << ')' << std::endl; }

#define DBG_MSG3(A,B,C)  { std::cerr << std::endl << __FILE__ << "/" << __LINE__ \
	<< ':' << (A) << " (" << (B) << ", " << (C) << ')' << std::endl; }


///////////////////////////////////////////////////////////////////////////

	sg::DDSkeleton* sk2 = ((SkeletalGraph*)si->pSG->GetSkeleton())->GetDDSGraph();
	sg::DiscreteSegCurve* c2 = dynamic_cast<sg::DiscreteSegCurve*>(sk2->getShape()->getCurves()->front());
	unsigned int nSegments = c2->segments.size();
	sg::LineSeg* pSeg;

	for (unsigned int i = 0; i < nSegments; i++)
	{
		pSeg = dynamic_cast<sg::LineSeg*>(c2->segments[i]);
		const sg::Point& pt = pSeg->startPt;
		m_pWnd->draw_pixel(ReMapPt(pt, si), leda::black);
	}

	return true;

///////////////////////////////////////////////////////////////////////////

if (sgpts.GetSize() > 0)
	{
		const POINTS& sgpts = si->pSG->GetBoundaryPts();

		for(int i = 0; i < sgpts.GetSize(); i++)
			pts.push(ReMapPt(sgpts[i], si));
	
		m_pWnd->draw_polygon(pts);
		m_pWnd->draw_segment(ReMapPt(sgpts[sgpts.GetSize() - 1], si), ReMapPt(sgpts[0], si));
	}
	else if (si->pSG->GetSkeleton() != NULL)
	{
	}
	
///////////////////////////////////////////////////////////////////////////

/*
	Testing function
*/
template <class SEGMENT>
void PiecewiseApprox<SEGMENT>::Test()
{
	static POINT testData[] =
	{
		POINT(1.517,  0.187),
		POINT(1.200,  2.923),
		POINT(1.353,  7.465),
		POINT(3.444,  9.187),
		POINT(6.017,  9.933),
		POINT(1.464,  14.00),
		POINT(7.320,  16.26),
		POINT(9.478,  17.15),
		POINT(7.472,  22.14),
		POINT(13.48,  23.18)
	};

	int n = sizeof(testData) / sizeof(*testData);
	
	for (int i = 0; i < n; i++)
		std::cout << std::endl << testData[i];
	
	std::cout << std::endl;

	double e;
	SEGMENT seg;
	e = LeastSquares(testData, n, seg);

	std::cerr << "\nError: " << e << ", slope: " << seg.m << "b: " << seg.b << std::endl;

	std::cerr << "\nShould be: e: 0.68210106, line: y = 4.273150085299648 + 1.5109204502228364x\n";
}

///////////////////////////////////////////////////////////////////////////

	m_curvePoints.Resize(m_knots.GetSize());
	int n;

	for (int i = 0, d = 0; i < m_knots.GetSize(); i++)
	{
		n = m_knots[i].nIndex - d + 1;
		m_curvePoints[i].Resize(n);
		GetTotalDistance(pts + d, n, m_knots[i].seg, m_curvePoints[i]);
		d = m_knots[i].nIndex + 1;
	}
	
///////////////////////////////////////////////////////////////////////////

void SetColinearCtrlPt(const POINT* vertices, double& x1, double& y1, double& x2, double& y2)
{
	double x0 = vertices[0].x;
	double y0 = vertices[0].y;
	double x3 = vertices[1].x; // check indices here. is this what we want?
	double y3 = vertices[1].y;

	double x02 = x0 * x0;
	double x32 = x3 * x3;
	
	double m = (y3 - y0) / double(x3 - x0);
	double m2 = m * m;

	double d2 = 1; // square of the target distance
	                   
	x1 = (-((-2 - 2 * m2) * x0) + sqrt(pow((-2 - 2 * m2 ), 2) * x02 - 
		4 * (1 + m2 ) * (-d2  + x02  + m2 * x02 ))) / (2 * (1 + m2));

	y1 = m * x1 + y0;

	x2 = (-((-2 - 2 * m2) * x3) - sqrt(pow((-2 - 2 * m2 ), 2) * x32 - 
		4 * (1 + m2 ) * (-d2  + x32  + m2 * x32 ))) / (2 * (1 + m2));
 
	y2 = m * x2 + y3;
}

///////////////////////////////////////////////////////////////////////////

	a3 = (x3 - x0 + 3 * (x1 - x2)) / 8;
	b3 = (y3 - y0 + 3 * (y1 - y2)) / 8;
	a2 = (x3 + x0 - x1 - x2) * 3 / 8;
	b2 = (y3 + y0 - y1 - y2) * 3 / 8;
	a1 = (x3 - x0) / 2 - a3;
	b1 = (y3 - y0) / 2 - b3;
	a0 = (x3 + x0) / 2 - a2;
	b0 = (y3 + y0) / 2 - b2;
	
///////////////////////////////////////////////////////////////////////////

	double a3 = (p3.x - p0.x + 3 * (p1.x - p2.x)) / 8;
	double b3 = (p3.y - p0.y + 3 * (p1.y - p2.y)) / 8;
	double a2 = (p3.x + p0.x - p1.x - p2.x) * 3 / 8;
	double b2 = (p3.y + p0.y - p1.y - p2.y) * 3 / 8;
	double a1 = (p3.x - p0.x) / 2 - a3;
	double b1 = (p3.y - p0.y) / 2 - b3;

///////////////////////////////////////////////////////////////////////////

void PolyBezierApprox::Draw(/*CDC* pDC, int nWidth, COLORREF color*/)
{
	/*if (x0 == 0 && y0 == 0) return;

	CPen pen(PS_SOLID, nWidth, color);
	POINT points[4] = {{x0, y0}, {x1, y1}, {x2, y2}, {x3, y3}};
	
	CPen* pOldPen = pDC->SelectObject(&pen);
	pDC->PolyBezier(points, 4);

	pDC->SelectObject(pOldPen);*/
}

void CBSegment::Draw(/*CDC* pDC, int nWidth, COLORREF color*/)
{
	/*CPen pen(PS_SOLID, nWidth, color);
	
	CPen* pOldPen = pDC->SelectObject(&pen);
	
	pDC->PolyBezier(m_points, 4);

	pDC->SelectObject(pOldPen);

	CPoint pt(m_points[3]);
	pDC->Rectangle(pt.x - 4, pt.y - 4, pt.x + 4, pt.y + 4);*/
}

///////////////////////////////////////////////////////////////////////////

			if (val == 'r')
				m_pWnd->reset_clipping();
			else if (val == 'l')
				m_bShowLabels = !m_bShowLabels;
			else if (val == 't')
				m_bShowNodeType = !m_bShowNodeType;
			else if (val == 'a' || val == 'b')
			{
				ShockGraph sg;
				sg = (val == 'a') ? *GetSGInfo1()->pSG:*GetSGInfo2()->pSG;
				ShowGraph(sg);
			}
			else if (val == 'c')
				m_bShowCoords = !m_bShowCoords;
			else if (val == 'i')
				m_bShowSkeletonApproximation = !m_bShowSkeletonApproximation;
			else if (val == 's')
				m_bShowBoundarySegments = !m_bShowBoundarySegments;
			else if (val == 'd')
				m_bShowPointData = !m_bShowPointData;
			else if (isdigit(val))
				m_nShowColorLines = val - '0';
			else if (val == 'h')
			else
				break;

///////////////////////////////////////////////////////////////////////////
// from ShockGraph.cpp

	//!!! boundary points from ImgPreProcess
//	m_boundaryPts = imgInfo.boundaryPts;

// 	for (int k = 0; k < m_boundaryPts.GetSize(); k++)
// 	{
// 		if (xmin == 0 || xmin >  m_boundaryPts[k].x)
// 			xmin = m_boundaryPts[k].x;
// 			
// 		if (xmax <  m_boundaryPts[k].x)	
// 			xmax = m_boundaryPts[k].x;
// 			
// 		if (xmin == 0 || ymin >  m_boundaryPts[k].y)
// 			ymin = m_boundaryPts[k].y;
// 			
// 		if (ymax <  m_boundaryPts[k].y)	
// 			ymax = m_boundaryPts[k].y;
// 	}
	//xmin = ymin = 0;
	//xmax = ymax = 300;
	
///////////////////////////////////////////////////////////////////////////
// from ShockGraph.cpp
	
	/*std::vector<TreeSkel*> set_of_skeletons; //vector to store the pointer to the TreeSkel skeletons
	Skeleton get_skeletons;

	set_of_skeletons = get_skeletons.determine_skeletons(parameters);

	TreeSkel* get_one_skel;

	for(unsigned int j = 0; j < set_of_skeletons.size(); j++)  // for each skeleton, test whether it exists. do this by counting the number of branches
	{
		get_one_skel = set_of_skeletons[j];
		int number_branch = 0;
		for(int i = 0 ; i < get_one_skel->branches.Count(); i++) //count the number of branches
		{
			if(get_one_skel->branches[i]->geomLength()) { number_branch++; }
		}
		cerr << "The number of branches in skeleton number " << j << " is " << number_branch << endl;
	}

	if (set_of_skeletons.size() == 0)
		return false;

	m_pSkeleton = TranslateTreeSkelIntoDDS(set_of_skeletons[0], sgparams); // This returns a FluxSkeleton
	delete set_of_skeletons[0];

	bool thingsOK = ComputeSGFromDDSkeleton(((FluxSkeleton*)m_pSkeleton)->GetSkeletonGraph());*/
	
	/*if (thingsOK)
	{
		// Add the SGs from alternative tree skeletons...
		m_derivSGs.Resize(set_of_skeletons.size() - 1);
			
		for (unsigned int i = 1; thingsOK && i < set_of_skeletons.size(); i++)
		{
			ShockGraph* pSG = new ShockGraph;
			pSG->m_pSkeleton = TranslateTreeSkelIntoDDS(set_of_skeletons[i], sgparams); // This returns a FluxSkeleton
			delete set_of_skeletons[i];
			
			thingsOK = pSG->ComputeSGFromDDSkeleton(((FluxSkeleton*)m_pSkeleton)->GetSkeletonGraph());
			
			if (thingsOK)
				m_derivSGs[i] = pSG;
		}
	}

	return thingsOK;*/

///////////////////////////////////////////////////////////////////////////
// from ShockGraph.h

#include "treeskel.h"

	static FluxSkeleton* TranslateTreeSkelIntoDDS(TreeSkel* ts, const SGCP& sgparams);
	static void ConnectTreeSkelNodes(sg::DDSkeleton*, const TreeSkel::TreeBranch&, const TreeSkel::TreePoint*, sg::DDSNode*, bool);
	static sg::FluxPoint TranslateTreePtIntoFluxPt(const TreeSkel::TreePoint* pTreePt);
	static  void ShowBranchInfo(sg::DDSEdge* , sg::DDSNode* , int);


///////////////////////////////////////////////////////////////////////////
// from ShockGraph.cpp

/*!
	@brief Traverses the skeleton and shows the info in each branch
*/
/* static */ void ShockGraph::ShowBranchInfo(sg::DDSEdge* e, sg::DDSNode* n, int level)
{
	using namespace sg;
	
	// Then, keep creating and connecting nodes
	DDSEdgeVect& edges = n->getEdges();
	DDSEdgeVect::iterator I;
	DDSEdge* ee;
	
	for (int i = 0; i < level; i++)
		cerr << "\t";
				
	cerr << e->getN1()->fp.p << ", " << e->getN2()->fp.p << endl;
	
	// Check that the flow is fine wrt end points
#ifdef _DEBUG
	sg::FluxPointList& fpl = e->getFluxPoints();
	int last = fpl.size() - 1;
	
	if (last > 2 && fpl[0].p.distanceToPt(fpl[1].p) >=  fpl[0].p.distanceToPt(fpl[last - 1].p))
	{
		DBG_MSG("Wrong flow direction")
		cerr << "dist from " << fpl[0].p << " to " << fpl[1].p << " >= dist from "
			<< fpl[0].p << " to " << fpl[last - 1].p;
	}
	
	ASSERT(last <= 2 || fpl[last].p.distanceToPt(fpl[last - 1].p) <  fpl[last].p.distanceToPt(fpl[1].p));
#endif //_DEBUG

	for(I = edges.begin(); I != edges.end(); I++)
	{
		ee = *I;
		
		if (e != ee)
			ShowBranchInfo(ee, ee->getN1() != n ? ee->getN1():ee->getN2(), level + 1);
	}
}

/*!
	@brief Text
	
	More text
	Params in sgparams: {dSkTreshold}
*/
/*static*/ FluxSkeleton* ShockGraph::TranslateTreeSkelIntoDDS(TreeSkel* pTreeSkel, const SGCP& sgparams)
{
	sg::DiscreteSegCurve c;
	sg::SimpleShape s(&c,0,300,0,300);
	sg::DistanceTransform dt(&s);
	sg::DivergenceMap dm(dt);
	sg::DDSkeleton* pDDS = new sg::DDSkeleton(dm);
	leda_d_array<long, sg::DDSNode*> map;
	sg::DDSNode *pEndPt1, *pEndPt2;
	sg::DDSEdge* pEdge;
	int j;

//################################ ADDED JANUARI 13 ##############################

// for(int i = 0; i < pTreeSkel->branches.Count(); i++)
// {
// 	cerr << *pTreeSkel->branches[i] << endl;
// }

//################################################################################
	
	
	
	
	//We take the first branch out of the list of branches
	//and add this one to the DDSkeleton
	int nFirstNonZeroLength = 0;
	TreeSkel::TreeBranch& br = *pTreeSkel->branches[nFirstNonZeroLength];
	if(pTreeSkel->branches.Count() > 1)
	{
		while( ((br.end1->branches.Count() != 1) && (br.end2->branches.Count() != 1)) ||
			((br.end1->branches.Count() == 1) && (br.end2->branches.Count() == 1)))
		{	
 			cerr << "Going to next branch in search for an endbranch\n";
			nFirstNonZeroLength++;
			br = *pTreeSkel->branches[nFirstNonZeroLength];
		}
	}
	//We now found the first branch that has a non zero length
	//and will add this branch to pDDS
	
// 	cerr << "Number of branches at endpoint 1: " << br.end1->branches.Count() << " and at end2 : " << br.end2->branches.Count() << endl;
	
	//Add endpoints to DDSNodes
	if(br.end1->branches.Count() == 1)
	{
		pEndPt1 = new sg::DDSNode(TranslateTreePtIntoFluxPt(br.end1));
		//cerr << "Endpoint 1: (" << br.end1->x << "," << br.end1->y << ") number of neighbor branches at this point " << br.end1->branches.Count() << endl;
		pDDS->addNode(pEndPt1);
		pEndPt2 = new sg::DDSNode(TranslateTreePtIntoFluxPt(br.end2));
		//cerr << "Endpoint 2: (" << br.end2->x << "," << br.end2->y << ") number of neighbor branches at this point " << br.end2->branches.Count() << endl;
		pDDS->addNode(pEndPt2);
	}
	else
	{
		pEndPt1 = new sg::DDSNode(TranslateTreePtIntoFluxPt(br.end2));
		//cerr << "Endpoint 1: (" << br.end1->x << "," << br.end1->y << ") number of neighbor branches at this point " << br.end1->branches.Count() << endl;
		pDDS->addNode(pEndPt1);
		pEndPt2 = new sg::DDSNode(TranslateTreePtIntoFluxPt(br.end1));
		//cerr << "Endpoint 2: (" << br.end2->x << "," << br.end2->y << ") number of neighbor branches at this point " << br.end2->branches.Count() << endl;
		pDDS->addNode(pEndPt2);
	}	
	
	
	sg::FluxPointList fluxPts;
	TreeSkel::TreePoint* pTrSkelEnd1 = NULL;
	TreeSkel::TreePoint* pTrSkelEnd2 = NULL;
	//Add the edge to the sDDS, in "normal" order
	//so from end1 -> end2
	if(br.end1->branches.Count() == 1)
	{
		//sg::FluxPointList fluxPts;
		cout << endl << endl << "%new branch" << endl;
		fluxPts.push_back(pEndPt1->fp);
		for (j = 0; j < br.points.Count(); j++)
			fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
		fluxPts.push_back(pEndPt2->fp);
		pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
		pDDS->addEdge(pEdge);
		
		/*TreeSkel::TreePoint* */ pTrSkelEnd1 = br.end1;
		/*TreeSkel::TreePoint* */ pTrSkelEnd2 = br.end2;
	}
	else
	{
		//sg::FluxPointList fluxPts;
		cout << endl << endl << "%new branch" << endl;
		fluxPts.push_back(pEndPt1->fp);
		for (j = br.points.Count() -1; j >= 0; j--)
			fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
		fluxPts.push_back(pEndPt2->fp);
		pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
		pDDS->addEdge(pEdge);
		
		/*TreeSkel::TreePoint* */ pTrSkelEnd1 = br.end2;
		/*TreeSkel::TreePoint* */ pTrSkelEnd2 = br.end1;
	}	
	
	//Recursively add a new edge and a node to the existing graph
	//given: pDDS, current branch, current endpoint
	//Node that belongs to the endpoint
	cerr << "Start adding edges and nodes to the graph\n";
	bool bFlowAway = false;
	ConnectTreeSkelNodes(pDDS, br, pTrSkelEnd1, pEndPt1, bFlowAway);
	bFlowAway = true;
	ConnectTreeSkelNodes(pDDS, br, pTrSkelEnd2, pEndPt2, bFlowAway);
	cerr << "Done with all the adding of branches\n";
	
	return (new FluxSkeleton(pDDS));
}

/*static*/ void ShockGraph::ConnectTreeSkelNodes(sg::DDSkeleton* pDDS, const TreeSkel::TreeBranch& existingBr, 
	const TreeSkel::TreePoint* pExistingEndPt, sg::DDSNode* pExistingNode, bool flowAway)
{
	using namespace sg;
	
	DDSNode* pNewEndPt;
	DDSNode *pEndPt1, *pEndPt2;
	DDSEdge* pEdge;
	int i,j;
	//for all branches that are connected to the existing endpoint
	for (i = 0; i < pExistingEndPt->branches.Count(); i++)
	{
		//cerr << "\nLooking at 1 branch..." << endl;
		//for all branches different from the one that already
		//existed for this endpoint
		const TreeSkel::TreeBranch& br = *pExistingEndPt->branches[i];

// 		if (br.geomLength() == 0)
// 			ASSERT(true)

// 		cerr << "\nNumber of innerpoints in the branch is: " << br.points.Count() << endl;

		//ASSERT(br.geomLength() != 0)

		if (br != existingBr)
		{
			//cerr << "\nWe actually want to add it to the structure..." << endl;
			sg::FluxPointList fluxPts;//(br.points.Count() + 2); // plus endpoints
			
			if (br.end1 != pExistingEndPt)
			//Endpoint 1 is not yet a node
			{
				pNewEndPt = new sg::DDSNode(TranslateTreePtIntoFluxPt(br.end1));
				pDDS->addNode(pNewEndPt);
				//Add edge in from end2 -> end1, thus away from the given one
				if(flowAway == true) //start from pExistingNode which is end2
				{
					pEndPt1 = pExistingNode;
					pEndPt2 = pNewEndPt;
					//cout << endl << endl << "%new branch" << endl;
					fluxPts.push_back(pEndPt1->fp);
					for (j = br.points.Count() -1; j > -1; j--)
						fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
					fluxPts.push_back(pEndPt2->fp);
					pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
					pDDS->addEdge(pEdge);
					ConnectTreeSkelNodes(pDDS, br, br.end1, pEndPt2, flowAway);
				}
				else //flowAway == false, so start from pNewEndPt which is end1
				{
					pEndPt1 = pNewEndPt;
					pEndPt2 = pExistingNode;
					//cout << endl << endl << "%new branch" << endl;
					fluxPts.push_back(pEndPt1->fp);
					for (j = 0; j < br.points.Count(); j++)
						fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
					fluxPts.push_back(pEndPt2->fp);
					pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
					pDDS->addEdge(pEdge);
					ConnectTreeSkelNodes(pDDS, br, br.end1, pEndPt2, flowAway);
				}
			}
			else if (br.end2 != pExistingEndPt)
			//Endpoint 2 is not yet a node
			{
				pNewEndPt = new DDSNode(TranslateTreePtIntoFluxPt(br.end2));
				pDDS->addNode(pNewEndPt);
				
				if(flowAway == true) //start from pExistingNode which is end1
				{
					pEndPt1 = pExistingNode;
					pEndPt2 = pNewEndPt;
					//cout << endl << endl << "%new branch" << endl;
					fluxPts.push_back(pEndPt1->fp);
					for (j = 0; j < br.points.Count(); j++)
						fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
					fluxPts.push_back(pEndPt2->fp);
					pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
					pDDS->addEdge(pEdge);
					ConnectTreeSkelNodes(pDDS, br, br.end2, pEndPt2, flowAway);
				}
				else //flowAway == false, so start from pNewEndPt which is end2
				{	
					pEndPt1 = pNewEndPt;
					pEndPt2 = pExistingNode;
					//cout << endl << endl << "%new branch" << endl;
					fluxPts.push_back(pEndPt1->fp);
					for (j = br.points.Count() -1; j > -1; j--)
						fluxPts.push_back(TranslateTreePtIntoFluxPt(br.points[j]));
					fluxPts.push_back(pEndPt2->fp);
					pEdge = new sg::DDSEdge(pDDS, fluxPts, pEndPt1, pEndPt2);
					pDDS->addEdge(pEdge);
					ConnectTreeSkelNodes(pDDS, br, br.end2, pEndPt2, flowAway);
				}
			}
			else
				cerr << "We don't deal with circular branches right now\n";
		}
	}
}

/*!
	@brief Text
	
	More text
*/
/*static*/ sg::FluxPoint ShockGraph::TranslateTreePtIntoFluxPt(const TreeSkel::TreePoint* pTreePt)
{
	sg::FluxPoint fp;
	
	fp.p.x = pTreePt->x;
	fp.p.y = pTreePt->y;
	fp.dist = pTreePt->dRadius; //pTreePt.radius;
	//cout << pTreePt->dRadius << endl;
	fp.col = 0; // not used
	fp.val = 0; // not used
	
	return fp;
}

///////////////////////////////////////////////////////////////////////////

typedef leda_list<leda_edge> EdgeList;
typedef leda_list<leda_node> NodeList;
typedef leda_d_array<leda_node, leda_node> NodeMap;
typedef leda_d_array<leda_edge, leda_node> EdgeNodeMap;
typedef leda_d_array<leda_node, leda_list_item> NodeListItemMap;
typedef leda_d_array<leda_node, int> NodeIndexMap;

typedef leda_list<DAGNodePtr> DAGNodeList;
typedef leda_d_array<DAGNodePtr, DAGNodePtr> DAGNodeMap;


/*
 * For a given node, the	 following method counts the number of its siblings,
 * parents and children, if any.
 * This number is necassary to create an input file to
 * feed the earth mover's distance code.
 */
int GestureGraph::Get_number_of_relations(int node){

 int counter = 0; //The first number accounts for the node itself.
 int nVertices = hierarchyLevels.GetSize();

//cout << "no_vertices from size :" << hierarchyLevels.GetSize() << endl;

 for(int i=0; i < nVertices; i++){

        if (hierarchicalMatrix[node][i]!=0) //count all the relations.
                 counter++;

 }

 return counter;

}


int GestureGraph::Get_nth_relation(int n, int node){

  int no = 0;
  int nVertices = hierarchyLevels.GetSize();

        for (int i=0; i<nVertices; i++){
                if (hierarchicalMatrix[node][i] != 0)
                        no++;

                if (no==n)
                        return i;
        }

 return 0;
}

/*
 * Computing the Euclidean distance between 2 nodes.
 */

float GestureGraph::Get_distance(int node1, int node2){

 const DAGNode *dag_ptr1 = GetNode(GetNode(node1));
 const GGNode *p1 = dynamic_cast<const GGNode*>(dag_ptr1);

 const DAGNode *dag_ptr2 = GetNode(GetNode(node2));
 const GGNode *p2 = dynamic_cast<const GGNode*>(dag_ptr2);

 int x1 = p1->m_nXPos;
 int y1 = p1->m_nYPos;
 int x2 = p2->m_nXPos;
 int y2 = p2->m_nYPos;
 float temp = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);

 return sqrt(temp);
}


int GestureGraph::Get_xpos(int node){

 const DAGNode *dag_ptr = GetNode(GetNode(node));
 const GGNode *p = dynamic_cast<const GGNode*>(dag_ptr);

 return p->m_nXPos;

}

int GestureGraph::Get_ypos(int node){

 const DAGNode *dag_ptr = GetNode(GetNode(node));
 const GGNode *p = dynamic_cast<const GGNode*>(dag_ptr);

 return p->m_nYPos;

}

void GetPath(int i, int last, int tgt)
{
	COctahedronPoints pts(3);
	int* pNeigPts = pts.GetNeighbours(i - 1, 2);
	int n1 = pNeigPts[0] + 1;
	int n2 = pNeigPts[1] + 1;
	free(pNeigPts);

	int n = n1 == last ? n2:n1;

	if (n == tgt)
		return;
	else
	{
		cout << endl << n;
		GetPath(n, i, tgt);
	}
}

SmartArray<int> GetClosestViewsByRange(int i, int res, const double& range)
{
	COctahedronPoints pts(res);
	int n;

	//int* pNeigPts = pts.GetNeighbours(i - 1, range, n);
	n = 126;
	int* pNeigPts = pts.GetNeighbours(i - 1, n);
	SmartArray<int> views(n);
	
	for (int j = 0; j < n; j++)
		views[j] = pNeigPts[j] + 1;

	free(pNeigPts);

	return views;
}

SmartArray<int> GetSymmetricViewMap()
{
	const int nViewsPerObj = 128;
	SmartArray<int> symmap, views;
	int viewmap[nViewsPerObj], i, j, k;

	symmap.Resize(nViewsPerObj + 1, true); // view 0 isn't used

	for (i = 1; i <= nViewsPerObj; i++)
	{
		views = GetClosestViewsByRange(i, 3, 178); // 178 = a bit less than 180.

		// Turn off all views
		memset(viewmap, 0, nViewsPerObj * sizeof(int));

		// Turn on views that are within 178 deg.
		for (j = 0; j < views.GetSize(); j++)
			viewmap[views[j] - 1] = 1;

		// Turn on the target view
		viewmap[i - 1] = 1;

		// There should be only one view off = 0
		for (k = 0; k < nViewsPerObj; k++)
			if (viewmap[k] == 0 && symmap[i] == 0)
				symmap[i] = k + 1;
			else if (viewmap[k] == 0 && symmap[i] != 0)
			{
				ShowError("Multiple symmetric views.");
				ASSERT(false);
			}
			else if (k == nViewsPerObj - 1 && symmap[i] == 0 && viewmap[k] != 0)
			{
				ShowError("One view is unmapped.");
				ASSERT(false);
			}
	}

	return symmap;
}



	/*//Check if it is type 4
	if (outdeg(v) == 2 && indeg(v) == 1 && parentType == ROOT)
	{
		int d1 = GetBranchDir(GetFirstChild(v), v);
		int d2 = GetBranchDir(GetSecondChild(v), v);
		
		// If children are decreasing must relabel
		if (d1 == -1 && d2 == -1)
			UnsafeGetSGNode(v)->SetNodeType(SHOCK_4);
	}
	//Check if it is type 2
	else if(outdeg(v) == 0 && indeg(v) == 2)
	{
		int d1 = GetBranchDir(GetFirstParent(v), v);
		int d2 = GetBranchDir(GetSecondParent(v), v);
		
		// If parents are increasing must relabel
		if (d1 == 1 && d2 == 1)
			UnsafeGetSGNode(v)->SetNodeType(SHOCK_2);
		else // it's a 3 with 1's decresing. change that!!!
		{
			WARNING(d1 == -1 || d2 == -1, "Should not occurr in this context");
			forall_in_edges(e, v)
				if (GetBranchDir(source(e), v) == -1)
					rev_edge(e);
		}
	}*/


	/*DBG_VAL(pNode1->GetSegments().GetHead().p0)
	DBG_VAL(g1Pts.GetHead())
	DBG_VAL(pNode1->GetSegments().GetTail().p1)
	DBG_VAL(g1Pts.GetTail())
	
	DBG_VAL(pNode2->GetSegments().GetHead().p0)
	DBG_VAL(g2Pts.GetHead())
	DBG_VAL(pNode2->GetSegments().GetTail().p1)
	DBG_VAL(g2Pts.GetTail())*/

int GetLeaves(TREE_NODE root, leda_graph& g, leda_list<TREE_NODE>& leaves)
{
	int nMaxHeight = root.height;

	if (g.outdeg(root.node) > 0)
	{
		leda_node v, w = root.node;
		int h;

		root.height++;

		forall_adj_nodes(v, w)
		{
			// If loopy node, hide it so as to process it last
			if (indeg(v) > 1)
				g.hide_node(v);
			else
			{
				root.node = v;
    			h = GetLeaves(root, g, leaves);

    			if (h > nMaxHeight)
    				nMaxHeight = h;
			}
		}
		
		// Let's now process loopy nodes, which are hidden
		list_item it;
		leda_list<leda_node> hnlist = g.hidden_nodes();
		leda_edge e;
		
		forall_items(it, hnlist)
		{
			// Add the loopy node. It will be last
			// among its siblings
			v = hnlist[it];	
			root.node = v;	
			h = GetLeaves(root, g, leaves);

    		if (h > nMaxHeight)
    			nMaxHeight = h;
    			
    		// Now that we porcess all the children of w,
    		// we continue with the other parents of the
    		// loopy nodes. We process these parents and

    		// the hide them, so that they don't get process twice.
    			
    		forall_in_edges(e, v)
    		{
				if (g.source(e) != w)
				{
					root.node = g.source(e);
					root.height = GetNodeHeight(g, root.node);
					
					h = GetLeaves(root, g, leaves);
					g.hide_node(root.node);
					
					if (h > nMaxHeight)
    					nMaxHeight = h;
				}
			}
					
			g.restore_node(v);
		}
		
		// If we are dealing with the root, it is time to unhide
		// all th eparents of loopy nodes, becaus ewe are done.
		if (g.indeg(w) == 0)
			g.restore_all_edges();
	}
	else
		leaves.append(root);

	return nMaxHeight;
}



void ShockGraph::RevertEdge(leda_edge pxEdge)
{
	leda_node parent = source(pxEdge);
	leda_node x = target(pxEdge);
	leda_edge e;
	SmartArray<leda_edge> edgesToDelete(1, SA_GROWING_FACTOR);
	
	edgesToDelete.AddTail(pxEdge); // pxEdge will be del at the end
	
	// if x not type 3 or has no children
	if (NodeType(x) != SHOCK_3 || outdeg(x) == 0)
	{
		// Move all children of x's parent (that are also connected to x)
		// to the left side of x
		const ShockInfo& inPt = GetJointPoint(parent, x);
		

		forall_adj_edges(e, parent)
		{
			if (e != pxEdge && GetJointPoint(parent, target(e)) == inPt)
			{
				NewEdge(x, target(e));
				edgesToDelete.AddTail(e);
			}
		}
		
		NewEdge(x, parent); // creates x->p edge
	}
	else // There are nodes coming from different sides
	{
		ASSERT(NodeType(x) == SHOCK_3);
		
		leda_node leftChild = NewNode(new SGNode(*GetSGNode(x)));
		leda_node rightChild = NewNode(new SGNode(*GetSGNode(x)));
		
		// Move all children of x's parent (that are also connected to x)
		// to the left side of x
		const ShockInfo& inPt = GetJointPoint(parent, x);
		
		forall_adj_edges(e, parent)
		{
			if (e != pxEdge && GetJointPoint(parent, target(e)) == inPt)
			{
				NewEdge(leftChild, target(e));
				edgesToDelete.AddTail(e);
			}
		}
		
		NewEdge(leftChild, parent); // creates x's left->p edge
		
		// Move all children of x to the right side of x
		forall_adj_edges(e, x)
		{
			NewEdge(rightChild, target(e));
			edgesToDelete.AddTail(e);
		}
		
		// Link x to its left and right sides
		NewEdge(x, rightChild);
		NewEdge(x, leftChild);
	}
	
	for (int i = 0; i < edgesToDelete.GetSize(); i++)
		//DelEdge(edgesToDelete[i]);
		hide_edge(edgesToDelete[i]);
}
	
	
	
	
	double tau = pts.AvgRadius() * compParams.dSigma; //compParams.dSigma
	int winSize = int(ceil(pow(pts.Length(), 3.0) / (compParams.dSigmaRange * pts.Area())));

	if (winSize < 1) winSize = 1;

	//ApproxPoly poly(tau, compParams.dDerivCutoff);
	//poly.TwoPassFit(data, nSize);
	//poly.Fit(data, nSize);
	//poly.Fit(data, nSize, winSize, compParams.dDerivCutoff, compParams.dSigma);
	//poly.Fit(data, nSize, int(ceil(nSize / 12)));


DDSNode* FluxSkeleton::ReadNodesAndEdges(istream& is, DDSkeleton& dds)
{
	int fp_count, n1_adj_edges_count, i, j, tgtIdx;
	double lt1, lt2, rt1, rt2;
	FluxPoint fp;
	DDSNode* n2;

	// read n1
	is.read((char*) &fp, sizeof(fp));
	is.read((char*) &n1_adj_edges_count, sizeof(n1_adj_edges_count));

	DDSNode* n1 =  new DDSNode(fp);
	dds.addNode(n1);

	for (i = 0; i < n1_adj_edges_count; i++)
	{
	        is.read((char*) &tgtIdx, sizeof(tgtIdx));

		// Read target node
		n2 = ReadNodesAndEdges(is, dds);

		//Read edge
		is.read((char*) &lt1, sizeof(lt1));
		is.read((char*) &lt2, sizeof(lt2));
		is.read((char*) &rt1, sizeof(rt1));
		is.read((char*) &rt2, sizeof(rt2));
		is.read((char*) &fp_count, sizeof(fp_count));
		ASSERT(fp_count > 0);
		FluxPointList fpl;

		for (j = 0; j < fp_count; j++) 
		{
			is.read((char*) &fp, sizeof(fp));
			fpl.push_back(fp);
		}

		//Add edge
		DDSEdge* e = new DDSEdge(&dds, fpl, tgtIdx == 2 ? n1:n2, tgtIdx == 2 ? n2:n1);
		if (lt1 != -1 || lt2 != -1) e->setLeftSegment(lt1, lt2);
		if (rt1 != -1 || rt2 != -1) e->setRightSegment(rt1, rt2);
		dds.addEdge(e);
	}

	return n1;

  leda_d_array<long, leda_node> map;


}

void FluxSkeleton::WriteNodesAndEdges(ostream& os, DDSNode* src, DDSEdge* pInEdge)
{
	FluxPoint fp;
	DDSEdgeVect::iterator I;
	DDSEdgeVect edges = src->getEdges();
	int src_adj_edges_count = (pInEdge) ? edges.size() - 1:edges.size(); // Do not save in edge
	DDSEdge* e;
	int tgtIdx;

	// Write node 1
	os.write((char*) &src->fp, sizeof(src->fp));
	os.write((char*) &src_adj_edges_count, sizeof(src_adj_edges_count));
    
	for(I = edges.begin(); I != edges.end(); I++)
	{
		e = (*I);

		// Write only adj edges
		if (pInEdge != e)
		{
		        ASSERT(src == e->getN1() || src == e->getN2());

		        // Keep the adjacency indices in the edge
		        tgtIdx = (src == e->getN1()) ? 2:1;
			os.write((char*) &tgtIdx, sizeof(tgtIdx));

			//Write target node's adj edges
			WriteNodesAndEdges(os, (tgtIdx == 1) ? e->getN1():e->getN2(), e);

			//Write edge
			FluxPointList& fpl = e->getFluxPoints();
			int fp_count = fpl.size();
			ASSERT(fp_count > 0);

			os.write((char*) &e->left_t1, sizeof(e->left_t1));
			os.write((char*) &e->left_t2, sizeof(e->left_t2));
			os.write((char*) &e->right_t1, sizeof(e->right_t1));
			os.write((char*) &e->right_t2, sizeof(e->right_t2));
			os.write((char*) &fp_count, sizeof(fp_count));

			FluxPointList::iterator II;

			for(II = fpl.begin(); II != fpl.end(); II++)
			{
				fp = *II;
				os.write((char*) &fp, sizeof(fp));
			}		
		}
	}
}








/*!
@brief Finds the branch with the largest average radius.
*/
sg::DDSEdge* ShockGraph::FindLatestNodeToForm(sg::DDSkeleton* sk) const
{
	using namespace sg;
	
	DDSEdgeVect& edges = sk->getEdges();
	DDSEdgeVect::iterator I;
	DDSEdge* e = *edges.begin();
	double dMaxAvgRadius = -1, dAvgRadius;
	int i;
	
	for(I = edges.begin(); I != edges.end(); I++)
	{
		const sg::FluxPointList& fpl = (*I)->getFluxPoints();
		
		for (i = 0, dAvgRadius = 0.0; i < fpl.size(); i++)
			dAvgRadius += fabs(fpl[i].dist);
		
		if (dAvgRadius > 0.0)
			dAvgRadius = dAvgRadius / fpl.size();
		
		// Save the gratest min point among all branches
		if (dAvgRadius > dMaxAvgRadius)
		{
			dMaxAvgRadius = dAvgRadius;
			e = *I;
		}
	}
	
	return e;
}

double SweepContrast(const SGNode *node)
{
	
	double min_rad = 999999;
	double max_rad = 0;
	double curr_rad = 0;
	double sweep_contrast;
	
	int shockCount = node->GetShockCount();  
	
	for (int j = 0; j < shockCount; j++)
    {
		double curr_rad = node->m_shocks[j].radius;	    
		if (curr_rad > max_rad)
			max_rad = curr_rad;
		if (curr_rad < min_rad)
			min_rad = curr_rad;
    }
	sweep_contrast = ((double) max_rad - (double) min_rad)/(double) max_rad;
	return(sweep_contrast);
}


/* This function labels the node as being a 1,2,3, or 4 based on first assuming
that the sweep function is second order.  We will find the max and minimum radius
along the skeleton, and look at their deviation and their relative positions,
and based on simple ordering rules, we'll classify the skeleton. 
*/

int ShockGraph::ComputeNodeLabel(const SGNode *node) const
{
	double sweep_contrast_thresh = .20;
	double min_rad = 999999;
	double max_rad = 0;
	double curr_rad = 0;
	double sweep_contrast = SweepContrast(node);
	double avg_radius = 0;
	
	int shockCount = node->GetShockCount();  
	int node_type;
	
	double first_rad = node->m_shocks[0].radius;
	double last_rad = node->m_shocks[shockCount - 1].radius;
	
	for (int j = 0; j < shockCount; j++)
	{
		double curr_rad = node->m_shocks[j].radius;	    
		if (curr_rad > max_rad)
			max_rad = curr_rad;
		if (curr_rad < min_rad)
			min_rad = curr_rad;
		avg_radius = avg_radius + curr_rad;
	}
	avg_radius = avg_radius / (double) shockCount;
	
	// If both end points have significantly larger radius than min, then type 2
	if ((min_rad < first_rad) && (min_rad < last_rad) &&
		((first_rad - min_rad)/first_rad >= sweep_contrast_thresh) &&
		((last_rad - min_rad)/last_rad >= sweep_contrast_thresh))
	{
		node_type = SHOCK_2;
	}
	// Else if both endpoints have significantly less radius than max, then type 4
	else if ((max_rad > first_rad) && (max_rad > last_rad) &&
		((max_rad - first_rad)/max_rad >= sweep_contrast_thresh) &&
		((max_rad - last_rad)/max_rad >= sweep_contrast_thresh))
	{
		node_type = SHOCK_4;
	}
	// If average radius is near the max or the min, then type 3.
	else if (((max_rad - avg_radius)/max_rad <= sweep_contrast_thresh) ||
		((avg_radius - min_rad)/max_rad <= sweep_contrast_thresh))
	{
		node_type = SHOCK_3;
	}
	else
	{
		node_type = SHOCK_1;
	}
	return node_type;
}

NODE_ROLE ShockGraph::ComputeNodeRole(leda_node v) const
{
	int nType = NodeType(v);
	
	// Is birth. Rule 1
	if (nType == ROOT)
		return BIRTH;
	
	if (GetSGNode(v)->GetShockCount() == 1 && nType != SHOCK_2 && nType != SHOCK_4)
		return DUMMY;
	
	int nParentType = NodeType(source(first_in_edge(v)));
	
	// Is union
	if (indeg(v) == 2 && (nType == SHOCK_2 || nType == SHOCK_3))
	{
		// Rule 5 and 6a
		//ASSERT(nType == SHOCK_2 || nType == SHOCK_3);
		return UNION;
	}
	else if (nType == SHOCK_3 && nParentType == SHOCK_1)
		// Rule 6b
		return UNION;
	
	// Is death. Rules 7, 8, 9 and 10
	if (outdeg(v) == 0)
		return DEATH;
	
	

	int nFirstOrderSeg = 0;
	leda_node w;
	
	forall_adj_nodes(w, v)

		if (NodeType(w) == SHOCK_1)
			nFirstOrderSeg++;
		
		bool bAllOnes = nFirstOrderSeg == outdeg(v);
		
		// Is protrusion
		
		// Rule 4
		if (nType == SHOCK_1 && nFirstOrderSeg >= 2 && bAllOnes)
			return PROTRUSION;
		
		// Rule 2
		else if (nType == SHOCK_4 && bAllOnes)
			return PROTRUSION;
		
		// Rule 3b
		else if (nType == SHOCK_3 && nParentType == ROOT && bAllOnes)
			return PROTRUSION;
		
		else if (nType == SHOCK_3) // and more
			return PROTRUSION;
		
			/*cerr << endl << GetDAGLbl() << " in node " << GetNodeLbl(v) << 
			"\nUnknown role: " << 
			"\n\tNode type: " << nType <<
			"\n\tParent type: " << nParentType <<
			"\n\tnFirstOrderSeg: " << nFirstOrderSeg <<
			"\n\tbAllOnes: " << bAllOnes << endl << flush;
			
			 
		DBG_MSG("Unknown SG node role!!!");*/
		
		return UNK_ROLE;
}
void ShockGraph::EliminateSpuriousNodes()
{
	leda_node v;
	bool flag = false;
	
	forall_nodes(v, *this)
	{

		if (NodeType(v) == SHOCK_3 && 
			indeg(v) == 1 && outdeg(v) == 1 && 
			GetSGNode(v)->GetShockCount() == 1)
		{
			leda_edge outEdge = first_adj_edge(v);
			
			if (NodeType(target(outEdge)) == SHOCK_1)
			{
				leda_edge inEdge = first_in_edge(v);
				
				NewEdge(source(inEdge), target(outEdge));
				
				del_edge(inEdge);
				del_edge(outEdge);
				del_node(v);
				
				flag = true;
			}
		}
	}
	
	if (flag)
		cerr << endl << GetDAGLbl() << " has been cleaned up!";
}


bool ShockGraph::ComputeFromPPMFile2(const char* szFileName, 

		                     double cutoff, double sigma, double range)
{
  using namespace sg;
  
  // do the skeleton work, Alex's code
  //  cout << endl << "Generating the skeleton:" << endl;
  
  int i, j, rows, cols, format;
  pixval maxval;
  
  FILE* fp = fopen(szFileName, "r");
  
  if (fp == NULL)
    {
      cerr << "Can't open " << szFileName << endl;
      return false;
    }
  
  ppm_readppminit(fp, &cols, &rows, &maxval, &format);
  fclose(fp);
  
  //  cout << "Getting array...";
  char *a = get_arr(&rows, &cols, szFileName);  
  //  cout << "done." << endl;
  // first, we must make a Shape
  sg::SimpleShapeMaker ssm(cols, rows);
  
  // update the SimpleShape
  for (i=0; i < rows; i++)
    for (j=0; j < cols; j++)
      ssm(j,i) = a[i*cols + j];
  
  // free the input array 
  free(a);
  
  // the shape is being made here
  SimpleShape ss = *((SimpleShape*)ssm.getShape());
  
  double xmin,xmax,ymin,ymax;
  ss.getBounds(&xmin,&xmax, &ymin,&ymax);
  
  std::cerr << "(xmin,ymin): ("<<xmin<<", "<<ymin<<")\n";
  std::cerr << "(xmax,ymax): ("<<xmax<<", "<<ymax<<")\n";
  
  // we can get the contour of a SimpleShape as is consists of a
  // single Curve (actually a DiscreteSegCurve) 
  DiscreteSegCurve dsc = *(DiscreteSegCurve *)ssm.getContour();
  std::cerr << dsc << "\n";
  
  // now, we can create a DistanceTransform object
  DistanceTransform dt(&ss);
  
  // and a DivergenceMap
  DivergenceMap dm(dt);
  
  // to supply to the SkeletonMaker
  //  cout << "Making the skeleton...";
  DivergenceSkeletonMaker dsm(dm);
  double thresh=-2.0, mag=1.0;
  DDSkeleton *skeleton = dsm.getDiscreteDivergenceSkeleton(1.0/mag, thresh); 
  //  cout << "done." << endl;  

  /*************************************NEW CODE********************************/
  
  // analyse the points, create the LEDA graph (SG)
  //  cout << endl << "Generating the shock graph:" << endl;
  
  Clear(); //make sure the graph is empty
  
  // stores the shock points
  std::vector<DiscreteDivergenceSkeletonNode*> nodes;
  std::vector<DiscreteDivergenceSkeletonEdge*> edges;
  
  nodes = skeleton->getNodes();	// get all nodes
  edges = skeleton->getEdges();
  
  //DiscreteDivergenceSkeletonEdge* SKparent;
  SGNode* pNode = NULL;
  //	SGNode* SGparent = NULL;
  leda_d_array<long, leda_node> map;
  char szNodeLbl[10];
  
  // make some LEDA nodes
  for ( int i=0; i<edges.size(); i++ )
    {
      long pointerID = (long)(edges[i]);
      
      sprintf(szNodeLbl, "%d", i);
      pNode = new SGNode(szNodeLbl, 0);
      
      FluxPointList fpl = (edges[i])->getFluxPoints();
      int num_pts = fpl.size();
      
      pNode->m_shocks.Resize((num_pts>0) ? num_pts:0);
      for ( int j=0; j<num_pts; j++ )
	{
	  FluxPoint pt = fpl[j];
	  ShockInfo& si = pNode->m_shocks[j];
	  si.xcoord = pt.p.x;
	  si.ycoord = pt.p.y;
	  si.radius = -1.0 * pt.dist; // guessing here
	  si.speed  = pt.val;  // guessing here too
	  si.color = 0;
	  
	  // Set bounding rectangle for drawing purposes
	  /*if (pt.p.x - si.radius < this->xmin) this->xmin = pt.p.x - si.radius;
	  if (pt.p.x + si.radius > this->xmax) this->xmax = pt.p.x + si.radius;
	  if (pt.p.y - si.radius < this->ymin) this->ymin = pt.p.y - si.radius;
	  if (pt.p.y + si.radius > this->ymax) this->ymax = pt.p.y + si.radius;*/

	  if (pt.p.x < this->xmin) this->xmin = pt.p.x;
	  if (pt.p.x > this->xmax) this->xmax = pt.p.x;
	  if (pt.p.y < this->ymin) this->ymin = pt.p.y;
	  if (pt.p.y > this->ymax) this->ymax = pt.p.y;
	}
		
      pNode->ComputeDerivedValues();
      pNode->SetNodeRole(NODE_ROLE(0));

      map[pointerID] = NewNode(pNode); // make a map entry
      

      //      cout << "Node #" << i << " has " << pNode->GetShockCount() << " points and average radius " 
      //	   << pNode->m_shocks.AvgRadius() << ". Type is " << pNode->GetType() << endl;
    }
  
  //  cout << "Drawing the edges (v6)..." << endl;
  DiscreteDivergenceSkeletonEdge* root_edge;  
  sprintf(szNodeLbl, "%c", '#');
  SGNode* hash = new SGNode(szNodeLbl, 0);
  hash->SetNodeRole(NODE_ROLE(BIRTH));
  hash->SetNodeType(ROOT);
  map[(long)hash] = NewNode(hash);
  
  while (( root_edge = GetGreatestUntouched(map,edges) ) != NULL )
    {
      // split if necessary, otherwise returns itput node
      pNode = (SGNode*)GetSGNode(map[(long)root_edge]);
      SGNode* pNode2 = SplitSGNode(pNode, map);

      // draw edges from # to each root edge
      NewEdge( map[(long)hash], map[(long)root_edge], 1.0 );
      //      cout << "Edge drawn from # to avg rad " << GetSGNode(map[(long)root_edge])->m_shocks.AvgRadius();
      if ( pNode != pNode2 ) // if there's a split we need a second root
	{
	  NewEdge( map[(long)hash], map[(long)pNode2], 1.0 );
	  //	  cout << " and to it's mirror side.";
	}
      //      cout << endl;
      // call DrawEdges to recursively traverse the skeleton and create edges
      if ( root_edge->getN1() != NULL ) DrawEdges(root_edge, root_edge->getN1(), map, pNode);
      if ( root_edge->getN2() != NULL ) DrawEdges(root_edge, root_edge->getN2(), map, pNode2);
    }
  ComputeDerivedValues();
  SetDAGLbl(szFileName);
  return true;
}

SGNode* ShockGraph::SplitSGNode(SGNode* pNode, leda_d_array<long, leda_node>& map)
{
  int type = ComputeNodeLabel(pNode);
  if ( type == SHOCK_3 || type == SHOCK_2 )
    {
      SGNode* newNode = new SGNode(*pNode);
      map[(long)newNode] = NewNode(newNode);
      // should add labels 'a' and 'b' to each side
      return newNode;
    }
  else
    return pNode;
}

sg::DiscreteDivergenceSkeletonEdge* ShockGraph::GetGreatestUntouched(leda_d_array<long, leda_node>& map, 
	std::vector<sg::DiscreteDivergenceSkeletonEdge*> edges)
{
  using namespace sg;
  DiscreteDivergenceSkeletonEdge* greatest_edge = NULL;
  for ( int i=0; i<edges.size(); i++ )
    {
      const SGNode* node = GetSGNode(map[(long)edges[i]]);
      if ( node->GetType() == 0 ) 
	{
	  if ( greatest_edge == NULL || node->m_shocks.AvgRadius() > GetSGNode(map[(long)greatest_edge])->m_shocks.AvgRadius() )
	    {
	      // select new greatest edge
	      greatest_edge = edges[i];
	    }
	}
    }
  return greatest_edge;
}

/*!
	@brief Recursive edge maker
*/
void ShockGraph::DrawEdges(sg::DiscreteDivergenceSkeletonEdge* SKparent,
	sg::DiscreteDivergenceSkeletonNode* node, leda_d_array<long, leda_node>& map, SGNode* SGparent)
{
  using namespace sg;
  std::vector<DiscreteDivergenceSkeletonEdge*> l_edges;	// stores local edges
  long pointerID;
  
  // in the case of 3's and 2's the SKparent will return a different pointer than
  // what is expected.  This is because of the duplicate entries for 3's and 2's
  // we want to use the correct key, in this case SGparent itself, not SKparent
  SGparent->SetNodeType(ComputeNodeLabel(SGparent)); // set the type
  if ( SGparent == GetSGNode(map[(long)SKparent]) )
    pointerID = (long)SKparent;
  else
    pointerID = (long)SGparent;
  
  if ( node->getEdges().size() > 1 )
    {
      l_edges = node->getEdges();
      for ( int j=0; j<l_edges.size(); j++ )
	{ 
	  // compare radii (do not recurse if a larger radius is found
	  SGNode* SGchild = (SGNode*)GetSGNode(map[(long)l_edges[j]]);
	  if ( SKparent != l_edges[j] && SGparent->m_shocks.AvgRadius() > SGchild->m_shocks.AvgRadius() )
	    {
	      // draw edges from parent to (each) child, check for splits
	      SGNode* SGchild2 = SplitSGNode(SGchild, map);
	      NewEdge( map[pointerID], map[(long)l_edges[j]], 1.0); // draw the edge
	      //	      cout << "Edge drawn from avg rad " << SGparent->m_shocks.AvgRadius()
		  // << " to avg rad " << SGchild->m_shocks.AvgRadius();	      
	      if ( SGchild != SGchild2 ) // if there's a split we need a second root
		{
		  NewEdge( map[pointerID], map[(long)SGchild2], 1.0 );
		  //		  cout << " and to its mirror side";
		}
	      //	      cout << endl;
	      // recursive call
	      if ( SGchild->GetType() == 0 && l_edges[j]->getN1() != NULL && l_edges[j]->getN1() != node )
		DrawEdges(l_edges[j], l_edges[j]->getN1(), map, SGchild);
	      else 
		SGchild->SetNodeType(ComputeNodeLabel(SGchild));
	      // more recursion...
	      if ( SGchild2->GetType() == 0 && l_edges[j]->getN2() != NULL && l_edges[j]->getN2() != node )
		DrawEdges(l_edges[j], l_edges[j]->getN2(), map, SGchild2);
	      else
		SGchild2->SetNodeType(ComputeNodeLabel(SGchild2));
	    }
	}
    }
}


##############################################################################

int IsAncestor(leda_node ancestor, leda_node child, int nMaxDist) const;

int ComputeMatchDeg(leda_node root, const DAG& g, const NODE_MAP& matchMap, 
						 leda_node& bestRoot, int& nMaxDeg) const;

leda_node GetBestMatchedSubtree(const DAG& g, const NODE_MAP& matchMap) const;

int DAG::IsAncestor(leda_node ancestor, leda_node child, int nMaxDist) const
{
	leda_edge e;

	if (nMaxDist == 0)
		return 0;

	forall_in_edges(e, child)
	{
		parent = source(e);

		if (parent == ancestor)
			return nMaxDist;
		else if (n = IsAncestor(ancestor, parent, nMaxDist - 1))
			return n;
	}

	return 0;
}

int DAG::ComputeMatchDeg(leda_node root, const DAG& g, const NODE_MAP& matchMap, 
						 leda_node& bestRoot, int& nMaxDeg) const
{
	int n = 0, childDeg;
	int nMaxDist = 2;

	forall_adj_nodes(v, root)
	{
		childDeg = ComputeMatchDeg(v);

		if (g.IsAncestor(matchMap[root], matchMap[v], nMaxDist))
			n += 1 + childDeg;
	}

	if (n > nMaxDeg)
	{
		nMaxDeg = n;
		bestRoot = root;
	}

	return n;
}

leda_node DAG::GetBestMatchedSubtree(const DAG& g, const NODE_MAP& matchMap) const
{
	leda_node root = GetFirstRoot();
	leda_node bestRoot;
	int nMaxDeg = 0;

	ComputeMatchDeg(root, g, matchMap, bestRoot, nMaxDeg);

	return bestRoot;
}

double TreeSimilarity(r1, r2)
{
	if (r1&r2 are leaves)
		return NodeSimilarity();
	else
		...
}

double Match()
{
	Construct bipartite graph with links on related nodes.

	BFS()
	{

	}
}