# include/net/network_draw.hpp
# Namespaces
Name |
---|
net |
# Source code
#ifndef NET_NETWORK_DRAW_HPP
#define NET_NETWORK_DRAW_HPP
#include "error.hpp"
#include "gviz.hpp"
#include "network.hpp"
#include "node.hpp"
#include <cstdlib>
#include <fstream>
#include <initializer_list>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#ifdef NET_GRAPH_VIZ
#include <graphviz/cgraph.h>
#include <graphviz/gvc.h>
#ifdef NET_SHOW_FIG_USE_CLING
#include <unistd.h>
#endif
#endif
namespace net {
std::string base64_encode(const std::string & in);
#ifdef NET_GRAPH_VIZ
std::string render(std::string dot_content, const std::string & engine);
void show_fig(const std::string & fig_content, bool tmux, bool st);
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void
network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::draw_to_file(const std::string & filename, const std::string & title, const bool label_bond) const {
draw(filename, {{}}, label_bond);
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::draw_to_file(
const std::string & filename,
const std::string & title,
const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> & contains,
const bool label_bond) const {
std::ofstream fig_file(filename, std::ios::binary);
if (this->size() > 0)
fig_file << render(gviz(contains, label_bond), "sfdp");
}
inline std::string render(std::string dot_content, const std::string & engine) {
GVC_t * gvc;
Agraph_t * g;
char * cres;
std::string res;
unsigned int len;
gvc = gvContext();
g = agmemread(dot_content.c_str());
gvLayout(gvc, g, engine.c_str());
gvRenderData(gvc, g, "png", &cres, &len);
res = std::string(cres, len);
gvFreeRenderData(cres);
gvFreeLayout(gvc, g);
agclose(g);
return res;
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::draw(const std::string & title, const bool label_bond) const {
draw(title, {{}}, label_bond);
}
template <typename NodeVal, typename EdgeVal, typename NodeKey, typename EdgeKey, typename Trait>
void network<NodeVal, EdgeVal, NodeKey, EdgeKey, Trait>::draw(
const std::string & title,
const std::vector<std::set<NodeKey, typename Trait::nodekey_less>> & contains,
const bool label_bond) const {
consistency();
if (this->size() == 0) {
std::cout << "-----------------------------------------------\n";
std::cout << "empty lattice\n";
std::cout << "-----------------------------------------------\n";
} else {
show_fig(render(gviz(title, contains, label_bond), "sfdp"), false, false);
show_fig(render(gviz_legend(contains), "neato"), false, true);
}
}
#ifdef NET_SHOW_FIG_USE_CLING
extern int pipeToJupyterFD;
// https://github.com/root-project/cling/blob/0c880f8472f5a313095203ccd35561b0097b13ec/tools/Jupyter/Kernel.cpp#L54
inline bool show_mime(const std::map<std::string, std::string> & contentDict) {
unsigned char sizeLong = sizeof(long);
if (write(pipeToJupyterFD, &sizeLong, 1) != 1)
return false;
long dictSize = contentDict.size();
if (write(pipeToJupyterFD, &dictSize, sizeof(long)) != sizeof(long))
return false;
for (auto iContent : contentDict) {
const std::string & mimeType = iContent.first;
long mimeTypeSize = (long)mimeType.size();
if (write(pipeToJupyterFD, &mimeTypeSize, sizeof(long)) != sizeof(long))
return false;
if (write(pipeToJupyterFD, mimeType.c_str(), mimeType.size() + 1) != (long)(mimeType.size() + 1))
return false;
const std::string & mimeData = iContent.second;
const long string_size = mimeData.size();
if (write(pipeToJupyterFD, &string_size, sizeof(long)) != sizeof(long))
return false;
if (write(pipeToJupyterFD, mimeData.data(), string_size) != string_size)
return false;
}
return true;
}
#endif
inline void show_fig(const std::string & fig_content, bool tmux, bool stop_tag) {
#if defined NET_SHOW_FIG_USE_ITERM
if (tmux) {
std::cout << "\033Ptmux;\033\033]";
} else {
std::cout << "\033]";
}
std::cout << "1337;File=;inline=1:";
std::cout << base64_encode(fig_content);
if (tmux) {
std::cout << "\a\033\\";
} else {
std::cout << "\a";
}
std::cout << "\n";
if (stop_tag) {
std::cout << "\x1B[31mPaused.\x1B[0m Please press enter to continue.\n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
#elif defined NET_SHOW_FIG_USE_CLING
show_mime({{"text/html", "<img src='data:image/png;base64, " + base64_encode(fig_content) + "'></img>"}});
#elif defined NET_SHOW_FIG_USE_GWENVIEW
std::ofstream("/tmp/net_tmp.png") << fig_content;
std::system("gwenview /tmp/net_tmp.png || eog /tmp/net_tmp.png");
std::cout << "\x1B[31mPaused.\x1B[0m Please press enter to continue.\n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
#else
std::cout << "Method of showing the figure is invalid or unspecified!\n";
std::cout << "\x1B[31mPaused.\x1B[0m Please press enter to continue.\n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
#endif
}
#endif
// base64 functions are copied from
// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
// originally by Manuel Martinez
inline std::string base64_encode(const std::string & in) {
std::string out;
int val = 0, valb = -6;
for (unsigned char c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6)
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
while (out.size() % 4)
out.push_back('=');
return out;
}
inline std::string base64_decode(const std::string & in) {
std::string out;
std::vector<int> T(256, -1);
for (int i = 0; i < 64; i++)
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
int val = 0, valb = -8;
for (unsigned char c : in) {
if (T[c] == -1)
break;
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val >> valb) & 0xFF));
valb -= 8;
}
}
return out;
}
} // namespace net
#endif
Updated on 15 June 2022 at 16:04:19 CST