コード例 #1
0
ファイル: GraphIO_ogml.cpp プロジェクト: marvin2k/ogdf
// recursively write clusters and nodes
static void write_ogml_graph(const ClusterGraphAttributes &A, cluster c, int level, ostream &os)
{
	if(level > 0) {
		GraphIO::indent(os,2+level) << "<node id=\"c" << c->index() << "\">\n";
		if (A.has(GraphAttributes::nodeLabel)) {
			GraphIO::indent(os,4) << "<label id=\"lc" << c->index() << "\">\n";
			GraphIO::indent(os,5) << "<content>" << formatLabel(A.label(c)) << "</content>\n";
			GraphIO::indent(os,4) << "</label>\n";
		}
	}

	ListConstIterator<node> itn;
	for (itn = c->nBegin(); itn.valid(); ++itn) {
		node v = *itn;
		GraphIO::indent(os,3+level) << "<node id=\"n" << v->index() << "\">\n";
		if (A.has(GraphAttributes::nodeLabel)) {
			GraphIO::indent(os,4) << "<label id=\"ln" << v->index() << "\">\n";
			GraphIO::indent(os,5) << "<content>" << formatLabel(A.label(v)) << "</content>\n";
			GraphIO::indent(os,4) << "</label>\n";
		}
		GraphIO::indent(os,3+level) << "</node>\n";
	}

	for (cluster child : c->children) {
		write_ogml_graph(child, level+1, os);
	}

	if(level > 0) {
		GraphIO::indent(os,2+level) << "</node>\n";
	}
}
コード例 #2
0
ファイル: GraphIO_dot.cpp プロジェクト: marvin2k/ogdf
static inline void writeAttributes(
	std::ostream &out, const int &depth,
	const ClusterGraphAttributes &CA, const cluster &c)
{
	GraphIO::indent(out, depth) << "color=\"" << CA.strokeColor(c) << "\"\n";
	GraphIO::indent(out, depth) << "bgcolor=\"" << CA.fillColor(c) << "\"\n";
	GraphIO::indent(out, depth) << "label=\"" << CA.label(c) << "\"\n";

	// There is no point in exporting rest of the cluster attributes, so to
	// maintain high readability they are omitted.
}
コード例 #3
0
void FMMMLayout::call(ClusterGraphAttributes &GA)
{
	const Graph &G = GA.constGraph();
	//compute depth of cluster tree, also sets cluster depth values
	const ClusterGraph &CG = GA.constClusterGraph();
	int cdepth = CG.treeDepth();
	EdgeArray<double> edgeLength(G);
	//compute lca of end vertices for each edge
	edge e;
	forall_edges(e, G)
	{
		edgeLength[e] = cdepth - CG.clusterDepth(CG.commonCluster(e->source(),e->target())) + 1;
		OGDF_ASSERT(edgeLength[e] > 0)
	}
コード例 #4
0
ファイル: GraphIO_ogml.cpp プロジェクト: marvin2k/ogdf
// write cluster layout with attributes
static void write_ogml_layout(const ClusterGraphAttributes &A, ostream &os)
{
	const ClusterGraph &C = A.constClusterGraph();

	GraphIO::indent(os,2) << "<layout>\n";
	GraphIO::indent(os,3) << "<styles>\n";

	for(cluster c : C.clusters) {
		if(c != C.rootCluster()) {
			GraphIO::indent(os,4) << "<nodeStyle idRef=\"c" << c->index() << "\">\n";

			GraphIO::indent(os,5) << "<location x=\"" << A.x(c) << "\" y=\"" << A.y(c) << "\" />\n";
			GraphIO::indent(os,5) << "<shape type=\"rect\" width=\"" << A.width(c) << "\" height=\"" << A.height(c) << "\" />\n";
			GraphIO::indent(os,5) << "<fill color=\"" << A.fillColor(c) << "\""
				<< " pattern=\"" << fillPatternToOGML(A.fillPattern(c))
				<< "\" patternColor=\""
				<< A.fillBgColor(c) << "\" />\n";
			GraphIO::indent(os,5) << "<line type=\"" << edgeStyleToOGML(A.strokeType(c)) << "\" width=\"" << A.strokeWidth(c) << "\" color=\"" << A.strokeColor(c) << "\" />\n";

			GraphIO::indent(os,4) << "</nodeStyle>\n";
		}
	}

	write_ogml_layout_nodes_edges(A,os);

	GraphIO::indent(os,3) << "</styles>\n";
	GraphIO::indent(os,2) << "</layout>\n";
}
コード例 #5
0
ファイル: GraphIO_dot.cpp プロジェクト: ogdf/ogdf
bool GraphIO::writeDOT(const ClusterGraphAttributes &CA, std::ostream &out)
{
	const Graph &G = CA.constGraph();
	const ClusterGraph &C = CA.constClusterGraph();
	int id = 1;

	// Assign a list of edges for each cluster. Perhaps usage of std::vector
	// here needs reconsideration - vector is fast but usage of STL iterators
	// is ugly without C++11 for-each loop.
	ClusterArray< std::vector<edge> > edgeMap(C);
	for(edge e : G.edges) {
		const node s = e->source(), t = e->target();
		edgeMap[C.commonCluster(s, t)].push_back(e);
	}

	return dot::writeCluster(out, 0, edgeMap, C, &CA, C.rootCluster(), id);
}
コード例 #6
0
ファイル: GraphIO_ogml.cpp プロジェクト: marvin2k/ogdf
// write cluster structure with attributes
static void write_ogml_graph(const ClusterGraphAttributes &A, ostream &os)
{
	GraphIO::indent(os,2) << "<structure>\n";

	write_ogml_graph(A, A.constClusterGraph().rootCluster(), 0, os);
	write_ogml_graph_edges(A, os);

	GraphIO::indent(os,2) << "</structure>\n";
}
コード例 #7
0
ファイル: GraphIO_gexf.cpp プロジェクト: lncosie/ogdf
bool GraphIO::writeGEXF(const ClusterGraphAttributes &CA, std::ostream &out)
{
	const ClusterGraph &C = CA.constClusterGraph();

	gexf::writeHeader(out, true);
	gexf::writeCluster(out, 1, C, &CA, C.rootCluster());
	gexf::writeFooter(out);

	return true;
}
コード例 #8
0
ファイル: GraphMLParser.cpp プロジェクト: marvin2k/ogdf
bool GraphMLParser::readData(
	ClusterGraphAttributes &CA,
	const cluster &c,
	const pugi::xml_node clusterData)
{
	auto keyId = clusterData.attribute("key");
	if (!keyId) {
		GraphIO::logger.lout() << "Cluster data does not have a key." << endl;
		return false;
	}

	pugi::xml_text text = clusterData.text();

	using namespace graphml;
	switch (toAttribute(m_attrName[keyId.value()])) {
	case a_nodeLabel:
		CA.label(c) = text.get();
		break;
	case a_x:
		CA.x(c) = text.as_double();
		break;
	case a_y:
		CA.y(c) = text.as_double();
		break;
	case a_width:
		CA.width(c) = text.as_double();
		break;
	case a_height:
		CA.height(c) = text.as_double();
		break;
	case a_size:
		// We want to set a new size only if width and height was not set.
		if (CA.width(c) == CA.height(c)) {
			CA.width(c) = CA.height(c) = text.as_double();
		}
	case a_r:
		if (!GraphIO::setColorValue(text.as_int(), [&](uint8_t val) { CA.fillColor(c).red(val); })) {
			return false;
		}
		break;
	case a_g:
		if (!GraphIO::setColorValue(text.as_int(), [&](uint8_t val) { CA.fillColor(c).green(val); })) {
			return false;
		}
		break;
	case a_b:
		if (!GraphIO::setColorValue(text.as_int(), [&](uint8_t val) { CA.fillColor(c).blue(val); })) {
			return false;
		}
		break;
	case a_clusterStroke:
		CA.strokeColor(c) = text.get();
		break;
	default:
		GraphIO::logger.lout(Logger::LL_MINOR) << "Unknown cluster attribute with \""
		             << keyId.value()
		             << "--enum: " << m_attrName[keyId.value()] << "--"
		             << "\"." << endl;
	}

	return true;
}
コード例 #9
0
ファイル: GmlParser.cpp プロジェクト: lncosie/ogdf
//recursively read cluster subtree information
bool GmlParser::recursiveAttributedClusterRead(GmlObject* clusterObject,
								ClusterGraph& CG,
								ClusterGraphAttributes& ACG,
								cluster c)
{

	//for direct root cluster sons, this is checked twice...
	if (clusterObject->m_valueType != gmlListBegin) return false;

	GmlObject *clusterSon = clusterObject->m_pFirstSon;

	for(; clusterSon; clusterSon = clusterSon->m_pBrother)
	{
		//we dont read the attributes, therefore look only for
		//id and sons
		switch(id(clusterSon))
		{
			case clusterPredefKey:
				{
					if (clusterSon->m_valueType != gmlListBegin) return false;

					cluster cson = CG.newCluster(c);
					//recursively read child cluster
					recursiveAttributedClusterRead(clusterSon, CG, ACG, cson);
				}
				break;
			case labelPredefKey:
				{
					if (clusterSon->m_valueType != gmlStringValue) return false;
					ACG.label(c) = clusterSon->m_stringValue;
				}
				break;
			case templatePredefKey:
				{
					if (clusterSon->m_valueType != gmlStringValue) return false;
					ACG.templateCluster(c) = clusterSon->m_stringValue;
					break;
				}
			case graphicsPredefKey: //read the info for cluster c
				{
					if (clusterSon->m_valueType != gmlListBegin) return false;

					readClusterAttributes(clusterSon, c , ACG);
				}//graphics
				break;
			case vertexPredefKey: //direct cluster vertex entries
				{
					if (clusterSon->m_valueType != gmlStringValue) return false;
					string vIDString = clusterSon->m_stringValue;

					if ((vIDString[0] != 'v') &&
						(!isdigit((int)vIDString[0])))return false; //do not allow labels
					//if old style entry "v"i
					if (!isdigit((int)vIDString[0])) //should check prefix?
						vIDString[0] = '0'; //leading zero to allow conversion
					int vID = stoi(vIDString);

					OGDF_ASSERT(m_mapToNode[vID] != 0)

					//we assume that no node is already assigned
					//changed: all nodes are already assigned to root
					CG.reassignNode(m_mapToNode[vID], c);

				}//case vertex
		}//switch
	}//for clustersons

	return true;
}//recursiveAttributedClusterRead
コード例 #10
0
ファイル: GmlParser.cpp プロジェクト: lncosie/ogdf
bool GmlParser::readClusterAttributes(
	GmlObject* cGraphics,
	cluster c,
	ClusterGraphAttributes& ACG)
{
	string label;
	string fill;  // the fill color attribute
	string line;  // the line color attribute
	float lineWidth = 1.0f; //node line width
	int    pattern = 1; //node brush pattern
	int    stipple = 1; //line style pattern

	// read all relevant attributes
	GmlObject *graphicsObject = cGraphics->m_pFirstSon;
	for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother)
	{
		switch(id(graphicsObject))
		{
		case xPredefKey:
			if(graphicsObject->m_valueType != gmlDoubleValue) return false;
			ACG.x(c) = graphicsObject->m_doubleValue;
			break;

		case yPredefKey:
			if(graphicsObject->m_valueType != gmlDoubleValue) return false;
			ACG.y(c) = graphicsObject->m_doubleValue;
			break;

		case widthPredefKey:
			if(graphicsObject->m_valueType != gmlDoubleValue) return false;
			ACG.width(c) = graphicsObject->m_doubleValue;
			break;

		case heightPredefKey:
			if(graphicsObject->m_valueType != gmlDoubleValue) return false;
			ACG.height(c) = graphicsObject->m_doubleValue;
			break;
		case fillPredefKey:
			if(graphicsObject->m_valueType != gmlStringValue) return false;
			ACG.fillColor(c) = graphicsObject->m_stringValue;
			break;
		case patternPredefKey:
			if(graphicsObject->m_valueType != gmlIntValue) return false;
			pattern = graphicsObject->m_intValue;
			break;
			//line style
		case colorPredefKey: // line color
			if(graphicsObject->m_valueType != gmlStringValue) return false;
			ACG.strokeColor(c) = graphicsObject->m_stringValue;
			break;

		case stipplePredefKey:
			if(graphicsObject->m_valueType != gmlIntValue) return false;
			stipple = graphicsObject->m_intValue;
			break;
		case lineWidthPredefKey:
			if(graphicsObject->m_valueType != gmlDoubleValue) return false;
			lineWidth =	(float)graphicsObject->m_doubleValue;
			break;
			//TODO: backgroundcolor
			//case stylePredefKey:
			//case boderwidthPredefKey:
		}//switch
	}//for

	//Hier eigentlich erst abfragen, ob clusterattributes setzbar in ACG,
	//dann setzen
	ACG.setStrokeType(c, intToStrokeType(stipple)); //defaulting 1
	ACG.strokeWidth(c) = lineWidth;
	ACG.setFillPattern(c, intToFillPattern(pattern));

	return true;
}//readclusterattributes
コード例 #11
0
//the call function that lets ClusterPlanarizationLayout compute a layout
//for the input using \a weight for the computation of the cluster planar subgraph
void ClusterPlanarizationLayout::call(
	Graph& G,
	ClusterGraphAttributes& acGraph,
	ClusterGraph& cGraph,
	EdgeArray<double>& edgeWeight,
	bool simpleCConnect) //default true
{
	m_nCrossings = 0;
	bool subGraph = false; // c-planar subgraph computed?

	//check some simple cases
	if (G.numberOfNodes() == 0) return;

//-------------------------------------------------------------
//we set pointers and arrays to the working graph, which can be
//the original or, in the case of non-c-planar input, a copy

	Graph* workGraph = &G;
	ClusterGraph* workCG = &cGraph;
	ClusterGraphAttributes* workACG = &acGraph;

	//potential copy of original if non c-planar
	Graph GW;
	//list of non c-planarity causing edges
	List<edge> leftEdges;

	//list of nodepairs to be connected (deleted edges)
	List<NodePair> leftWNodes;

	//store some information
	//original to copy
	NodeArray<node> resultNode(G);
	EdgeArray<edge> resultEdge(G);
	ClusterArray<cluster> resultCluster(cGraph);
	//copy to original
	NodeArray<node> orNode(G);
	EdgeArray<edge> orEdge(G);
	ClusterArray<cluster> orCluster(cGraph);

	for(node workv : G.nodes) {
		resultNode[workv] = workv; //will be set to copy if non-c-planar
		orNode[workv] = workv;
	}
	for(edge worke : G.edges) {
		resultEdge[worke] = worke; //will be set to copy if non-c-planar
		orEdge[worke] = worke;
	}
	for (cluster workc : cGraph.clusters) {
		resultCluster[workc] = workc; //will be set to copy if non-c-planar
		orCluster[workc] = workc;
	}


	//-----------------------------------------------
	//check if instance is clusterplanar and embed it
	CconnectClusterPlanarEmbed CCPE; //cccp

	bool cplanar = CCPE.embed(cGraph, G);

	List<edge> connectEdges;

	//if the graph is not c-planar, we have to check the reason and to
	//correct the problem by planarising or inserting connection edges
	if (!cplanar)
	{
		bool connect = false;

		if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) ||
				(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) )
		{
			//we insert edges to make the input c-connected
			makeCConnected(cGraph, G, connectEdges, simpleCConnect);

			//save edgearray info for inserted edges
			for(edge e : connectEdges)
			{
				resultEdge[e] = e;
				orEdge[e]     = e;
			}

			connect = true;

			CCPE.embed(cGraph, G);

			if ( (CCPE.errCode() == CconnectClusterPlanarEmbed::nonConnected) ||
				(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCConnected) )
			{
				cerr << "no correct connection made\n"<<flush;
				OGDF_THROW(AlgorithmFailureException);
			}
		}//if not cconnected
		if ((CCPE.errCode() == CconnectClusterPlanarEmbed::nonPlanar) ||
			(CCPE.errCode() == CconnectClusterPlanarEmbed::nonCPlanar))
		{
			subGraph = true;
			EdgeArray<bool> inSubGraph(G, false);

			CPlanarSubClusteredGraph cps;
			if (edgeWeight.valid())
				cps.call(cGraph, inSubGraph, leftEdges, edgeWeight);
			else
				cps.call(cGraph, inSubGraph, leftEdges);
#ifdef OGDF_DEBUG
			//			for(edge worke : G.edges) {
			//				if (inSubGraph[worke])
			//					acGraph.strokeColor(worke) = "#FF0000";
			//			}
#endif
			//---------------------------------------------------------------
			//now we delete the copies of all edges not in subgraph and embed
			//the subgraph (use a new copy)

			//construct copy

			workGraph = &GW;
			workCG = new ClusterGraph(cGraph, GW, resultCluster, resultNode, resultEdge);

			//----------------------
			//reinit original arrays
			orNode.init(GW, nullptr);
			orEdge.init(GW, nullptr);
			orCluster.init(*workCG, nullptr);

			//set array entries to the appropriate values
			for (node workv : G.nodes)
				orNode[resultNode[workv]] = workv;
			for (edge worke : G.edges)
				orEdge[resultEdge[worke]] = worke;
			for (cluster workc : cGraph.clusters)
				orCluster[resultCluster[workc]] = workc;

			//----------------------------------------------------
			//create new ACG and copy values (width, height, type)

			workACG = new ClusterGraphAttributes(*workCG, workACG->attributes());
			for (node workv : GW.nodes)
			{
				//should set same attributes in construction!!!
				if (acGraph.attributes() & GraphAttributes::nodeType)
					workACG->type(workv) = acGraph.type(orNode[workv]);
				workACG->height(workv) = acGraph.height(orNode[workv]);
				workACG->width(workv) = acGraph.width(orNode[workv]);
			}
			if (acGraph.attributes() & GraphAttributes::edgeType) {
				for (edge worke : GW.edges) {
					workACG->type(worke) = acGraph.type(orEdge[worke]);
					//all other attributes are not needed or will be set
				}
			}

			for(edge ei : leftEdges)
			{
				edge e = resultEdge[ei];
				NodePair np;
				np.m_src = e->source();
				np.m_tgt = e->target();

				leftWNodes.pushBack(np);

				GW.delEdge(e);
			}

			CconnectClusterPlanarEmbed CCP;

#ifdef OGDF_DEBUG
			bool subPlanar =
#endif
				CCP.embed(*workCG, GW);
			OGDF_ASSERT(subPlanar);
		}//if not planar
		else
		{
			if (!connect)
			OGDF_THROW_PARAM(PreconditionViolatedException, pvcClusterPlanar);
		}

	}//if

	//if multiple CCs are handled, the connectedges (their copies resp.)
	//can be deleted here

	//now CCPE should give us the external face

	ClusterPlanRep CP(*workACG, *workCG);

	OGDF_ASSERT(CP.representsCombEmbedding());

	const int numCC = CP.numberOfCCs(); //equal to one
	//preliminary
	OGDF_ASSERT(numCC == 1);

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

	for (int ikl = 0; ikl < numCC; ikl++)
	{

			CP.initCC(ikl);
			CP.setOriginalEmbedding();

			OGDF_ASSERT(CP.representsCombEmbedding())

			Layout drawing(CP);

			//m_planarLayouter.get().setOptions(4);//progressive

			adjEntry ae = nullptr;

			//internally compute adjEntry for outer face

			//edges that are reinserted in workGraph (in the same
			//order as leftWNodes)
			List<edge> newEdges;
			m_planarLayouter.get().call(CP, ae, drawing, leftWNodes, newEdges, *workGraph);

			OGDF_ASSERT(leftWNodes.size()==newEdges.size())
			OGDF_ASSERT(leftEdges.size()==newEdges.size())

			ListConstIterator<edge> itE = newEdges.begin();
			ListConstIterator<edge> itEor = leftEdges.begin();
			while (itE.valid())
			{
				orEdge[*itE] = *itEor;
				++itE;
				++itEor;
			}

			//hash index over cluster ids
			HashArray<int, ClusterPosition> CA;

			computeClusterPositions(CP, drawing, CA);

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

			for(int i = CP.startNode(); i < CP.stopNode(); ++i) {
				node vG = CP.v(i);

				acGraph.x(orNode[vG]) = drawing.x(CP.copy(vG));
				acGraph.y(orNode[vG]) = drawing.y(CP.copy(vG));

				for(adjEntry adj : vG->adjEdges)
				{
					if ((adj->index() & 1) == 0) continue;
					edge eG = adj->theEdge();

					edge orE = orEdge[eG];
					if (orE)
						drawing.computePolylineClear(CP,eG,acGraph.bends(orE));
				}

			}//for

			//even assignment for all nodes is not enough, we need all clusters
			for(cluster c : workCG->clusters)
			{
				int clNumber = c->index();
				//int orNumber = originalClId[c];
				cluster orCl = orCluster[c];

				if (c != workCG->rootCluster())
				{
					OGDF_ASSERT(CA.isDefined(clNumber));
					acGraph.height(orCl) = CA[clNumber].m_height;
					acGraph.width(orCl) = CA[clNumber].m_width;
					acGraph.y(orCl) = CA[clNumber].m_miny;
					acGraph.x(orCl) = CA[clNumber].m_minx;
				}//if real cluster
			}

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

	}//for connected components

	//postProcess(acGraph);
	//
	// arrange layouts of connected components
	//

	Array<DPoint> offset(numCC);

	m_packer.get().call(boundingBox,offset,m_pageRatio);

	// The arrangement is given by offset to the origin of the coordinate
	// system. We still have to shift each node, edge and cluster by the offset
	// of its connected component.

	const Graph::CCsInfo &ccInfo = CP.ccInfo();
	for(int i = 0; i < numCC; ++i)
	{
		const double dx = offset[i].m_x;
		const double dy = offset[i].m_y;

		HashArray<int, bool> shifted(false);

		// iterate over all nodes in ith CC
		for(int j = ccInfo.startNode(i); j < ccInfo.stopNode(i); ++j)
		{
			node v = ccInfo.v(j);

			acGraph.x(orNode[v]) += dx;
			acGraph.y(orNode[v]) += dy;

			// update cluster positions accordingly
			//int clNumber = cGraph.clusterOf(orNode[v])->index();
			cluster cl = cGraph.clusterOf(orNode[v]);

			if ((cl->index() > 0) && !shifted[cl->index()])
			{
				acGraph.y(cl) += dy;
				acGraph.x(cl) += dx;
				shifted[cl->index()] = true;
			}//if real cluster

			for(adjEntry adj : v->adjEdges) {
				if ((adj->index() & 1) == 0) continue;
				edge e = adj->theEdge();

				//edge eOr = orEdge[e];
				if (orEdge[e])
				{
					DPolyline &dpl = acGraph.bends(orEdge[e]);
					for(DPoint &p : dpl) {
						p.m_x += dx;
						p.m_y += dy;
					}
				}
			}
		}//for nodes
	}//for numcc


	while (!connectEdges.empty()) {
		G.delEdge(connectEdges.popFrontRet());
	}

	if (subGraph)
	{
		//originalClId.init();
		orCluster.init();
		orNode.init();
		orEdge.init();
		delete workCG;
		delete workACG;
	}//if subgraph created

	acGraph.removeUnnecessaryBendsHV();

}//call