/**---------------------------------------------------
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;
	}
Beispiel #2
0
void OrthoLayoutUML::call(PlanRepUML &PG,
	adjEntry adjExternal,
	Layout &drawing)
{
	// 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;
	}


	//classify brother-to-brother hierarchy edges to allow alignment
	if (m_align)
	{
		classifyEdges(PG, adjExternal);
	}//if align
	//compaction with scaling: help node cages to pass by each other
	double l_orsep = m_separation;
	if (m_useScalingCompaction)
	{
		m_scalingSteps = 6;
		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();

	//check preconditions, currently not necessary
	//assureDrawability(PG);

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

	// determine orthogonal shape
	OrthoRep OR;

	//OrthoFormerUML OF;
	OrthoShaper OFG;

	//set some options
	OFG.align(m_align);    //align brother objects on hierarchy levels
	OFG.traditional(m_orthoStyle > 0 ? false : true); //prefer 90/270 degree angles over 180/180

	// New Call
	OFG.setBendBound(m_bendBound);
	OFG.call(PG,E,OR);

	// remove face splitter
	edge e, eSucc;
	for(e = PG.firstEdge(); e; e = eSucc)
	{
		eSucc = e->succ();
		if(PG.faceSplitter(e)) {
			OR.angle(e->adjSource()->cyclicPred()) = 2;
			OR.angle(e->adjTarget()->cyclicPred()) = 2;
			PG.delEdge(e);
		}
	}

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

	// apply constructive compaction heuristics

	OR.normalize();
	OR.dissect2(&PG); //OR.dissect();

	OR.orientate(PG,m_preferedDir);

	// compute cage information and routing channels
	OR.computeCageInfoUML(PG);

	// adjust value of cOverhang
	if(m_cOverhang < 0.05)
		m_cOverhang = 0.0;
	if(m_cOverhang > 0.5)
		m_cOverhang = 0.5;

	//temporary grid layout
	GridLayoutMapped gridDrawing(PG,OR,m_separation,m_cOverhang,2);

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