1. 程式人生 > 其它 >利用C++&Graphviz完成繪圖任務

利用C++&Graphviz完成繪圖任務

技術標籤:集合論與圖論c++

前傳:Graphviz解決圖論簡單畫圖

問題背景

Graphviz是個好東西啊,但是可惜的是我並沒有找到可以直接用C++畫圖的程式?(可能是我找的不對勁?

需求: 完成一個C++類,能夠通過C++類中的函式呼叫等方法完成繪圖工作。

前提: 已經完成Graphviz的安裝,並且把對應的路徑加入到系統的PATH中,即“前傳”部分已經完成。

解決方案

  1. 完成一個C++畫圖類,類比python networkx那種,可以呼叫函式來畫圖。
  2. 建立一個臨時檔案,按照過程寫入Graphviz的dot檔案
  3. 能夠區分有向圖跟無向圖
  4. 未完待續…

應用例項

//main.cpp

#include
"DrawGraph.h"
int main() { DrawGraph d; d.Start(); d.Create_Node("TEST1"); d.Create_Node("TEST2"); d.Create_Relationship("TEST1", "TEST2", DrawGraph::Graph, "knows"); d.End(); d.Get_Png("H:/test.png"); return 0; }

生成圖片:

示例圖片

Future Work

  1. 增加節點的多種屬性設定,基本按照Graphviz的Attribute來設定
  2. 增加子圖模式,允許在整張圖之中增加子圖。
  3. 增加邊的多種屬性模式,包括形狀顏色等。
  4. 提供面向物件的建模方式,方便快速排版生成的dot檔案。
  5. 允許對其中的節點進行層級排布,允許加入順序關係。
  6. 支援html等格式的初始化節點。
  7. 支援從鄰接矩陣、鄰接表中匯入圖形。
  8. 未完待續…

Code

//DrawGraph.h

#pragma once
#include <map>
#include <string>
#include <fstream>

class DrawGraph
{
private
: std::map<std::string, int> str2int; std::map<int, std::string> int2str; std::string temp_file = "./temp.tp"; int node_cnt = 0, rela_cnt = 0; public: static const int DiGraph = 1, Graph = 0; void Start(int mode = 0);//開始畫圖的之前需要選定畫圖模式,DrawGraph::DiGraph or DrawGraph::Graph int Create_Node(std::string node_name);//建立一個節點,並且節點名稱為node_name int Create_Node(int node_name);//建立一個節點,節點名為一個整數數字 int Find_Node(std::string node_name);//根據節點名稱找到節點編號(方便上層開發的時候,不需要存下每個建立過的節點的具體名字,只需要存數字即可) std::string Find_Node(int node_id);//通過節點的編號找到節點的名稱 int Create_Relationship(std::string start_name, std::string end_name, int mode = 0, std::string label = "");//建立一個邊,mode是有向圖和無向圖兩種,label是邊上的標籤 int Create_Relationship(int start_id, int end_id, int mode = 0, std::string label = "");//根據節點編號建立邊,仍然是方便上層開發 void End();//表示這個圖畫完了 void Print_Dot(std::string file_path);//把.dot檔案生成到指定的目錄下,方便使用和人工更改。file_path最好是以".dot"結尾。 void Get_Png(std::string file_path);//畫圖,file_path以png結尾,表示最後輸出的圖片目錄 };
//DrawGraph.cpp

#include "DrawGraph.h"

void DrawGraph::Start(int mode)
{
	FILE* fp = fopen(temp_file.c_str(), "w");
	if (mode == DiGraph)
		fprintf(fp, "digraph my_graph{\n");
	else if (mode == Graph)
		fprintf(fp, "graph my_graph{\n");
	fclose(fp);
}

int DrawGraph::Create_Node(std::string node_name)
{
	FILE* fp = fopen(temp_file.c_str(), "a");
	str2int[node_name] = ++node_cnt;
	int2str[node_cnt] = node_name;

	fprintf(fp, "\t%s;\n", node_name.c_str());

	fclose(fp);
	return node_cnt;
}

int DrawGraph::Create_Node(int node_name)
{
	std::string str_node_name = std::to_string(node_name);
	return Create_Node(str_node_name);
}

int DrawGraph::Find_Node(std::string node_name)
{
	if (str2int.find(node_name) == str2int.end())
		return -1;
	return str2int[node_name];
}

std::string DrawGraph::Find_Node(int node_id)
{
	if (node_id > node_cnt || node_id <= 0)
		return std::string();
	return int2str[node_id];
}

int DrawGraph::Create_Relationship(std::string start_name, std::string end_name, int mode, std::string label)
{
	FILE* fp = fopen(temp_file.c_str(), "a");

	fprintf(fp, "\t%s ", start_name.c_str());

	if (mode == DiGraph) {
		fprintf(fp, " -> ");
	}
	else if (mode == Graph) {
		fprintf(fp, " -- ");
	}

	fprintf(fp, " %s ", end_name.c_str());

	if (label != std::string("")) {
		fprintf(fp, "[label=%s]", label.c_str());
	}

	fprintf(fp, ";\n");

	fclose(fp);
	return ++rela_cnt;
}

int DrawGraph::Create_Relationship(int start_id, int end_id, int mode, std::string label)
{
	if (Find_Node(start_id) == std::string() || Find_Node(end_id) == std::string())
		return -1;
	return Create_Relationship(Find_Node(start_id), Find_Node(end_id), mode, label);
}

void DrawGraph::End()
{
	FILE* fp = fopen(temp_file.c_str(), "a");

	fprintf(fp, "}");

	fclose(fp);
}

void DrawGraph::Print_Dot(std::string file_path)
{
	std::ifstream in(temp_file.c_str());
	std::ofstream out(file_path.c_str());
	out << in.rdbuf();
	in.close();
	out.close();
}

void DrawGraph::Get_Png(std::string file_path)
{
	std::string command = "dot -Tpng " + temp_file + " -o " + file_path;
	system(command.c_str());
}

參考文獻&擴充套件閱讀

Graphviz官網

Graphviz文獻集

Graphviz原始碼

Python-Graphviz

語雀-Graphviz教程

WebGraphviz