Пример #1
0
void StressMinimization::call(GraphAttributes& GA)
{
	const Graph& G = GA.constGraph();
	// if the graph has at most one node nothing to do
	if (G.numberOfNodes() <= 1) {
		// make it exception save
		for(node v : G.nodes)
		{
			GA.x(v) = 0;
			GA.y(v) = 0;
		}
		return;
	}
	if (m_componentLayout && !isConnected(G)) {
		OGDF_THROW(PreconditionViolatedException);
		return;
	}
	NodeArray<NodeArray<double> > shortestPathMatrix(G);
	NodeArray<NodeArray<double> > weightMatrix(G);
	initMatrices(G, shortestPathMatrix, weightMatrix);
	// if the edge costs are defined by the attribute copy it to an array and
	// construct the proper shortest path matrix
	if (m_hasEdgeCostsAttribute) {
		if (!GA.has(GraphAttributes::edgeDoubleWeight)) {
			OGDF_THROW(PreconditionViolatedException);
			return;
		}
		m_avgEdgeCosts = dijkstra_SPAP(GA, shortestPathMatrix);
		// compute shortest path all pairs
	} else {
		m_avgEdgeCosts = m_edgeCosts;
		bfs_SPAP(G, shortestPathMatrix, m_edgeCosts);
	}
	call(GA, shortestPathMatrix, weightMatrix);
}
Пример #2
0
void GmlParser::createObjectTree(istream &is, bool doCheck)
{
	initPredefinedKeys();
	m_error = false;
	m_objectTree = 0;

	m_is = &is;
	m_doCheck = doCheck; // indicates more extensive checking

	// initialize line buffer (note: GML specifies a maximal line length
	// of 254 characters!)
	m_rLineBuffer = new char[256];
	if (m_rLineBuffer == 0) OGDF_THROW(InsufficientMemoryException);

	*m_rLineBuffer = '\n';
	m_lineBuffer = m_rLineBuffer+1;

	m_pCurrent = m_pStore = m_lineBuffer;
	m_cStore = 0; // forces getNextSymbol() to read first line

	// create object tree
	m_objectTree = parseList(gmlEOF,gmlListEnd);
	
	delete[] m_rLineBuffer;
}
Пример #3
0
void PivotMDS::eigenValueDecomposition(
	Array<Array<double> >& K,
	Array<Array<double> >& eVecs,
	Array<double>& eValues)
{
	randomize(eVecs);
	const int p = K.size();
	double r = 0;
	for (int i = 0; i < DIMENSION_COUNT; i++) {
		eValues[i] = normalize(eVecs[i]);
	}
	while (r < EPSILON) {
        if (std::isnan(r) || isinf(r)) {
			// Throw arithmetic exception (Shouldn't occur
			// for DIMEMSION_COUNT = 2
			OGDF_THROW(AlgorithmFailureException);
			return;
		}
		// remember prev values
		Array<Array<double> > tmpOld(DIMENSION_COUNT);
		for (int i = 0; i < DIMENSION_COUNT; i++) {
			tmpOld[i].init(p);
			for (int j = 0; j < p; j++) {
				tmpOld[i][j] = eVecs[i][j];
				eVecs[i][j] = 0;
			}
		}
		// multiply matrices
		for (int i = 0; i < DIMENSION_COUNT; i++) {
			for (int j = 0; j < p; j++) {
				for (int k = 0; k < p; k++) {
					eVecs[i][k] += K[j][k] * tmpOld[i][j];
				}
			}
		}
		// orthogonalize
		for (int i = 0; i < DIMENSION_COUNT; i++) {
			for (int j = 0; j < i; j++) {
				double fac = prod(eVecs[j], eVecs[i])
						/ prod(eVecs[j], eVecs[j]);
				for (int k = 0; k < p; k++) {
					eVecs[i][k] -= fac * eVecs[j][k];
				}
			}
		}
		// normalize
		for (int i = 0; i < DIMENSION_COUNT; i++) {
			eValues[i] = normalize(eVecs[i]);
		}
		r = 1;
		for (int i = 0; i < DIMENSION_COUNT; i++) {
			// get absolute value (abs only defined for int)
			double tmp = prod(eVecs[i], tmpOld[i]);
			if (tmp < 0) {
				tmp *= -1;
			}
			r = min(r, tmp);
		}
	}
}
Пример #4
0
String::String(const char *str)
{
	m_length = strlen(str);
	m_pChar = new char[m_length+1];
	if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException);

	ogdf::strcpy(m_pChar,m_length+1,str);
}
Пример #5
0
String::String(size_t maxLen, const char *str)
{
	m_length = maxLen;
	m_pChar = new char[m_length+1];
	if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException);

	ogdf::strncpy(m_pChar, m_length+1, str, m_length);
	m_pChar[m_length] = '\0';
}
Пример #6
0
	//
	// C o n s t r u c t o r
	//
	DinoLineBuffer::DinoLineBuffer(const char *fileName) :
		m_pIs(0),
		m_pLinBuf(0),
		m_numberOfMostRecentlyReadLine(0),
		m_inputFileLineCounter(0)
	{
		// Open file
		m_pIs = new ifstream(fileName, ios::in);
		if (!(*m_pIs)) {
			DinoTools::reportError("DinoLineBuffer::DinoLineBuffer",
									__LINE__,
						           "Error opening file!");
		}

		// Create and initialize lineUpdateCountArray
		m_lineUpdateCountArray = new int[DinoLineBuffer::c_maxNoOfLines];
		int i;
		for (i = 0; i < DinoLineBuffer::c_maxNoOfLines; i++){
			m_lineUpdateCountArray[i] = 0;
		}

		// Create and initialize line buffer 
		m_pLinBuf = new char[(DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength)];
		if (m_pLinBuf == 0) 
			OGDF_THROW(InsufficientMemoryException);
		for (i = 0; i < DinoLineBuffer::c_maxNoOfLines * DinoLineBuffer::c_maxLineLength; i++){
			m_pLinBuf[i] = '0';
		}

		// Read first line
		if (!m_pIs->eof()){
			
			// Read first line
			m_pIs->getline(m_pLinBuf, DinoLineBuffer::c_maxLineLength);

			// Increase inputFileLineCounter
			++m_inputFileLineCounter;

			// Increase updateCount
			++(m_lineUpdateCountArray[0]);

		}
		// End of file is reached immeadiately
		else{

			// Set eof marker
			*m_pLinBuf = EOF;

		}

		// Set position
		m_currentPosition.set(0, m_lineUpdateCountArray[0], 0);

	} // DinoLineBuffer::DinoLineBuffer
