Exemplo n.º 1
0
	void SimpleEmbedder::call(Graph& G, adjEntry& adjExternal)
	{
		OGDF_ASSERT(isPlanar(G));

		//----------------------------------------------------------
		//
		// determine embedding of G
		//

		// We currently compute any embedding and choose the maximal face
		// as external face

		// if we use FixedEmbeddingInserterOld, we have to re-use the computed
		// embedding, otherwise crossing nodes can turn into "touching points"
		// of edges (alternatively, we could compute a new embedding and
		// finally "remove" such unnecessary crossings).
		adjExternal = nullptr;
		if(!G.representsCombEmbedding())
			planarEmbed(G);

		if (G.numberOfEdges() > 0)
		{
			CombinatorialEmbedding E(G);
			//face fExternal = E.maximalFace();
			face fExternal = findBestExternalFace(G, E);
			adjExternal = fExternal->firstAdj();
		}
	}
Exemplo n.º 2
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);
}
Exemplo n.º 3
0
void SchnyderLayout::doCall(
	const Graph &G,
	adjEntry adjExternal,
	GridLayout &gridLayout,
	IPoint &boundingBox,
	bool fixEmbedding)
{
	// check for double edges & self loops
	OGDF_ASSERT(isSimple(G));

	// handle special case of graphs with less than 3 nodes
	if (G.numberOfNodes() < 3) {
		node v1, v2;
		switch (G.numberOfNodes()) {
		case 0:
			boundingBox = IPoint(0, 0);
			return;

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

		case 2:
			v1 = G.firstNode();
			v2 = G.lastNode();
			gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0;
			gridLayout.x(v2) = 1;
			boundingBox = IPoint(1, 0);
			return;
		}
	}

	// make a copy for triangulation
	GraphCopy GC(G);

	// embed
	if (!fixEmbedding) {
		if (planarEmbed(GC) == false) {
			OGDF_THROW_PARAM(PreconditionViolatedException, pvcPlanar);
		}
	}

	triangulate(GC);

	schnyderEmbedding(GC, gridLayout, adjExternal);
}
Exemplo n.º 4
0
// sets the positions of the nodes in a largest face of G in the form
// of a regular k-gon. The corresponding nodes and their positions are
// stored in nodes and pos, respectively.
void TutteLayout::setFixedNodes(
	const Graph &G,
	List<node>& nodes,
	List<DPoint>& pos,
	double radius)
{
	// compute faces of a copy of G
	GraphCopy GC(G);

	// compute a planar embedding if \a G is planar
	if(isPlanar(G)) planarEmbed(GC);
	//FIXME this stuff above seems wrong!!

	CombinatorialEmbedding E(GC);
	E.computeFaces();

	// search for largest face
	face maxFace = E.maximalFace();

	// delete possible old entries in nodes and pos
	nodes.clear();
	pos.clear();

	// set nodes and pos
	NodeArray<bool> addMe(GC,true);

	List<node> maxNodes;
	for(adjEntry adj : maxFace->entries) {
		maxNodes.pushBack(adj->theNode());
	}

	for(node w : maxNodes) {
		if(addMe[w]) {
			nodes.pushBack(w);
			addMe[w] = false;
		}
	}

	double step  = 2.0 * Math::pi / (double)(nodes.size());
	double alpha = 0.0;
	for(int i = 0; i < nodes.size(); ++i) {
		pos.pushBack(DPoint(radius * cos(alpha), radius * sin(alpha)));
		alpha += step;
	}
}
Exemplo n.º 5
0
	void VarEdgeInserterDynCore::ExpandedGraph::expand(node v, node vPred, node vSucc)
	{
		m_exp.clear();
		while (!m_nodesG.empty())
			m_GtoExp[m_nodesG.popBackRet()] = nullptr;

		edge eInS = nullptr;
		if (vPred != nullptr) {
			eInS = m_BC.dynamicSPQRForest().virtualEdge(vPred, v);
			m_eS = insertEdge(eInS->source(), eInS->target(), nullptr);
		}
		edge eOutS = nullptr;
		if (vSucc != nullptr) {
			eOutS = m_BC.dynamicSPQRForest().virtualEdge(vSucc, v);
			m_eT = insertEdge(eOutS->source(), eOutS->target(), nullptr);
		}

		expandSkeleton(v, eInS, eOutS);

		planarEmbed(m_exp);
		m_E.init(m_exp);
	}
