예제 #1
0
파일: UpwardPlanRep.cpp 프로젝트: ogdf/ogdf
adjEntry UpwardPlanRep::getAdjEntry(const CombinatorialEmbedding &Gamma, node v, face f) const {
	adjEntry adjFound = nullptr;
	for(adjEntry adj : v->adjEntries) {
		if (Gamma.rightFace(adj) == f) {
			adjFound = adj;
			break;
		}
	}
	OGDF_ASSERT(adjFound != nullptr);
	OGDF_ASSERT(Gamma.rightFace(adjFound) == f);

	return adjFound;
}
예제 #2
0
	void FixEdgeInserterCore::removeEdge(CombinatorialEmbedding &E, edge eOrig)
	{
		const List<edge> &path = m_pr.chain(eOrig);
		for(edge e : path)
		{
			adjEntry adj = e->adjSource();
			m_delFaces->insert(E.leftFace  (adj));
			m_delFaces->insert(E.rightFace (adj));
		}

		// delete all corresponding nodes in dual
		for(face f : m_delFaces->faces())
			m_dual.delNode(m_nodeOf[f]);

		m_delFaces->clear();

		// remove edge path from PG
		m_pr.removeEdgePathEmbedded(E,eOrig,*m_newFaces);

		// update dual
		// insert new nodes
		for(face f : m_newFaces->faces()) {
			m_nodeOf[f] = m_dual.newNode();
		}

		// insert new edges into dual
		for(face f : m_newFaces->faces())
			insertEdgesIntoDualAfterRemove(E, f);

		m_newFaces->clear();
	}
예제 #3
0
	//---------------------------------------------------------
	// construct dual graph, marks dual edges corresponding to generalization
	// in m_primalIsGen
	// assumes that m_pDual, m_primalAdj and m_nodeOf are already constructed
	//
	void FixEdgeInserterUMLCore::constructDual(const CombinatorialEmbedding &E)
	{
		// insert a node in the dual graph for each face in E
		for(face f : E.faces)
			m_nodeOf[f] = m_dual.newNode();


		// Insert an edge into the dual graph for each adjacency entry in E.
		// The edges are directed from the left face to the right face.
		for(node v : m_pr.nodes)
		{
			for(adjEntry adj : v->adjEdges)
			{
				node vLeft  = m_nodeOf[E.leftFace (adj)];
				node vRight = m_nodeOf[E.rightFace(adj)];

				edge e = m_dual.newEdge(vLeft,vRight);
				m_primalAdj[e] = adj;

				// mark dual edges corresponding to generalizations
				if (m_pr.typeOf(adj->theEdge()) == Graph::generalization)
					m_primalIsGen[e] = true;
			}
		}

		// Augment the dual graph by two new vertices. These are used temporarily
		// when searching for a shortest path in the dual graph.
		m_vS = m_dual.newNode();
		m_vT = m_dual.newNode();
	}
예제 #4
0
	//---------------------------------------------------------
	// construct dual graph
	// assumes that m_pDual, m_primalAdj and m_nodeOf are already constructed
	//
	void FixEdgeInserterCore::constructDual(const CombinatorialEmbedding &E)
	{
		// insert a node in the dual graph for each face in E
		for(face f : E.faces)
			m_nodeOf[f] = m_dual.newNode();


		// Insert an edge into the dual graph for each adjacency entry in E.
		// The edges are directed from the left face to the right face.
		for(node v : m_pr.nodes)
		{
			for(adjEntry adj : v->adjEdges)
			{
				// Do not insert edges into dual if crossing the original edge
				// is forbidden
				if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true)
					continue;

				node vLeft  = m_nodeOf[E.leftFace (adj)];
				node vRight = m_nodeOf[E.rightFace(adj)];

				m_primalAdj[m_dual.newEdge(vLeft,vRight)] = adj;
			}
		}

		// Augment the dual graph by two new vertices. These are used temporarily
		// when searching for a shortest path in the dual graph.
		m_vS = m_dual.newNode();
		m_vT = m_dual.newNode();
	}