Пример #7
0
// embeds constraint graph such that all sources and sinks lie in a common
// face
void CompactionConstraintGraphBase::embed()
{
	NodeArray<bool> onExternal(*this,false);
	const CombinatorialEmbedding &E = *m_pOR;
	face fExternal = E.externalFace();

	for(adjEntry adj : fExternal->entries)
		onExternal[m_pathNode[adj->theNode()]] = true;

	// compute lists of sources and sinks
	SList<node> sources, sinks;

	for(node v : nodes) {
		if (onExternal[v]) {
			if (v->indeg() == 0)
				sources.pushBack(v);
			if (v->outdeg() == 0)
				sinks.pushBack(v);
		}
	}

	// determine super source and super sink
	node s,t;
	if (sources.size() > 1)
	{
		s = newNode();
		for (node v : sources)
			newEdge(s,v);
	}
	else
		s = sources.front();

	if (sinks.size() > 1)
	{
		t = newNode();
		for (node v : sinks)
			newEdge(v,t);
	}
	else
		t = sinks.front();

	edge st = newEdge(s,t);

	bool isPlanar = planarEmbed(*this);
	if (!isPlanar) OGDF_THROW(AlgorithmFailureException);


	delEdge(st);
	if (sources.size() > 1)
		delNode(s);
	if (sinks.size() > 1)
		delNode(t);
}
Пример #8
0
String &String::operator =(const char *str)
{
	delete [] m_pChar;

	m_length = strlen(str);
	m_pChar = new char[m_length+1];
	if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException);

	ogdf::strcpy(m_pChar,m_length+1,str);

	return *this;
}
Пример #9
0
void String::sprintf(const char *format, ...)
{
	delete [] m_pChar;

	va_list argList;
	va_start(argList,format);

	m_length = ogdf::vsprintf(s_pBuffer,OGDF_STRING_BUFFER_SIZE,format,argList);
	m_pChar = new char[m_length+1];
	if (m_pChar == 0) OGDF_THROW(InsufficientMemoryException);

	ogdf::strcpy(m_pChar,m_length+1,s_pBuffer);
}
Пример #10
0
void PivotMDS::call(GraphAttributes& GA)
{
	if (!isConnected(GA.constGraph())) {
		OGDF_THROW_PARAM(PreconditionViolatedException,pvcConnected);
		return;
	}
	if (m_hasEdgeCostsAttribute
			&& !GA.has(GraphAttributes::edgeDoubleWeight)) {
				OGDF_THROW(PreconditionViolatedException);
		return;
	}
	pivotMDSLayout(GA);
}
Пример #11
0
	//
	// C o n s t r u c t o r
	//
	LineBuffer::LineBuffer(istream &is) :
		m_pIs(&is),
		m_pLinBuf(0),
		m_numberOfMostRecentlyReadLine(0),
		m_inputFileLineCounter(0)
	{
		if (!(*m_pIs)) {
			Logger::slout() << "LineBuffer::LineBuffer: Error opening file!\n";
			OGDF_THROW_PARAM(AlgorithmFailureException, afcUnknown);
		}

		// Create and initialize lineUpdateCountArray
		m_lineUpdateCountArray = new int[LineBuffer::c_maxNoOfLines];
		int i;
		for (i = 0; i < LineBuffer::c_maxNoOfLines; i++){
			m_lineUpdateCountArray[i] = 0;
		}

		// Create and initialize line buffer
		m_pLinBuf = new char[(LineBuffer::c_maxNoOfLines * LineBuffer::c_maxLineLength)];
		if (m_pLinBuf == 0)
			OGDF_THROW(InsufficientMemoryException);
		for (i = 0; i < LineBuffer::c_maxNoOfLines * LineBuffer::c_maxLineLength; i++){
			m_pLinBuf[i] = '0';
		}

		// Read first line
		if (!m_pIs->eof()){

			// Read first line
			m_pIs->getline(m_pLinBuf, LineBuffer::c_maxLineLength);

			// Increase inputFileLineCounter
			++m_inputFileLineCounter;

			// Increase updateCount
			++(m_lineUpdateCountArray[0]);

		}
		// End of file is reached immeadiately
		else{

			// Set eof marker
			*m_pLinBuf = EOF;

		}

		// Set position
		m_currentPosition.set(0, m_lineUpdateCountArray[0], 0);

	} // LineBuffer::LineBuffer
Пример #12
0
	//
	// C o n s t r u c t o r
	//
	DinoXmlScanner::DinoXmlScanner(const char *fileName)
	{
		// Create line buffer
		m_pLineBuffer = new DinoLineBuffer(fileName);

		// Create current token string
		m_pCurrentTokenString = new char[DinoLineBuffer::c_maxStringLength];
		if (m_pCurrentTokenString == 0) 
			OGDF_THROW(InsufficientMemoryException);
		for (int i = 0; i < DinoLineBuffer::c_maxStringLength; i++){
			m_pCurrentTokenString[i] = '0';
		}

	} // DinoXmlScanner::DinoXmlScanner
