void ComponentSplitterLayout::call(GraphAttributes &GA)
{
	// Only do preparations and call if layout is valid
	if (m_secondaryLayout.valid())
	{
		//first we split the graph into its components
		const Graph& G = GA.constGraph();

		NodeArray<int> componentNumber(G);
		m_numberOfComponents = connectedComponents(G, componentNumber);
		if (m_numberOfComponents == 0) {
			return;
		}

		//std::vector< std::vector<node> > componentArray;
		//componentArray.resize(numComponents);
		//Array<GraphAttributes *> components(numComponents);
		//

		// intialize the array of lists of nodes contained in a CC
		nodesInCC.init(m_numberOfComponents);

		node v;
		forall_nodes(v,G)
			nodesInCC[componentNumber[v]].pushBack(v);

		 // Create copies of the connected components and corresponding
		 // GraphAttributes
		 GraphCopy GC;
		 GC.createEmpty(G);

		 EdgeArray<edge> auxCopy(G);

		 for (int i = 0; i < m_numberOfComponents; i++)
		 {
			 GC.initByNodes(nodesInCC[i],auxCopy);
			 GraphAttributes cGA(GC);
			 //copy information into copy GA
			 forall_nodes(v, GC)
			 {
				cGA.width(v) = GA.width(GC.original(v));
				cGA.height(v) = GA.height(GC.original(v));
				cGA.x(v) = GA.x(GC.original(v));
				cGA.y(v) = GA.y(GC.original(v));
			 }
			 m_secondaryLayout.get().call(cGA);

			 //copy layout information back into GA
			 forall_nodes(v, GC)
			 {
				 node w = GC.original(v);
				 if (w != 0)
					 GA.x(w) = cGA.x(v);
				 GA.y(w) = cGA.y(v);
			 }
		 }
void ComponentSplitterLayout::call(GraphAttributes &GA)
{
	// Only do preparations and call if layout is valid
	if (m_secondaryLayout.valid())
	{
		//first we split the graph into its components
		const Graph& G = GA.constGraph();

		NodeArray<int> componentNumber(G);
		int numberOfComponents = connectedComponents(G, componentNumber);
		if (numberOfComponents == 0) {
			return;
		}

		// intialize the array of lists of nodes contained in a CC
		Array<List<node> > nodesInCC(numberOfComponents);

		for(node v : G.nodes)
			nodesInCC[componentNumber[v]].pushBack(v);

		// Create copies of the connected components and corresponding
		// GraphAttributes
		GraphCopy GC;
		GC.createEmpty(G);

		EdgeArray<edge> auxCopy(G);

		for (int i = 0; i < numberOfComponents; i++)
		{
			GC.initByNodes(nodesInCC[i],auxCopy);
			GraphAttributes cGA(GC, GA.attributes());
			//copy information into copy GA
			for(node v : GC.nodes)
			{
				cGA.width(v) = GA.width(GC.original(v));
				cGA.height(v) = GA.height(GC.original(v));
				cGA.x(v) = GA.x(GC.original(v));
				cGA.y(v) = GA.y(GC.original(v));
			}
			// copy information on edges
			if (GA.attributes() & GraphAttributes::edgeDoubleWeight) {
				for (edge e : GC.edges) {
					cGA.doubleWeight(e) = GA.doubleWeight(GC.original(e));
				}
			}
			m_secondaryLayout.get().call(cGA);

			//copy layout information back into GA
			for(node v : GC.nodes)
			{
				node w = GC.original(v);
				if (w != nullptr)
				{
					GA.x(w) = cGA.x(v);
					GA.y(w) = cGA.y(v);
					if (GA.attributes() & GraphAttributes::threeD) {
						GA.z(w) = cGA.z(v);
					}
				}
			}
		}

		// rotate component drawings and call the packer
		reassembleDrawings(GA, nodesInCC);

	}//if valid
}
Exemple #3
0
//Connect parts of partial active current CC.
//Note that this only makes sense when the CC parts are
//already correctly embedded. Crossings are already replaced
//by nodes
bool PlanRepInc::makeTreeConnected(adjEntry /* adjExternal */)
{

	//we compute node numbers for the partial CCs in order to
	//identify the treeConnect Edges that can be deleted later
	m_component.init(*this, -1);

	//if there is only one CC, we don't need to connect
	if (isConnected(*this)) return false;
	//We have to insert edges connnecting nodes lying on
	//the "external" face of the active parts

	//First, we activate the CC's parts one by one and compute
	//the 'external' face from the layout information
	//If the PlanRepInc is not embedded corresponding to
	//this layout, we may introduce edges that are non-planar
	//in the drawing, leading to problems when we compute paths
	//in the dual graph

	List<node> isolatedNodes;
	const int numPartialCC = connectedIsolatedComponents(*this,
		isolatedNodes, m_component);

	//CombinatorialEmbedding can cope with unconnected graphs
	//but does not provide faces for isolated nodes
	CombinatorialEmbedding E(*this);
	TopologyModule tm;
	List<adjEntry> extAdjs;
	//we run through all faces searching for all outer faces
	for(face f : E.faces)
	{
		//TODO: check if we should select special adjEntry instead of first
		if (tm.faceSum(*this, *m_pGraphAttributes, f) < 0)
			extAdjs.pushBack(f->firstAdj());

#ifdef OGDF_DEBUG
		cout << "FaceSum in Face " << f->index() << " Groesse " << f->size()
			<< " ist: " << tm.faceSum(*this, *m_pGraphAttributes, f) <<"\n" << flush;
#endif
	}//forallfaces

	//now we have faces for all partial CCs that are not isolated nodes

	OGDF_ASSERT(extAdjs.size() + isolatedNodes.size() == numPartialCC)
	//OGDF_ASSERT(extAdjs.size() > 1) //eigentlich: = #partial CCs
	//OGDF_ASSERT(extAdjs.size() == numPartialCC)

	const int n1 = numPartialCC-1;
	m_eTreeArray.init(0, n1, 0, n1, nullptr);
	m_treeInit = true;

	//Three cases: only CCs, only isolated nodes, and both (where
	//only one CC + isolated nodes is possible

	//now we connect all partial CCs by inserting edges at the adjEntries
	//in extAdjs and adding all isolated nodes
	adjEntry lastAdj = nullptr;
	ListIterator<adjEntry> it = extAdjs.begin();
	while(it.valid())
	{
		//for the case: one external face, multiple isolated nodes
		lastAdj = (*it);
		adjEntry adj = (*it);
		ListIterator<adjEntry> it2 = it.succ();
		if (it2.valid())
		{
			adjEntry adj2 = (*it2);
			edge eTree = newEdge(adj, adj2);
			m_treeEdge[eTree] = true;
			lastAdj = eTree->adjTarget();
			//save the connection edge by CC number index
			//this is used when deleting obsolete edges later
			//after edge reinsertion
			m_eTreeArray(componentNumber(adj->theNode()), componentNumber(adj2->theNode())) =
				m_eTreeArray(m_component[adj2->theNode()], m_component[adj->theNode()])
				= eTree;
		}//if CCs left to connect

		++it;
	}//while
	while (!isolatedNodes.empty())
	{
		node uvw = isolatedNodes.popFrontRet();
		if (lastAdj)
		{
			//same block as above
			edge eTree = newEdge(uvw, lastAdj);
			m_treeEdge[eTree] = true;
			//save the connection edge by CC number index
			//this is used when deleting obsolete edges later
			//after edge reinsertion
			m_eTreeArray(componentNumber(lastAdj->theNode()), componentNumber(uvw)) =
				m_eTreeArray(m_component[uvw], m_component[lastAdj->theNode()])
				= eTree;
			lastAdj = eTree->adjSource();
		}
		else //connect the first two isolated nodes / only iso nodes exist
		{
			//MUST BE #isonodes>1, else we returned already because CC connected
			OGDF_ASSERT(!isolatedNodes.empty())
			node secv = isolatedNodes.popFrontRet();
			//same block as above
			edge eTree = newEdge(uvw, secv);
			m_treeEdge[eTree] = true;
			//save the connection edge by CC number index
			//this is used when deleting obsolete edges later
			//after edge reinsertion
			m_eTreeArray(componentNumber(secv), componentNumber(uvw)) =
				m_eTreeArray(m_component[uvw], m_component[secv])
				= eTree;
			lastAdj = eTree->adjSource();

		}
	}//while isolated nodes

	OGDF_ASSERT(isConnected(*this));


	//List<adjEntry> extAdjs;
	//getExtAdjs(extAdjs);


	return true;
}//makeStarConnected