예제 #5
0
void CPlanarEdgeInserter::constructDualGraph(ClusterPlanRep& CPR,
											 CombinatorialEmbedding& E,
											 EdgeArray<edge>& arcRightToLeft,
											 EdgeArray<edge>& arcLeftToRight,
		 									 FaceArray<node>& nodeOfFace,
											 //NodeArray<face>&, faceOfNode,
											 EdgeArray<edge>& arcTwin)
{
	//dual graph gets two arcs for each edge (in both directions)
	//these arcs get their status (usable for path) depending on
	//the edge to be reinserted

	m_dualGraph.clear();
	//faceOfNode.init(m_dualGraph, 0);

	//*********************************
	//construct nodes
	//corresponding to the graphs faces
	face f;
	for (f = E.firstFace(); f; f = f->succ())
	{
		node v = m_dualGraph.newNode();
		nodeOfFace[f] = v;
		//faceOfNode[v] = f;
	}

	//*********************************
	//
	edge e;
	forall_edges(e, CPR)
	{
		edge arc1 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjTarget())],
			nodeOfFace[E.rightFace(e->adjSource())] );
		arcLeftToRight[e] = arc1;
		edge arc2 = m_dualGraph.newEdge( nodeOfFace[E.rightFace(e->adjSource())],
			nodeOfFace[E.rightFace(e->adjTarget())] );
		arcRightToLeft[e] = arc2;
		arcTwin[arc1] = arc2;
		arcTwin[arc2] = arc1;
		m_arcOrig[arc1] = e->adjSource();//e->adjTarget();
		m_arcOrig[arc2] = e->adjTarget();//e->adjSource();
	}
예제 #6
0
	face SimpleEmbedder::findBestExternalFace(
		const PlanRep& PG,
		const CombinatorialEmbedding& E)
	{
		FaceArray<int> weight(E);

		for(face f : E.faces)
			weight[f] = f->size();

		for(node v : PG.nodes)
		{
			if(PG.typeOf(v) != Graph::generalizationMerger)
				continue;

			adjEntry adjFound = nullptr;
			for(adjEntry adj : v->adjEdges) {
				if (adj->theEdge()->source() == v) {
					adjFound = adj;
					break;
				}
			}

			OGDF_ASSERT(adjFound->theEdge()->source() == v);

			node w = adjFound->theEdge()->target();
			bool isBase = true;

			for(adjEntry adj : w->adjEdges) {
				edge e = adj->theEdge();
				if(e->target() != w && PG.typeOf(e) == Graph::generalization) {
					isBase = false;
					break;
				}
			}

			if(isBase == false)
				continue;

			face f1 = E.leftFace(adjFound);
			face f2 = E.rightFace(adjFound);

			weight[f1] += v->indeg();
			if(f2 != f1)
				weight[f2] += v->indeg();
		}

		face fBest = E.firstFace();
		for(face f : E.faces)
			if(weight[f] > weight[fBest])
				fBest = f;

		return fBest;
	}
예제 #7
0
	void FixEdgeInserterUMLCore::insertEdgesIntoDual(const CombinatorialEmbedding &E, adjEntry adjSrc)
	{
		face f = E.rightFace(adjSrc);
		node vRight = m_nodeOf[f];

		adjEntry adj1 = f->firstAdj(), adj = adj1;
		do {
			node vLeft = m_nodeOf[E.leftFace(adj)];

			edge eLR = m_dual.newEdge(vLeft,vRight);
			m_primalAdj[eLR] = adj;

			edge eRL = m_dual.newEdge(vRight,vLeft);
			m_primalAdj[eRL] = adj->twin();

			if(m_pr.typeOf(adj->theEdge()) == Graph::generalization)
				m_primalIsGen[eLR] = m_primalIsGen[eRL] = true;
		}
		while((adj = adj->faceCycleSucc()) != adj1);

		// the other face adjacent to *itEdge ...
		f = E.rightFace(adjSrc->twin());
		vRight = m_nodeOf[f];

		adj1 = f->firstAdj();
		adj = adj1;
		do {
			node vLeft = m_nodeOf[E.leftFace(adj)];

			edge eLR = m_dual.newEdge(vLeft,vRight);
			m_primalAdj[eLR] = adj;

			edge eRL = m_dual.newEdge(vRight,vLeft);
			m_primalAdj[eRL] = adj->twin();

			if(m_pr.typeOf(adj->theEdge()) == Graph::generalization)
				m_primalIsGen[eLR] = m_primalIsGen[eRL] = true;
		}
		while((adj = adj->faceCycleSucc()) != adj1);
	}