Пример #13
0
void ModularMultilevelMixer::call(MultilevelGraph &MLG)
{
	const Graph &G = MLG.getGraph();

	m_errorCode = ercNone;
	clock_t time = clock();
	if ((m_multilevelBuilder.valid() == false || m_initialPlacement.valid() == false) && m_oneLevelLayoutModule.valid() == false) {
		OGDF_THROW(AlgorithmFailureException);
	}

	if (m_fixedEdgeLength > 0.0) {
		edge e;
		forall_edges(e,G) {
			MLG.weight(e, m_fixedEdgeLength);
		}
Пример #14
0
void Constraint::generateIndent(char ** indent, const int & indentSize) 
{
	// free memory block (INFO: indent must point to an array of chars or to NULL)
	delete [] *indent;
	// instantiate array of chars
	*indent = new char[indentSize + 1];
	// if memory couldn't be allocated, we throw an exception
	if (!*indent) {
		OGDF_THROW(InsufficientMemoryException); // don't use regular throw!
	}
	// fill char array
	for(int i = 0; i < indentSize; ++i) {
		(*indent)[i] = INDENTCHAR;
	}
	// terminate string
	(*indent)[indentSize] = '\0';
}
Пример #15
0
MultilevelGraph::MultilevelGraph()
:m_createdGraph(true)
{
	m_G = new Graph();
	if(m_G == nullptr) {
		OGDF_THROW(InsufficientMemoryException);
	}

	//replaces layout info stuff below
	initInternal();

	m_nodeAssociations.init(*m_G, 0);
	m_edgeAssociations.init(*m_G, 0);
	m_radius.init(*m_G, 1.0);
	m_weight.init(*m_G, 1.0);

	initReverseIndizes();
}
Пример #16
0
MultilevelGraph::MultilevelGraph()
:m_createdGraph(false)
{
	m_G = new Graph();
	if(m_G == 0) {
		OGDF_THROW(InsufficientMemoryException);
	} else {
		m_createdGraph = true;
	}
	m_nodeAssociations.init(*m_G, 0);
	m_edgeAssociations.init(*m_G, 0);
	m_x.init(*m_G, 0);
	m_y.init(*m_G, 0);
	m_radius.init(*m_G, 1.0);
	m_weight.init(*m_G, 1.0);

	initReverseIndizes();
}
Пример #17
0
String &String::operator +=(const String &str)
{
	size_t oldLength = m_length;
	char *pOldChar = m_pChar;

	m_length += str.m_length;
	m_pChar = new char[m_length+1];
	if (m_pChar == 0) {
		delete [] pOldChar;
		OGDF_THROW(InsufficientMemoryException);
	}

	ogdf::strcpy(m_pChar,m_length+1,pOldChar);
	ogdf::strcpy(m_pChar+oldLength,m_length+1-oldLength,str.m_pChar);

	delete [] pOldChar;

	return *this;
}
Пример #18
0
MultilevelGraph::MultilevelGraph(const String &filename)
:m_createdGraph(true)
{
	m_G = new Graph();
	if(m_G == 0) {
		OGDF_THROW(InsufficientMemoryException);
	} 
	m_nodeAssociations.init(*m_G);
	m_edgeAssociations.init(*m_G);
	m_radius.init(*m_G);
	m_weight.init(*m_G);

	initInternal();
	//GraphAttributes tempGA(*m_G);
	m_GA->readGML(*m_G, filename);
	prepareGraphAttributes(*m_GA);
	importAttributesSimple(*m_GA);

	initReverseIndizes();
}
Пример #19
0
MultilevelGraph::MultilevelGraph(GraphAttributes &GA)
:m_createdGraph(false)
{
	m_G = new Graph();
	if(m_G == 0) {
		OGDF_THROW(InsufficientMemoryException);
	} else {
		m_createdGraph = true;
	}
	m_nodeAssociations.init(*m_G);
	m_edgeAssociations.init(*m_G);
	m_x.init(*m_G);
	m_y.init(*m_G);
	m_radius.init(*m_G);
	m_weight.init(*m_G);
	copyFromGraph(GA.constGraph(), m_nodeAssociations, m_edgeAssociations);
	prepareGraphAttributes(GA);
	importAttributes(GA);

	initReverseIndizes();
}
Пример #20
0
MultilevelGraph::MultilevelGraph(const char *filename) : m_createdGraph(true)
{
	m_G = new Graph();
	if(m_G == nullptr) {
		OGDF_THROW(InsufficientMemoryException);
	}
	m_nodeAssociations.init(*m_G);
	m_edgeAssociations.init(*m_G);
	m_radius.init(*m_G);
	m_weight.init(*m_G);

	initInternal();
#if 0
	GraphAttributes tempGA(*m_G);
#endif
	GraphIO::read(*m_GA, *m_G, filename, GraphIO::readGML);
	prepareGraphAttributes(*m_GA);
	importAttributesSimple(*m_GA);

	initReverseIndizes();
}
Пример #21
0
MultilevelGraph::MultilevelGraph(GraphAttributes &GA)
:m_createdGraph(true)
{
	m_G = new Graph();
	if(m_G == 0) {
		OGDF_THROW(InsufficientMemoryException);
	} 
	
	//replaces layout info stuff below
	initInternal();

	m_nodeAssociations.init(*m_G);
	m_edgeAssociations.init(*m_G);
	m_radius.init(*m_G);
	m_weight.init(*m_G);
	copyFromGraph(GA.constGraph(), m_nodeAssociations, m_edgeAssociations);
	prepareGraphAttributes(GA);
	importAttributes(GA);

	initReverseIndizes();
}
Пример #22
0
MultilevelGraph::MultilevelGraph(istream &is)
:m_createdGraph(false)
{
	m_G = new Graph();
	if(m_G == 0) {
		OGDF_THROW(InsufficientMemoryException);
	} else {
		m_createdGraph = true;
	}
	m_nodeAssociations.init(*m_G);
	m_edgeAssociations.init(*m_G);
	m_x.init(*m_G);
	m_y.init(*m_G);
	m_radius.init(*m_G);
	m_weight.init(*m_G);
	GraphAttributes tempGA(*m_G);
	tempGA.readGML(*m_G, is);
	prepareGraphAttributes(tempGA);
	importAttributesSimple(tempGA);

	initReverseIndizes();
}
Пример #23
0
//the call function that lets ClusterPlanarizationLayout compute a layout
//for the input using \a weight for the computation of the cluster planar subgraph
void ClusterPlanarizationLayout::call(
	Graph& G,
	ClusterGraphAttributes& acGraph,
	ClusterGraph& cGraph,
	EdgeArray<double>& edgeWeight,
	bool simpleCConnect) //default true
{
	m_nCrossings = 0;
	bool subGraph = false; // c-planar subgraph computed?

	//check some simple cases
	if (G.numberOfNodes() == 0) return;

//-------------------------------------------------------------
//we set pointers and arrays to the working graph, which can be
//the original or, in the case of non-c-planar input, a copy

	Graph* workGraph = &G;
	ClusterGraph* workCG = &cGraph;
	ClusterGraphAttributes* workACG = &acGraph;

	//potential copy of original if non c-planar
	Graph GW;
	//list of non c-planarity causing edges
	List<edge> leftEdges;

	//list of nodepairs to be connected (deleted edges)
	List<NodePair> leftWNodes;

	//store some information
	//original to copy
	NodeArray<node> resultNode(G);
	EdgeArray<edge> resultEdge(G);
	ClusterArray<cluster> resultCluster(cGraph);
	//copy to original
	NodeArray<node> orNode(G);
	EdgeArray<edge> orEdge(G);
	ClusterArray<cluster> orCluster(cGraph);

	for(node workv : G.nodes) {
		resultNode[workv] = workv; //will be set to copy if non-c-planar
		orNode[workv] = workv;
	}
	for(edge worke : G.edges) {
		resultEdge[worke] = worke; //will be set to copy if non-c-planar
		orEdge[worke] = worke;
	}
	for (cluster workc : cGraph.clusters) {
		resultCluster[workc] = workc; //will be set to copy if non-c-planar
		orCluster[workc] = workc;
	}


	//-----------------------------------------------
	//check if instance is clusterplanar and embed it
	CconnectClusterPlanarEmbed CCPE; //cccp

	bool cplanar = CCPE.embed(cGraph, G);

	List<edge> connectEdges;

	//if the graph is not c-planar, we have to check the reason and to
	//correct the problem by planarising or inserting connection edges
	if (!cplanar)
	{
		bool connect = false;

		if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) ||
				(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) )
		{
			//we insert edges to make the input c-connected
			makeCConnected(cGraph, G, connectEdges, simpleCConnect);

			//save edgearray info for inserted edges
			for(edge e : connectEdges)
			{
				resultEdge[e] = e;
				orEdge[e]     = e;
			}

			connect = true;

			CCPE.embed(cGraph, G);

			if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) ||
				(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) )
			{
				cerr << "no correct connection made\n"<<flush;
				OGDF_THROW(AlgorithmFailureException);
			}
		}//if not cconnected
		if ((CCPE.errCode() == CconnectClusterPlanarEmbed::nonPlanar) ||
			(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCPlanar))
		{
			subGraph = true;
			EdgeArray<bool> inSubGraph(G, false);

			CPlanarSubClusteredGraph cps;
			if (edgeWeight.valid())
				cps.call(cGraph, inSubGraph, leftEdges, edgeWeight);
			else
				cps.call(cGraph, inSubGraph, leftEdges);
#ifdef OGDF_DEBUG
			//			for(edge worke : G.edges) {
			//				if (inSubGraph[worke])
			//					acGraph.strokeColor(worke) = "#FF0000";
			//			}
#endif
			//---------------------------------------------------------------
			//now we delete the copies of all edges not in subgraph and embed
			//the subgraph (use a new copy)

			//construct copy

			workGraph = &GW;
			workCG = new ClusterGraph(cGraph, GW, resultCluster, resultNode, resultEdge);

			//----------------------
			//reinit original arrays
			orNode.init(GW, nullptr);
			orEdge.init(GW, nullptr);
			orCluster.init(*workCG, nullptr);

			//set array entries to the appropriate values
			for (node workv : G.nodes)
				orNode[resultNode[workv]] = workv;
			for (edge worke : G.edges)
				orEdge[resultEdge[worke]] = worke;
			for (cluster workc : cGraph.clusters)
				orCluster[resultCluster[workc]] = workc;

			//----------------------------------------------------
			//create new ACG and copy values (width, height, type)

			workACG = new ClusterGraphAttributes(*workCG, workACG->attributes());
			for (node workv : GW.nodes)
			{
				//should set same attributes in construction!!!
				if (acGraph.attributes() & GraphAttributes::nodeType)
					workACG->type(workv) = acGraph.type(orNode[workv]);
				workACG->height(workv) = acGraph.height(orNode[workv]);
				workACG->width(workv) = acGraph.width(orNode[workv]);
			}
			if (acGraph.attributes() & GraphAttributes::edgeType) {
				for (edge worke : GW.edges) {
					workACG->type(worke) = acGraph.type(orEdge[worke]);
					//all other attributes are not needed or will be set
				}
			}

			for(edge ei : leftEdges)
			{
				edge e = resultEdge[ei];
				NodePair np;
				np.m_src = e->source();
				np.m_tgt = e->target();

				leftWNodes.pushBack(np);

				GW.delEdge(e);
			}

			CconnectClusterPlanarEmbed CCP;

#ifdef OGDF_DEBUG
			bool subPlanar =
#endif
				CCP.embed(*workCG, GW);
			OGDF_ASSERT(subPlanar);
		}//if not planar
		else
		{
			if (!connect)
			OGDF_THROW_PARAM(PreconditionViolatedException, pvcClusterPlanar);
		}

	}//if

	//if multiple CCs are handled, the connectedges (their copies resp.)
	//can be deleted here

	//now CCPE should give us the external face

	ClusterPlanRep CP(*workACG, *workCG);

	OGDF_ASSERT(CP.representsCombEmbedding());

	const int numCC = CP.numberOfCCs(); //equal to one
	//preliminary
	OGDF_ASSERT(numCC == 1);

	// (width,height) of the layout of each connected component
	Array<DPoint> boundingBox(numCC);

	for (int ikl = 0; ikl < numCC; ikl++)
	{

			CP.initCC(ikl);
			CP.setOriginalEmbedding();

			OGDF_ASSERT(CP.representsCombEmbedding())

			Layout drawing(CP);

			//m_planarLayouter.get().setOptions(4);//progressive

			adjEntry ae = nullptr;

			//internally compute adjEntry for outer face

			//edges that are reinserted in workGraph (in the same
			//order as leftWNodes)
			List<edge> newEdges;
			m_planarLayouter.get().call(CP, ae, drawing, leftWNodes, newEdges, *workGraph);

			OGDF_ASSERT(leftWNodes.size()==newEdges.size())
			OGDF_ASSERT(leftEdges.size()==newEdges.size())

			ListConstIterator<edge> itE = newEdges.begin();
			ListConstIterator<edge> itEor = leftEdges.begin();
			while (itE.valid())
			{
				orEdge[*itE] = *itEor;
				++itE;
				++itEor;
			}

			//hash index over cluster ids
			HashArray<int, ClusterPosition> CA;

			computeClusterPositions(CP, drawing, CA);

			// copy layout into acGraph
			// Later, we move nodes and edges in each connected component, such
			// that no two overlap.

			for(int i = CP.startNode(); i < CP.stopNode(); ++i) {
				node vG = CP.v(i);

				acGraph.x(orNode[vG]) = drawing.x(CP.copy(vG));
				acGraph.y(orNode[vG]) = drawing.y(CP.copy(vG));

				for(adjEntry adj : vG->adjEdges)
				{
					if ((adj->index() & 1) == 0) continue;
					edge eG = adj->theEdge();

					edge orE = orEdge[eG];
					if (orE)
						drawing.computePolylineClear(CP,eG,acGraph.bends(orE));
				}

			}//for

			//even assignment for all nodes is not enough, we need all clusters
			for(cluster c : workCG->clusters)
			{
				int clNumber = c->index();
				//int orNumber = originalClId[c];
				cluster orCl = orCluster[c];

				if (c != workCG->rootCluster())
				{
					OGDF_ASSERT(CA.isDefined(clNumber));
					acGraph.height(orCl) = CA[clNumber].m_height;
					acGraph.width(orCl) = CA[clNumber].m_width;
					acGraph.y(orCl) = CA[clNumber].m_miny;
					acGraph.x(orCl) = CA[clNumber].m_minx;
				}//if real cluster
			}

			// the width/height of the layout has been computed by the planar
			// layout algorithm; required as input to packing algorithm
			boundingBox[ikl] = m_planarLayouter.get().getBoundingBox();

	}//for connected components

	//postProcess(acGraph);
	//
	// arrange layouts of connected components
	//

	Array<DPoint> offset(numCC);

	m_packer.get().call(boundingBox,offset,m_pageRatio);

	// The arrangement is given by offset to the origin of the coordinate
	// system. We still have to shift each node, edge and cluster by the offset
	// of its connected component.

	const Graph::CCsInfo &ccInfo = CP.ccInfo();
	for(int i = 0; i < numCC; ++i)
	{
		const double dx = offset[i].m_x;
		const double dy = offset[i].m_y;

		HashArray<int, bool> shifted(false);

		// iterate over all nodes in ith CC
		for(int j = ccInfo.startNode(i); j < ccInfo.stopNode(i); ++j)
		{
			node v = ccInfo.v(j);

			acGraph.x(orNode[v]) += dx;
			acGraph.y(orNode[v]) += dy;

			// update cluster positions accordingly
			//int clNumber = cGraph.clusterOf(orNode[v])->index();
			cluster cl = cGraph.clusterOf(orNode[v]);

			if ((cl->index() > 0) && !shifted[cl->index()])
			{
				acGraph.y(cl) += dy;
				acGraph.x(cl) += dx;
				shifted[cl->index()] = true;
			}//if real cluster

			for(adjEntry adj : v->adjEdges) {
				if ((adj->index() & 1) == 0) continue;
				edge e = adj->theEdge();

				//edge eOr = orEdge[e];
				if (orEdge[e])
				{
					DPolyline &dpl = acGraph.bends(orEdge[e]);
					for(DPoint &p : dpl) {
						p.m_x += dx;
						p.m_y += dy;
					}
				}
			}
		}//for nodes
	}//for numcc


	while (!connectEdges.empty()) {
		G.delEdge(connectEdges.popFrontRet());
	}

	if (subGraph)
	{
		//originalClId.init();
		orCluster.init();
		orNode.init();
		orEdge.init();
		delete workCG;
		delete workACG;
	}//if subgraph created

	acGraph.removeUnnecessaryBendsHV();

}//call
Пример #24
0
//
// p a r s e
//
// Take a look at the state machine of parse() to understand
// what is going on here.
//
// TODO: It seems to be useful that this function throws an exception
//       if something goes wrong.
XmlTagObject *XmlParser::parse()
{
    // Increment recursion depth
    ++m_recursionDepth;

    // currentTagObject is the tag object we want to create
    // in this invocation of parse()
    XmlTagObject *currentTagObject = 0;

    // Now we are in the start state of the state machine
    for( ; ; )
    {
        XmlToken token = m_pScanner->getNextToken();

        // Expect "<", otherwise failure
        if (token != openingBracket) {
            reportError("XmlParser::parse",
                        __LINE__,
                        "Opening Bracket expected!",
                        getInputFileLineCounter());
        }

        // Let's look what comes after "<"
        token = m_pScanner->getNextToken();

        // Read "?", i.e. we have the XML header line <? ... ?>
        if (token == questionMark) {

            // Skip until we reach the matching question mark
            if (!m_pScanner->skipUntil('?')) {
                reportError("XmlParser::parse",
                            __LINE__,
                            "Could not found the matching '?'",
                            getInputFileLineCounter());
            }

            // Consume ">", otherwise failure
            token = m_pScanner->getNextToken();
            if (token != closingBracket) {
                reportError("XmlParser::parse",
                            __LINE__,
                            "Closing Bracket expected!",
                            getInputFileLineCounter());
            }

            // Go to start state of the state machine
            continue;

        } // end of Read "?"

        // Read "!", i.e. we have a XML comment <!-- bla -->
        if (token == exclamationMark) {

            // A preambel comment <!lala > which could be also nested
            if ((m_pScanner->getNextToken() != minus) ||
                    (m_pScanner->getNextToken() != minus))
            {
                if (!m_pScanner->skipUntilMatchingClosingBracket()) {

                    reportError("XmlParser::parse",
                                __LINE__,
                                "Could not find closing comment bracket!",
                                getInputFileLineCounter());
                }

                continue;
            }

            // Find end of comment
            bool endOfCommentFound = false;
            while (!endOfCommentFound) {

                // Skip until we find a - (and skip over it)
                if (!m_pScanner->skipUntil('-', true)) {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Closing --> of comment not found!",
                                getInputFileLineCounter());
                }

                // The next characters must be -> (note that one minus is already consumed)
                if ((m_pScanner->getNextToken() == minus) &&
                        (m_pScanner->getNextToken() == closingBracket))
                {
                    endOfCommentFound = true;
                }

            } // while

            // Go to start state of the state machine
            continue;

        } // end of Read "!"

        // We have found an identifier, i.e. a tag name
        if (token == identifier) {

            // Get hash element of token string
            HashedString *tagName =
                hashString(m_pScanner->getCurrentTokenString());

            // Create new tag object
            currentTagObject = new XmlTagObject(tagName);
            if (currentTagObject == 0) {
                OGDF_THROW(InsufficientMemoryException);
            }
            //push (opening) tagName to stack
            m_tagObserver.push(tagName->key());
            // set depth of current tag object
            currentTagObject->setDepth(m_recursionDepth);

            // set line of the tag object in the parsed xml document
            currentTagObject->setLine(getInputFileLineCounter());

            // Next token
            token = m_pScanner->getNextToken();

            // Again we found an identifier, so it must be an attribute
            if (token == identifier) {

                // Read list of attributes
                do {
                    // Save the attribute name
                    HashedString *attributeName =
                        hashString(m_pScanner->getCurrentTokenString());

                    // Consume "=", otherwise failure
                    token = m_pScanner->getNextToken();
                    if (token != equalSign)
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Equal Sign expected!",
                                    getInputFileLineCounter());
                    }

                    // Read value
                    token = m_pScanner->getNextToken();
                    if ((token != quotedValue) &&
                            (token != identifier) &&
                            (token != attributeValue))
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "No valid attribute value!",
                                    getInputFileLineCounter());
                    }

                    // Create a new XmlAttributeObject
                    XmlAttributeObject *currentAttributeObject =
                        new XmlAttributeObject(attributeName, hashString(m_pScanner->getCurrentTokenString()));
                    if (currentAttributeObject == 0) {
                        OGDF_THROW(InsufficientMemoryException);
                    }

                    // Append attribute to attribute list of the current tag object
                    appendAttributeObject(currentTagObject, currentAttributeObject);

                    // Get next token
                    token = m_pScanner->getNextToken();

                }
                while (token == identifier);

            } // Found an identifier of an attribute

            // Read "/", i.e. the tag is ended immeadiately, e.g.
            // <A ... /> without a closing tag </A>
            if (token == slash) {

                // Consume ">", otherwise failure
                token = m_pScanner->getNextToken();
                if (token != closingBracket)
                {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Closing Bracket expected!",
                                getInputFileLineCounter());
                }

                // The tag is closed and ended so we return
                string s = m_tagObserver.pop();
                --m_recursionDepth;
                return currentTagObject;

            } // end of Read "/"

            // Read ">", i.e. the tag is closed and we
            // expect some content
            if (token == closingBracket) {

                // We read something different from "<", so we have to
                // deal with a tag value now, i.e. a string inbetween the
                // opening and the closing tag, e.g. <A ...> lalala </A>
                if (m_pScanner->testNextToken() != openingBracket) {

                    // Read the characters until "<" is reached and put them into
                    // currentTagObject
                    m_pScanner->readStringUntil('<');
                    currentTagObject->m_pTagValue = hashString(m_pScanner->getCurrentTokenString());

                    // We expect a closing tag now, i.e. </id>
                    token = m_pScanner->getNextToken();
                    if (token != openingBracket)
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Opening Bracket expected!",
                                    getInputFileLineCounter());
                    }

                    token = m_pScanner->getNextToken();
                    if (token != slash)
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Slash expected!",
                                    getInputFileLineCounter());
                    }

                    token = m_pScanner->getNextToken();
                    if (token != identifier)
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Identifier expected!",
                                    getInputFileLineCounter());
                    }

                    // next token is the closing tag
                    string nextTag(m_pScanner->getCurrentTokenString());
                    // pop corresponding tag from stack
                    string s = m_tagObserver.pop();
                    // compare the two tags
                    if (s != nextTag)
                    {
                        // the closing tag doesn't correspond to the opening tag:
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "wrong closing tag!",
                                    getInputFileLineCounter());
                    }

                    token = m_pScanner->getNextToken();
                    if (token != closingBracket)
                    {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Closing Bracket expected!",
                                    getInputFileLineCounter());
                    }

                    // The tag is closed so we return
                    --m_recursionDepth;
                    return currentTagObject;

                } // end of read something different from "<"

                // Found "<", so a (series of) new tag begins and we have to perform
                // recursive invocation of parse()
                //
                // There are two exceptions:
                // - a slash follows afer <, i.e. we have a closing tag
                // - an exclamation mark follows after <, i.e. we have a comment
                while (m_pScanner->testNextToken() == openingBracket) {

                    // Leave the while loop if a closing tag occurs
                    if (m_pScanner->testNextNextToken() == slash) {
                        break;
                    }

                    // Ignore comments
                    if (m_pScanner->testNextNextToken() == exclamationMark) {

                        // Comment must start with <!--
                        if ((m_pScanner->getNextToken() != openingBracket) ||
                                (m_pScanner->getNextToken() != exclamationMark) ||
                                (m_pScanner->getNextToken() != minus) ||
                                (m_pScanner->getNextToken() != minus))
                        {
                            reportError("XmlParser::parse",
                                        __LINE__,
                                        "Comment must start with <!--",
                                        getInputFileLineCounter());
                        }

                        // Find end of comment
                        bool endOfCommentFound = false;
                        while (!endOfCommentFound) {

                            // Skip until we find a - (and skip over it)
                            if (!m_pScanner->skipUntil('-', true)) {
                                reportError("XmlParser::parse",
                                            __LINE__,
                                            "Closing --> of comment not found!",
                                            getInputFileLineCounter());
                            }

                            // The next characters must be -> (note that one minus is already consumed)
                            if ((m_pScanner->getNextToken() == minus) &&
                                    (m_pScanner->getNextToken() == closingBracket))
                            {
                                endOfCommentFound = true;
                            }

                        } // while

                        // Proceed with outer while loop
                        continue;

                    } // Ignore comments

                    // The new tag object is a son of the current tag object
                    XmlTagObject *sonTagObject = parse();
                    appendSonTagObject(currentTagObject, sonTagObject);

                } // while

                // Now we have found all tags.
                // We expect a closing tag now, i.e. </id>
                token = m_pScanner->getNextToken();
                if (token != openingBracket)
                {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Opening Bracket expected!",
                                getInputFileLineCounter());
                }

                token = m_pScanner->getNextToken();
                if (token != slash)
                {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Slash expected!",
                                getInputFileLineCounter());
                }

                token = m_pScanner->getNextToken();
                if (token != identifier)
                {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Identifier expected!",
                                getInputFileLineCounter());
                }

                // next token is the closing tag
                string nextTag(m_pScanner->getCurrentTokenString());
                // pop corresponding tag from stack
                string s = m_tagObserver.pop();
                // compare the two tags
                if (s != nextTag)
                {
                    // the closing tag doesn't correspond to the opening tag:
                    reportError("XmlParser::parse",
                                __LINE__,
                                "wrong closing tag!",
                                getInputFileLineCounter());
                }

                token = m_pScanner->getNextToken();
                if (token != closingBracket)
                {
                    reportError("XmlParser::parse",
                                __LINE__,
                                "Closing Bracket expected!",
                                getInputFileLineCounter());
                }

                --m_recursionDepth;

                // check if Document contains code after the last closing bracket
                if (m_recursionDepth == 0) {
                    token = m_pScanner->getNextToken();
                    if (token != endOfFile) {
                        reportError("XmlParser::parse",
                                    __LINE__,
                                    "Document contains code after the last closing bracket!",
                                    getInputFileLineCounter());
                    }
                }

                return currentTagObject;

            } // end of Read ">"

            OGDF_ASSERT(false)
            //continue;

        } // end of found identifier

        OGDF_ASSERT(false)

    } // end of while (true)