Exemplo n.º 6
0
void FPPLayout::doCall(
	const Graph &G,
	adjEntry adjExternal,
	GridLayout &gridLayout,
	IPoint &boundingBox,
	bool fixEmbedding)
{
	// check for double edges & self loops
	OGDF_ASSERT(isSimple(G));

	// handle special case of graphs with less than 3 nodes
	if (G.numberOfNodes() < 3) {
		node v1, v2;
		switch (G.numberOfNodes()) {
		case 0:
			boundingBox = IPoint(0, 0);
			return;

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

		case 2:
			v1 = G.firstNode();
			v2 = G.lastNode();
			gridLayout.x(v1) = gridLayout.y(v1) = gridLayout.y(v2) = 0;
			gridLayout.x(v2) = 1;
			boundingBox = IPoint(1, 0);
			return;
		}
	}

	// make a copy for triangulation
	GraphCopy GC(G);

	// embed
	if (!fixEmbedding) {
		if (planarEmbed(GC) == false) {
			OGDF_THROW_PARAM(PreconditionViolatedException, pvcPlanar);
		}
	}

	triangulate(GC);

	// get edges for outer face (triangle)
	adjEntry e_12;
	if (adjExternal != 0) {
		edge eG  = adjExternal->theEdge();
		edge eGC = GC.copy(eG);
		e_12 = (adjExternal == eG->adjSource()) ? eGC->adjSource() : eGC->adjTarget();
	}
	else {
		e_12 = GC.firstEdge()->adjSource();
	}
	adjEntry e_2n = e_12->faceCycleSucc();

	NodeArray<int>  num(GC);

	NodeArray<adjEntry> e_wp(GC);					// List of predecessors on circle C_k
	NodeArray<adjEntry> e_wq(GC);					// List of successors on circle  C_k

	computeOrder(GC, num , e_wp, e_wq, e_12, e_2n, e_2n->faceCycleSucc());
	computeCoordinates(GC, boundingBox, gridLayout, num, e_wp, e_wq);
}
Exemplo n.º 7
0
	//--------------------------------------------------------------------
	// actual algorithm call
	//--------------------------------------------------------------------
	Module::ReturnType VarEdgeInserterDynCore::call(
		const Array<edge> &origEdges,
		RemoveReinsertType rrPost,
		double percentMostCrossed)
	{
		double T;
		usedTime(T);

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

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

		SListPure<edge> currentOrigEdges;

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

			// insertion of edges
			for (int i = origEdges.low(); i <= origEdges.high(); ++i)
			{
				edge eOrig = origEdges[i];
				storeTypeOfCurrentEdge(eOrig);

				m_pBC = createBCandSPQRtrees();
				SList<adjEntry> eip;
				insert(eOrig, eip);
				m_pr.insertEdgePath(eOrig, eip);
				delete m_pBC;

				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

						m_pr.removeEdgePath(eOrigRR);

						storeTypeOfCurrentEdge(eOrigRR);

						m_pBC = createBCandSPQRtrees();
						SList<adjEntry> eip;
						insert(eOrigRR, eip);
						m_pr.insertEdgePath(eOrigRR, eip);
						delete m_pBC;

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

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

		}
		else {

			// insertion of edges
			m_pBC = createBCandSPQRtrees();

			for (int i = origEdges.low(); i <= origEdges.high(); ++i)
			{
				edge eOrig = origEdges[i];
				storeTypeOfCurrentEdge(eOrig);

				SList<adjEntry> eip;
				insert(eOrig, eip);
				m_pBC->insertEdgePath(eOrig, eip);
			}

			delete m_pBC;

			// 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)
				{
					VEICrossingsBucket 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

					m_pr.removeEdgePath(eOrig);

					storeTypeOfCurrentEdge(eOrig);

					m_pBC = createBCandSPQRtrees();
					SList<adjEntry> eip;
					insert(eOrig, eip);
					m_pr.insertEdgePath(eOrig, eip);
					delete m_pBC;

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


#ifdef OGDF_DEBUG
		bool isPlanar =
#endif
			planarEmbed(m_pr);

		OGDF_ASSERT(isPlanar);

		m_pr.removePseudoCrossings();
		OGDF_ASSERT(m_pr.representsCombEmbedding());

		return retValue;
	}
Exemplo n.º 8
0
//-----------------------------------------------------------------------------
// call function: compute an UML layout for graph umlGraph
//-----------------------------------------------------------------------------
void PlanarizationLayoutUML::call(UMLGraph &umlGraph)
{
	m_nCrossings = 0;

	if(umlGraph.constGraph().empty())
		return;

	// check necessary preconditions
	preProcess(umlGraph);

	//---------------------------------------------------
	// preprocessing: insert a merger for generalizations
	umlGraph.insertGenMergers();

	PlanRepUML pr(umlGraph);
	const int numCC = pr.numberOfCCs();

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


	// alignment section (should not be here, because planarlayout should
	// not know about the meaning of layouter options and should not cope
	// with them), move later
	// we have to distinguish between cc's with and without generalizations
	// if the alignment option is set
	int l_layoutOptions = m_planarLayouter.get().getOptions();
	bool l_align = ((l_layoutOptions & umlOpAlign) > 0);
	//end alignment section

	//------------------------------------------
	//now planarize CCs and apply drawing module
	for(int i = 0; i < numCC; ++i)
	{
		//---------------------------------------
		// 1. crossing minimization
		//---------------------------------------

		// alignment: check wether gens exist, special treatment is necessary
		bool l_gensExist = false; // set this for all CC's, start with first gen,
		//this setting can be mixed among CC's without problems

		EdgeArray<Graph::EdgeType> savedType(pr);
		EdgeArray<Graph::EdgeType> savedOrigType(pr.original()); //for deleted copies

		EdgeArray<int> costOrig(pr.original(), 1);
		//edgearray for reinserter call: which edge may never be crossed?
		EdgeArray<bool> noCrossingEdge(pr.original(), false);

		edge e;
		forall_edges(e,pr)
		{
			edge eOrig = pr.original(e);

			if (pr.typeOf(e) == Graph::generalization)
			{
				if (l_align) l_gensExist = true;
				OGDF_ASSERT(!eOrig || !(noCrossingEdge[eOrig]));

				// high cost to allow alignment without crossings
				if (l_align && (
					(eOrig && (pr.typeOf(e->target()) == Graph::generalizationMerger))
						|| pr.alignUpward(e->adjSource())
					))
				 costOrig[eOrig] = 10;

			}
		}

		int cr;
		m_crossMin.get().call(pr, i, cr, &costOrig);
		m_nCrossings += cr;


		//---------------------------------------
		// 2. embed resulting planar graph
		//---------------------------------------

		// We currently compute any embedding and choose the maximal face as external face

		// if we use FixedEmbeddingInserter, we have to re-use the computed
		// embedding, otherwise crossing nodes can turn into "touching points"
		// of edges (alternatively, we could compute a new embedding and
		// finally "remove" such unnecessary crossings).
		if(!pr.representsCombEmbedding())
			planarEmbed(pr);

		adjEntry adjExternal = 0;
		if(pr.numberOfEdges() > 0) {
			CombinatorialEmbedding E(pr);
			face fExternal = findBestExternalFace(pr,E);
			adjExternal = fExternal->firstAdj();
		}


		//---------------------------------------------------------
		// 3. compute layout of planarized representation
		//---------------------------------------------------------

		Layout drawing(pr);

		// distinguish between CC's with/without generalizations
		// this changes the input layout modules options!
		if (l_gensExist)
			m_planarLayouter.get().setOptions(l_layoutOptions);
		else
			m_planarLayouter.get().setOptions((l_layoutOptions & ~umlOpAlign));

		// call the Layouter for the CC's UMLGraph
		m_planarLayouter.get().call(pr, adjExternal, drawing);

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

		for(int j = pr.startNode(); j < pr.stopNode(); ++j) {
			node vG = pr.v(j);

			umlGraph.x(vG) = drawing.x(pr.copy(vG));
			umlGraph.y(vG) = drawing.y(pr.copy(vG));

			adjEntry adj;
			forall_adj(adj,vG) {
				if ((adj->index() & 1) == 0) continue;
				edge eG = adj->theEdge();

				drawing.computePolylineClear(pr,eG,umlGraph.bends(eG));
			}
		}

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