예제 #8
0
	void FixEdgeInserterCore::insertEdgesIntoDual(const CombinatorialEmbedding &E, adjEntry adjSrc)
	{
		face f = E.rightFace(adjSrc);
		node vRight = m_nodeOf[f];

		adjEntry adj1 = f->firstAdj(), adj = adj1;
		do {
			if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true)
				continue;

			node vLeft = m_nodeOf[E.leftFace(adj)];

			edge eLR = m_dual.newEdge(vLeft,vRight);
			m_primalAdj[eLR] = adj;

			edge eRL = m_dual.newEdge(vRight,vLeft);
			m_primalAdj[eRL] = adj->twin();
		}
		while((adj = adj->faceCycleSucc()) != adj1);

		// the other face adjacent to *itEdge ...
		f = E.rightFace(adjSrc->twin());
		vRight = m_nodeOf[f];

		adj1 = f->firstAdj();
		adj = adj1;
		do {
			if(m_pForbidden && (*m_pForbidden)[m_pr.original(adj->theEdge())] == true)
				continue;

			node vLeft = m_nodeOf[E.leftFace(adj)];

			edge eLR = m_dual.newEdge(vLeft,vRight);
			m_primalAdj[eLR] = adj;

			edge eRL = m_dual.newEdge(vRight,vLeft);
			m_primalAdj[eRL] = adj->twin();
		}
		while((adj = adj->faceCycleSucc()) != adj1);
	}
예제 #9
0
	void FixEdgeInserterCore::insertEdge(CombinatorialEmbedding &E, edge eOrig, const SList<adjEntry> &crossed)
	{
		// remove dual nodes on insertion path
		SListConstIterator<adjEntry> it;
		for(it = crossed.begin(); it != crossed.rbegin(); ++it) {
			m_dual.delNode(m_nodeOf[E.rightFace(*it)]);
		}

		// update primal
		m_pr.insertEdgePathEmbedded(eOrig,E,crossed);

		// insert new face nodes into dual
		const List<edge> &path = m_pr.chain(eOrig);
		for(edge e : path)
		{
			adjEntry adj = e->adjSource();
			m_nodeOf[E.leftFace (adj)] = m_dual.newNode();
			m_nodeOf[E.rightFace(adj)] = m_dual.newNode();
		}

		// insert new edges into dual
		for(edge e : path)
			insertEdgesIntoDual(E, e->adjSource());
	}