Пример #25
0
GmlObject *GmlParser::parseList(GmlObjectType closingKey,
	GmlObjectType /* errorKey */)
{
	GmlObject *firstSon = nullptr;
	GmlObject **pPrev = &firstSon;

	for( ; ; ) {
		GmlObjectType symbol = getNextSymbol();

		if (symbol == closingKey || symbol == gmlError)
			return firstSon;

		if (symbol != gmlKey) {
			setError("key expected");
			return firstSon;
		}

		GmlKey key = m_keySymbol;

		symbol = getNextSymbol();
		GmlObject *object = nullptr;

		switch (symbol) {
		case gmlIntValue:
			object = OGDF_NEW GmlObject(key,m_intSymbol);
			break;

		case gmlDoubleValue:
			object = OGDF_NEW GmlObject(key,m_doubleSymbol);
			break;

		case gmlStringValue: {
			size_t len = strlen(m_stringSymbol)+1;
			char *pChar = new char[len];
			if (pChar == nullptr) OGDF_THROW(InsufficientMemoryException);

			strcpy(pChar,m_stringSymbol);
			object = OGDF_NEW GmlObject(key,pChar); }
			break;

		case gmlListBegin:
			object = OGDF_NEW GmlObject(key);
			object->m_pFirstSon = parseList(gmlListEnd,gmlEOF);
			break;

		case gmlListEnd:
			setError("unexpected end of list");
			return firstSon;

		case gmlKey:
			setError("unexpected key");
			return firstSon;

		case gmlEOF:
			setError("missing value");
			return firstSon;

		case gmlError:
			return firstSon;

		OGDF_NODEFAULT // one of the cases above has to occur
		}

		*pPrev = object;
		pPrev = &object->m_pBrother;
	}

	return firstSon;
}
Пример #26
0
void MultilevelLayout::call(GraphAttributes &GA, GraphConstraints &GC)
{
	//we assume that both structures work on the same graph

	OGDF_THROW(AlgorithmFailureException);
}
Пример #27
0
	//--------------------------------------------------------------------
	// actual algorithm call
	//--------------------------------------------------------------------
	Module::ReturnType FixEdgeInserterCore::call(
		const Array<edge> &origEdges,
		bool keepEmbedding,
		RemoveReinsertType rrPost,
		double percentMostCrossed)
	{
		double T;
		usedTime(T);

		Module::ReturnType retValue = Module::retFeasible;
		m_runsPostprocessing = 0;

		if(!keepEmbedding) m_pr.embed();
		OGDF_ASSERT(m_pr.representsCombEmbedding() == true);

		if (origEdges.size() == 0)
			return Module::retOptimal;  // nothing to do

		// initialization
		CombinatorialEmbedding E(m_pr);  // embedding of PG

		init(E);
		constructDual(E);

		// m_delFaces and m_newFaces are used by removeEdge()
		// if we can't allocate memory for them, we throw an exception
		if (rrPost != rrNone) {
			m_delFaces = new FaceSetSimple(E);
			if (m_delFaces == nullptr)
				OGDF_THROW(InsufficientMemoryException);

			m_newFaces = new FaceSetPure(E);
			if (m_newFaces == nullptr) {
				delete m_delFaces;
				OGDF_THROW(InsufficientMemoryException);
			}

		// no postprocessing -> no removeEdge()
		} else {
			m_delFaces = nullptr;
			m_newFaces = nullptr;
		}

		SListPure<edge> currentOrigEdges;
		if(rrPost == rrIncremental) {
			for(edge e : m_pr.edges)
				currentOrigEdges.pushBack(m_pr.original(e));
		}

		// insertion of edges
		bool doIncrementalPostprocessing =
			( rrPost == rrIncremental || rrPost == rrIncInserted );
		for(int i = origEdges.low(); i <= origEdges.high(); ++i)
		{
			edge eOrig = origEdges[i];
			storeTypeOfCurrentEdge(eOrig);
			//int eSubGraph = 0;  // edgeSubGraphs-data of eOrig
			//if(edgeSubGraphs!=0) eSubGraph = (*edgeSubGraphs)[eOrig];

			SList<adjEntry> crossed;
			if(m_pCost != nullptr) {
				findWeightedShortestPath(E, eOrig, crossed);
			} else {
				findShortestPath(E, eOrig, crossed);
			}

			insertEdge(E, eOrig, crossed);

			if(doIncrementalPostprocessing) {
				currentOrigEdges.pushBack(eOrig);

				bool improved;
				do {
					++m_runsPostprocessing;
					improved = false;

					for (edge eOrigRR : currentOrigEdges)
					{
						int pathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						if (pathLength == 0) continue; // cannot improve

						removeEdge(E, eOrigRR);

						storeTypeOfCurrentEdge(eOrigRR);

						// try to find a better insertion path
						SList<adjEntry> crossed;
						if(m_pCost != nullptr) {
							findWeightedShortestPath(E, eOrigRR, crossed);
						} else {
							findShortestPath(E, eOrigRR, crossed);
						}

						// re-insert edge (insertion path cannot be longer)
						insertEdge(E, eOrigRR, crossed);

						int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						OGDF_ASSERT(newPathLength <= pathLength);

						if(newPathLength < pathLength)
							improved = true;
					}
				} while (improved);
			}
		}

		if(!doIncrementalPostprocessing) {
			// postprocessing (remove-reinsert heuristc)
			const int m = m_pr.original().numberOfEdges();
			SListPure<edge> rrEdges;

			switch(rrPost)
			{
			case rrAll:
			case rrMostCrossed:
				for(int i = m_pr.startEdge(); i < m_pr.stopEdge(); ++i)
					rrEdges.pushBack(m_pr.e(i));
				break;

			case rrInserted:
				for(int i = origEdges.low(); i <= origEdges.high(); ++i)
					rrEdges.pushBack(origEdges[i]);
				break;

			case rrNone:
			case rrIncremental:
			case rrIncInserted:
				break;
			}

			// marks the end of the interval of rrEdges over which we iterate
			// initially set to invalid iterator which means all edges
			SListConstIterator<edge> itStop;

			bool improved;
			do {
				// abort postprocessing if time limit reached
				if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) {
					retValue = Module::retTimeoutFeasible;
					break;
				}

				++m_runsPostprocessing;
				improved = false;

				if(rrPost == rrMostCrossed)
				{
					FEICrossingsBucket bucket(&m_pr);
					rrEdges.bucketSort(bucket);

					const int num = int(0.01 * percentMostCrossed * m);
					itStop = rrEdges.get(num);
				}

				SListConstIterator<edge> it;
				for(it = rrEdges.begin(); it != itStop; ++it)
				{
					edge eOrig = *it;

					int pathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					if (pathLength == 0) continue; // cannot improve

					removeEdge(E, eOrig);

					storeTypeOfCurrentEdge(eOrig);

					// try to find a better insertion path
					SList<adjEntry> crossed;
					if(m_pCost != nullptr) {
						findWeightedShortestPath(E, eOrig, crossed);
					} else {
						findShortestPath(E, eOrig, crossed);
					}

					// re-insert edge (insertion path cannot be longer)
					insertEdge(E, eOrig, crossed);

					// we cannot find a shortest path that is longer than before!
					int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					OGDF_ASSERT(newPathLength <= pathLength);

					if(newPathLength < pathLength)
						improved = true;
				}
			} while (improved);
		}

		// verify computed planarization
		OGDF_ASSERT(m_pr.representsCombEmbedding());

		// free resources
		cleanup();

		return retValue;
	}
