//---------------------------------------------------------
// 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

#ifdef OGDF_DEBUG
	// Check if no edge in the list origEdges is forbidden
	if(forbiddenEdgeOrig != 0) {
		ListConstIterator<edge> itTemp;
		for(itTemp = origEdges.begin(); itTemp.valid(); ++itTemp)
			OGDF_ASSERT((*forbiddenEdgeOrig)[*itTemp] == false);
	}
#endif

	// 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);

#ifdef OGDF_DEBUG
	if(forbiddenEdgeOrig != 0) {
		edge e;
		forall_edges(e,m_dual) {
			OGDF_ASSERT((*forbiddenEdgeOrig)[PG.original(m_primalAdj[e]->theEdge())] == false);
		}
void MixedModelLayout::doCall(
	PlanRep &PG,
	adjEntry adjExternal,
	GridLayout &gridLayout,
	IPoint &boundingBox,
	bool fixEmbedding)
{
	// handle graphs with less than 3 nodes
	node v1, v2;
	switch (PG.numberOfNodes()) {
	case 0:
		boundingBox = IPoint(0,0);
		return;

	case 1:
		v1 = PG.firstNode();
		gridLayout.x(v1) = gridLayout.y(v1) = 0;
		boundingBox = IPoint(0,0);
		return;

	case 2:
		v1 = PG.firstNode();
		v2 = v1->succ();
		gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0;
		gridLayout.x(v2) = 1;
		boundingBox = IPoint(1,0);
		return;
	}

	MixedModelBase mm(PG,gridLayout);

	if(fixEmbedding) {
		OGDF_ASSERT(PG.representsCombEmbedding());
		PlanarAugmentationFix fixAugmenter;
		mm.computeOrder(fixAugmenter, 0, adjExternal, m_compOrder.get());
	} else
		mm.computeOrder(m_augmenter.get(),&m_embedder.get(),0,m_compOrder.get());

	mm.assignIopCoords();
	mm.placeNodes();
	mm.postprocessing1();
	mm.setBends();
	mm.postprocessing2();

	m_crossingsBeautifier.get().call(PG,gridLayout);

	int xmin, ymin;
	gridLayout.computeBoundingBox(xmin,boundingBox.m_x,ymin,boundingBox.m_y);
}
Example #3
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
	}