예제 #10
0
	face SimpleEmbedder::findBestExternalFace(const PlanRep& PG,
	                                          const CombinatorialEmbedding& E)
	{
		FaceArray<int> weight(E);

		face f;
		forall_faces(f,E)
			weight[f] = f->size();

		node v;
		forall_nodes(v,PG)
		{
			if(PG.typeOf(v) != Graph::generalizationMerger)
				continue;

			adjEntry adj;
			forall_adj(adj,v) {
				if(adj->theEdge()->source() == v)
					break;
			}

			OGDF_ASSERT(adj->theEdge()->source() == v);

			node w = adj->theEdge()->target();
			bool isBase = true;

			adjEntry adj2;
			forall_adj(adj2, w) {
				edge e = adj2->theEdge();
				if(e->target() != w && PG.typeOf(e) == Graph::generalization) {
					isBase = false;
					break;
				}
			}

			if(isBase == false)
				continue;

			face f1 = E.leftFace(adj);
			face f2 = E.rightFace(adj);

			weight[f1] += v->indeg();
			if(f2 != f1)
				weight[f2] += v->indeg();
		}
예제 #11
0
/**---------------------------------------------------
calling function taking the planar representation, the
external face (adjentry), the layout to be filled,
a list of non-planar edges, a list of inserted edges
and the original graph as input
*/
void ClusterOrthoLayout::call(ClusterPlanRep &PG,
	adjEntry adjExternal,
	Layout &drawing,
	List<NodePair>& npEdges,
	List<edge>& newEdges,
	Graph& originalGraph)
{
	// We don't care about UML hierarchies and therefore do not allow alignment
	OGDF_ASSERT(!m_align);

	// if we have only one vertex in PG ...
	if(PG.numberOfNodes() == 1) {
		node v1 = PG.firstNode();
		node vOrig = PG.original(v1);
		double w = PG.widthOrig(vOrig);
		double h = PG.heightOrig(vOrig);

		drawing.x(v1) = m_margin + w/2;
		drawing.y(v1) = m_margin + h/2;
		m_boundingBox = DPoint(w + 2*m_margin, h + 2*m_margin);
		return;
	}

	OGDF_ASSERT(PG.representsCombEmbedding())
	//-------------------------
	// insert cluster boundaries
	PG.ModelBoundaries();
	OGDF_ASSERT(PG.representsCombEmbedding())


	//--------------------------
	// insert non-planar edges
	CombinatorialEmbedding* CE = new CombinatorialEmbedding(PG);
	if (!npEdges.empty())
	{
		CPlanarEdgeInserter CEI;
		CEI.call(PG, *CE, originalGraph, npEdges, newEdges);
	}//if

	//------------------------------------------------------------
	// now we set the external face, currently to the largest face
	adjEntry extAdj = 0;
	int maximum = 0;
	edge e, eSucc;

	for(e = PG.firstEdge(); e; e = eSucc)
	{
		eSucc = e->succ();
		if ( PG.clusterOfEdge(e) == PG.getClusterGraph().rootCluster() )
		{
			int asSize = CE->rightFace(e->adjSource())->size();
			if ( asSize > maximum)
			{
				maximum = asSize;
				extAdj = e->adjSource();
			}
			int atSize = CE->rightFace(e->adjTarget())->size();
			if ( atSize > maximum)
			{
				maximum = atSize;
				extAdj = e->adjTarget();
			}

		}//if root edge

	}//for

	delete CE;

	//returns adjEntry in rootcluster
	adjExternal = extAdj;
	OGDF_ASSERT(adjExternal != 0);


	//----------------------------------------------------------
	//Compaction scaling: help node cages to pass by each other:
	//First, the layout is blown up and then shrunk again in several steps
	//We change the separation value and save the original value.
	double l_orsep = m_separation;
	if (m_useScalingCompaction)
	{
		double scaleFactor = double(int(1 << m_scalingSteps));
		m_separation = scaleFactor*m_separation; //reduce this step by step in compaction
	}//if scaling

	//***********************************
	// PHASE 1: determine orthogonal shape

	//-------------------------------------------------------
	// expand high-degree vertices and generalization mergers
	PG.expand();

	// get combinatorial embedding
	CombinatorialEmbedding E(PG);
	E.setExternalFace(E.rightFace(adjExternal));

	// orthogonal shape representation
	OrthoRep OR;

	ClusterOrthoShaper COF;

	//set some options
	COF.align(false); //cannot be used yet with clusters
	COF.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180
	//bend cost depends on cluster depths avoiding unnecessary "inner" bends
	COF.bendCostTopDown(ClusterOrthoShaper::topDownCost);

	// New Call
	//COF.call(PG,E,OR,2);
	// Original call without bend bounds(still valid)
	COF.call(PG, E, OR);

	String msg;
	OGDF_ASSERT(OR.check(msg))

	//******************************************************************
	// PHASE 2: construction of a feasible drawing of the expanded graph

	//---------------------------
	// expand low degree vertices
	PG.expandLowDegreeVertices(OR);

	OGDF_ASSERT(PG.representsCombEmbedding());

	//------------------
	// restore embedding
	E.computeFaces();
	E.setExternalFace(E.rightFace(adjExternal));

	OGDF_ASSERT(OR.check(msg))

	//----------
	//COMPACTION

	//--------------------------
	// apply constructive compaction heuristics
	OR.normalize();
	OR.dissect();

	OR.orientate(PG,m_preferedDir);

	OGDF_ASSERT(OR.check(msg))

	// compute cage information and routing channels
	OR.computeCageInfoUML(PG);
	//temporary grid layout
	GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,4);

	RoutingChannel<int> rcGrid(PG,gridDrawing.toGrid(m_separation),m_cOverhang);
	rcGrid.computeRoutingChannels(OR, m_align);

	node v;
	const OrthoRep::VertexInfoUML *pInfoExp;
	forall_nodes(v,PG) {
		pInfoExp = OR.cageInfo(v);

		if (pInfoExp) break;
	}
예제 #12
0
	void FixEdgeInserterCore::findWeightedShortestPath(const CombinatorialEmbedding &E, edge eOrig, SList<adjEntry> &crossed)
	{
		node s = m_pr.copy(eOrig->source());
		node t = m_pr.copy(eOrig->target());
		OGDF_ASSERT(s != t);

		int eSubgraph = (m_pSubgraph != nullptr) ? (*m_pSubgraph)[eOrig] : 0;

		EdgeArray<int> costDual(m_dual, 0);
		int maxCost = 0;
		for(edge eDual : m_dual.edges) {
			int c = getCost(m_primalAdj[eDual]->theEdge(), eSubgraph);
			costDual[eDual] = c;
			if (c > maxCost)
				maxCost = c;
		}

		++maxCost;
		Array<SListPure<edge> > nodesAtDist(maxCost);

		NodeArray<edge> spPred(m_dual,nullptr);

		int oldIdCount = m_dual.maxEdgeIndex();

		// augment dual by edges from s to all adjacent faces of s ...
		for(adjEntry adj : s->adjEdges) {
			// starting edges of bfs-search are all edges leaving s
			edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]);
			m_primalAdj[eDual] = adj;
			nodesAtDist[0].pushBack(eDual);
		}

		// ... and from all adjacent faces of t to t
		for(adjEntry adj : t->adjEdges) {
			edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT);
			m_primalAdj[eDual] = adj;
		}

		// actual search (using extended bfs on directed dual)
		int currentDist = 0;

		for( ; ; )
		{
			// next candidate edge
			while(nodesAtDist[currentDist % maxCost].empty())
				++currentDist;

			edge eCand = nodesAtDist[currentDist % maxCost].popFrontRet();
			node v = eCand->target();

			// leads to an unvisited node?
			if (spPred[v] == nullptr)
			{
				// yes, then we set v's predecessor in search tree
				spPred[v] = eCand;

				// have we reached t ...
				if (v == m_vT)
				{
					// ... then search is done.
					// constructed list of used edges (translated to crossed
					// adjacency entries in PG) from t back to s (including first
					// and last!)

					do {
						edge eDual = spPred[v];
						crossed.pushFront(m_primalAdj[eDual]);
						v = eDual->source();
					} while(v != m_vS);

					break;
				}

				// append next candidate edges to queue (all edges leaving v)
				appendCandidates(nodesAtDist, costDual, maxCost, v, currentDist);
			}
		}

		// remove augmented edges again
		adjEntry adj;
		while ((adj = m_vS->firstAdj()) != nullptr)
			m_dual.delEdge(adj->theEdge());

		while ((adj = m_vT->firstAdj()) != nullptr)
			m_dual.delEdge(adj->theEdge());

		m_dual.resetEdgeIdCount(oldIdCount);
	}