Пример #28
0
//---------------------------------------------------------
// actual call (called by all variations of call)
//   crossing of generalizations is forbidden if forbidCrossingGens = true
//   edge costs are obeyed if costOrig != 0
//
Module::ReturnType FixedEmbeddingInserter::doCall(
	PlanRep &PG,
	const List<edge> &origEdges,
	bool forbidCrossingGens,
	const EdgeArray<int>  *costOrig,
	const EdgeArray<bool> *forbiddenEdgeOrig,
	const EdgeArray<unsigned int> *edgeSubGraph)
{
  
	double T;
	usedTime(T);
	
	ReturnType retValue = retFeasible;
	m_runsPostprocessing = 0;

	PG.embed(); 
	OGDF_ASSERT(PG.representsCombEmbedding() == true);

	if (origEdges.size() == 0)
		return retOptimal;  // nothing to do

	// initialization
	CombinatorialEmbedding E(PG);  // embedding of PG

	m_dual.clear();
	m_primalAdj.init(m_dual);
	m_nodeOf.init(E);

	// construct dual graph
	m_primalIsGen.init(m_dual,false);

	OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0);

	if(forbidCrossingGens)
		constructDualForbidCrossingGens((const PlanRepUML&)PG,E);
	else
		constructDual(PG,E,forbiddenEdgeOrig);

	// m_delFaces and m_newFaces are used by removeEdge()
	// if we can't allocate memory for them, we throw an exception
	if (removeReinsert() != rrNone) {
		m_delFaces = new FaceSetSimple(E);
		if (m_delFaces == 0)
			OGDF_THROW(InsufficientMemoryException);

		m_newFaces = new FaceSetPure(E);
		if (m_newFaces == 0) {
			delete m_delFaces;
			OGDF_THROW(InsufficientMemoryException);
		}

	// no postprocessing -> no removeEdge()
	} else {
		m_delFaces = 0;
		m_newFaces = 0;
	}

	SListPure<edge> currentOrigEdges;
	if(removeReinsert() == rrIncremental) {
		edge e;
		forall_edges(e,PG)
			currentOrigEdges.pushBack(PG.original(e));
	}

	// insertion of edges
	ListConstIterator<edge> it;
	for(it = origEdges.begin(); it.valid(); ++it)
	{
		edge eOrig = *it;

		int eSubGraph = 0;  // edgeSubGraph-data of eOrig
		if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig];

		SList<adjEntry> crossed;
		if(costOrig != 0) {
			findShortestPath(PG, E, *costOrig,
				PG.copy(eOrig->source()),PG.copy(eOrig->target()),
				forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
				crossed, edgeSubGraph, eSubGraph);
		} else {
			findShortestPath(E,
				PG.copy(eOrig->source()),PG.copy(eOrig->target()),
				forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
				crossed);
		}

		insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig);
		
		if(removeReinsert() == rrIncremental) {
			currentOrigEdges.pushBack(eOrig);

			bool improved;
			do {
				++m_runsPostprocessing;
				improved = false;
				
				SListConstIterator<edge> itRR;
				for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR)
				{
					edge eOrigRR = *itRR;
		
					int pathLength;
					if(costOrig != 0)
						pathLength = costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph);
					else
						pathLength = PG.chain(eOrigRR).size() - 1;
					if (pathLength == 0) continue; // cannot improve
		
					removeEdge(PG,E,eOrigRR,forbidCrossingGens,forbiddenEdgeOrig);
		
					// try to find a better insertion path
					SList<adjEntry> crossed;
					if(costOrig != 0) {
						int eSubGraph = 0;  // edgeSubGraph-data of eOrig
						if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrigRR];

						findShortestPath(PG, E, *costOrig,
							PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()),
							forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association,
							crossed, edgeSubGraph, eSubGraph);
					} else {
						findShortestPath(E,
							PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()),
							forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association,
							crossed);
					}
					
					// re-insert edge (insertion path cannot be longer)
					insertEdge(PG,E,eOrigRR,crossed,forbidCrossingGens,forbiddenEdgeOrig);
		
					int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrigRR).size() - 1);
					OGDF_ASSERT(newPathLength <= pathLength);
					
					if(newPathLength < pathLength)
						improved = true;
				}
			} while (improved);
		}
	}

	const Graph &G = PG.original();
	if(removeReinsert() != rrIncremental) {
		// postprocessing (remove-reinsert heuristc)
		SListPure<edge> rrEdges;
	
		switch(removeReinsert())
		{
		case rrAll:
		case rrMostCrossed: {
				const List<node> &origInCC = PG.nodesInCC();
				ListConstIterator<node> itV;
	
				for(itV = origInCC.begin(); itV.valid(); ++itV) {
					node vG = *itV;
					adjEntry adj;
					forall_adj(adj,vG) {
						if ((adj->index() & 1) == 0) continue;
						edge eG = adj->theEdge();
						rrEdges.pushBack(eG);
					}
				}
			}
			break;
	
		case rrInserted:
			for(ListConstIterator<edge> it = origEdges.begin(); it.valid(); ++it)
				rrEdges.pushBack(*it);
			break;

		case rrNone:
		case rrIncremental:
			break;
		}
	
		// marks the end of the interval of rrEdges over which we iterate
		// initially set to invalid iterator which means all edges
		SListConstIterator<edge> itStop;
	
		bool improved;
		do {
			// abort postprocessing if time limit reached
			if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) {
				retValue = retTimeoutFeasible;
				break;
			}
				
			++m_runsPostprocessing;
			improved = false;
	
			if(removeReinsert() == rrMostCrossed)
			{
				FEICrossingsBucket bucket(&PG);
				rrEdges.bucketSort(bucket);
	
				const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges());
				itStop = rrEdges.get(num);
			}
	
			SListConstIterator<edge> it;
			for(it = rrEdges.begin(); it != itStop; ++it)
			{
				edge eOrig = *it;
							
				// remove only if crossings on edge;
				// in especially: forbidden edges are never handled by postprocessing
				//   since there are no crossings on such edges
				int pathLength;
				if(costOrig != 0)
					pathLength = costCrossed(eOrig,PG,*costOrig,edgeSubGraph);
				else
					pathLength = PG.chain(eOrig).size() - 1;
				if (pathLength == 0) continue; // cannot improve
	
				removeEdge(PG,E,eOrig,forbidCrossingGens,forbiddenEdgeOrig);
	
				// try to find a better insertion path
				SList<adjEntry> crossed;
				if(costOrig != 0) {
					int eSubGraph = 0;  // edgeSubGraph-data of eOrig
					if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig];

					findShortestPath(PG, E, *costOrig,
						PG.copy(eOrig->source()),PG.copy(eOrig->target()),
						forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
						crossed, edgeSubGraph, eSubGraph);
				} else {
					findShortestPath(E,
						PG.copy(eOrig->source()),PG.copy(eOrig->target()),
						forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
						crossed);
				}
	
				// re-insert edge (insertion path cannot be longer)
				insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig);
	
				int newPathLength = (costOrig != 0) ? costCrossed(eOrig,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrig).size() - 1);
				OGDF_ASSERT(newPathLength <= pathLength);
				
				if(newPathLength < pathLength)
					improved = true;
			}
		} while(improved); // iterate as long as we improve
	}