예제 #13
0
	void FixEdgeInserterCore::findShortestPath(const CombinatorialEmbedding &E, edge eOrig, SList<adjEntry> &crossed)
	{
		node s = m_pr.copy(eOrig->source());
		node t = m_pr.copy(eOrig->target());
		OGDF_ASSERT(s != t);

		NodeArray<edge> spPred(m_dual,nullptr);
		QueuePure<edge> queue;
		int oldIdCount = m_dual.maxEdgeIndex();

		// augment dual by edges from s to all adjacent faces of s ...
		for(adjEntry adj : s->adjEdges) {
			// starting edges of bfs-search are all edges leaving s
			edge eDual = m_dual.newEdge(m_vS, m_nodeOf[E.rightFace(adj)]);
			m_primalAdj[eDual] = adj;
			queue.append(eDual);
		}

		// ... and from all adjacent faces of t to t
		for(adjEntry adj : t->adjEdges) {
			edge eDual = m_dual.newEdge(m_nodeOf[E.rightFace(adj)], m_vT);
			m_primalAdj[eDual] = adj;
		}

		// actual search (using bfs on directed dual)
		for( ; ;)
		{
			// next candidate edge
			edge eCand = queue.pop();
			node v = eCand->target();

			// leads to an unvisited node?
			if (spPred[v] == nullptr)
			{
				// yes, then we set v's predecessor in search tree
				spPred[v] = eCand;

				// have we reached t ...
				if (v == m_vT)
				{
					// ... then search is done.
					// constructed list of used edges (translated to crossed
					// adjacency entries in PG) from t back to s (including first
					// and last!)

					do {
						edge eDual = spPred[v];
						crossed.pushFront(m_primalAdj[eDual]);
						v = eDual->source();
					} while(v != m_vS);

					break;
				}

				// append next candidate edges to queue (all edges leaving v)
				appendCandidates(queue, v);
			}
		}


		// remove augmented edges again
		adjEntry adj;
		while ((adj = m_vS->firstAdj()) != nullptr)
			m_dual.delEdge(adj->theEdge());

		while ((adj = m_vT->firstAdj()) != nullptr)
			m_dual.delEdge(adj->theEdge());

		m_dual.resetEdgeIdCount(oldIdCount);
	}