Skip to content

Commit

Permalink
chore: Minor tweaks to graphviz refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
GordonSmith committed Jan 17, 2024
2 parents 9466103 + dc1dd27 commit 7861b31
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 176 deletions.
9 changes: 6 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
"version": "0.2.0",
"configurations": [
{
"name": "index.html",
"name": "index-browser",
"type": "msedge",
"request": "launch",
"url": "http://localhost:8000/index.html",
"runtimeArgs": [],
"webRoot": "${workspaceRoot}"
"webRoot": "${workspaceRoot}",
"sourceMapPathOverrides": {
"webpack:///./*": "${workspaceRoot}/*",
"webpack:///*": "/*"
},
},
{
"name": "file:///index.html",
Expand Down
3 changes: 3 additions & 0 deletions src-cpp/graphviz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ set_property(SOURCE main.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINA
# --- --- ---

set(SRCS
main.hpp
main.cpp
util.hpp
util.cpp
)

include_directories(
Expand Down
211 changes: 56 additions & 155 deletions src-cpp/graphviz/main.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#include "main.hpp"

#include <gvc.h>
// #include <globals.h>
#include <gvplugin.h>
#include <graphviz_version.h>
#include <fstream>
// #include <cgraph++/AGraph.h>
// #include <gvc++/GVContext.h>
// #include <gvc++/GVLayout.h>
// #include <gvc++/GVRenderData.h>

#include <emscripten.h>

Expand Down Expand Up @@ -40,11 +34,11 @@ lt_symlist_t lt_preloaded_symbols[] = {
{"gvplugin_core_LTX_library", &gvplugin_core_LTX_library},
{0, 0}};

char lastErrorStr[1024];
StringBuffer lastErrorStr;

int vizErrorf(char *buf)
{
strncpy(lastErrorStr, buf, sizeof(lastErrorStr) - 1);
lastErrorStr = buf;
return 0;
}

Expand All @@ -67,6 +61,11 @@ Graphviz::Graphviz(int yInvert, int nop)
{
Y_invert = yInvert > 0 ? yInvert : origYInvert;
Nop = nop > 0 ? nop : origNop;

lastErrorStr = "";
agseterr(AGERR);
agseterrf(vizErrorf);
agreadline(1);
}

Graphviz::~Graphviz()
Expand All @@ -86,182 +85,84 @@ void Graphviz::createFile(const char *path, const char *data)
path, data);
}

const char *Graphviz::lastResult()
{
return m_result.c_str();
}

const char *Graphviz::layout(const char *src, const char *format, const char *engine)
{
lastErrorStr[0] = '\0';
m_result = "";

// const auto demand_loading = false;
// auto gvc = std::make_shared<GVC::GVContext>(lt_preloaded_symbols, demand_loading);
// auto g = std::make_shared<CGraph::AGraph>(dot);
// const auto layout = GVC::GVLayout(gvc, g, engine);
// const auto result = layout.render(format);
// m_result = result.string_view();

// return m_result.c_str();
layout_result = "";

GVC_t *gvc = gvContextPlugins(lt_preloaded_symbols, true);

agseterr(AGERR);
agseterrf(vizErrorf);

agreadline(1);

Agraph_t *graph;
char *data = NULL;
unsigned int length;
while ((graph = agmemread(src)))
Agraph_t *graph = agmemread(src);
if (graph)
{
if (data == NULL)
{
gvLayout(gvc, graph, engine);
gvRenderData(gvc, graph, format, &data, &length);
gvFreeLayout(gvc, graph);
}

char *data = NULL;
unsigned int length;

gvLayout(gvc, graph, engine);
gvRenderData(gvc, graph, format, &data, &length);
layout_result = data;
gvFreeRenderData(data);
gvFreeLayout(gvc, graph);
agclose(graph);

src = "";
}
m_result = data;
gvFreeRenderData(data);

gvFinalize(gvc);
gvFreeContext(gvc);

return m_result.c_str();
}

int myindegree(Agnode_t *n)
{
return agdegree(n->root, n, TRUE, FALSE);
return layout_result;
}

/* need outdegree without selfarcs */
int myoutdegree(Agnode_t *n)
bool Graphviz::acyclic(const char *src, bool doWrite, bool verbose)
{
Agedge_t *e;
int rv = 0;
acyclic_outFile = "";
acyclic_num_rev = 0;
bool retVal = false;

for (e = agfstout(n->root, n); e; e = agnxtout(n->root, e))
Agraph_t *graph = agmemread(src);
if (graph)
{
if (agtail(e) != aghead(e))
rv++;
TempFileBuffer outFile;
graphviz_acyclic_options_t opts = {outFile, doWrite, verbose};
retVal = graphviz_acyclic(graph, &opts, &acyclic_num_rev);
acyclic_outFile = outFile;
agclose(graph);
}
return rv;
}

bool isleaf(Agnode_t *n)
{
return myindegree(n) + myoutdegree(n) == 1;
return retVal;
}

bool ischainnode(Agnode_t *n)
void Graphviz::tred(const char *src, bool verbose, bool printRemovedEdges)
{
return myindegree(n) == 1 && myoutdegree(n) == 1;
}

void adjustlen(Agedge_t *e, Agsym_t *sym, int newlen)
{
char buf[12];
tred_out = "";
tred_err = "";

snprintf(buf, sizeof(buf), "%d", newlen);
agxset(e, sym, buf);
Agraph_t *graph = agmemread(src);
if (graph)
{
TempFileBuffer out;
TempFileBuffer err;
graphviz_tred_options_t opts = {verbose, printRemovedEdges, out, err};
graphviz_tred(graph, &opts);
tred_out = out;
tred_err = err;
agclose(graph);
}
}

Agsym_t *bindedgeattr(Agraph_t *g, const char *str)
const char *Graphviz::unflatten(const char *src, int maxMinlen, bool do_fans, int chainLimit)
{
return agattr(g, AGEDGE, const_cast<char *>(str), "");
}
unflatten_out = "";

const char *Graphviz::unflatten(const char *src, unsigned int MaxMinlen, bool Do_fans, unsigned int ChainLimit)
{
lastErrorStr[0] = '\0';
m_result = "";
Agraph_t *g = agmemread(src);
if (g)
Agraph_t *graph = agmemread(src);
if (graph)
{
graphviz_unflatten_options_t opts = {do_fans, maxMinlen, chainLimit};
graphviz_unflatten(graph, &opts);

Agnode_t *ChainNode;
unsigned int ChainSize = 0;

Agnode_t *n;
Agedge_t *e;
char *str;
Agsym_t *m_ix, *s_ix;
int cnt, d;

m_ix = bindedgeattr(g, "minlen");
s_ix = bindedgeattr(g, "style");

for (n = agfstnode(g); n; n = agnxtnode(g, n))
{
d = myindegree(n) + myoutdegree(n);
if (d == 0)
{
if (ChainLimit < 1)
continue;
if (ChainNode)
{
e = agedge(g, ChainNode, n, const_cast<char *>(""), TRUE);
agxset(e, s_ix, "invis");
ChainSize++;
if (ChainSize < ChainLimit)
ChainNode = n;
else
{
ChainNode = NULL;
ChainSize = 0;
}
}
else
ChainNode = n;
}
else if (d > 1)
{
if (MaxMinlen < 1)
continue;
cnt = 0;
for (e = agfstin(g, n); e; e = agnxtin(g, e))
{
if (isleaf(agtail(e)))
{
str = agxget(e, m_ix);
if (str[0] == 0)
{
adjustlen(e, m_ix, cnt % MaxMinlen + 1);
cnt++;
}
}
}

cnt = 0;
for (e = agfstout(g, n); e; e = agnxtout(g, e))
{
if (isleaf(e->node) || (Do_fans && ischainnode(e->node)))
{
str = agxget(e, m_ix);
if (str[0] == 0)
adjustlen(e, m_ix, cnt % MaxMinlen + 1);
cnt++;
}
}
}
}
FILE *fp = fopen("tmp.dot", "w");
agwrite(g, fp);
fclose(fp);
std::ifstream file("tmp.dot");
std::string graph_str((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
remove("tmp.dot");
m_result = graph_str;
TempFileBuffer tempFile;
agwrite(graph, tempFile);
unflatten_out = tempFile;
agclose(graph);
}
return m_result.c_str();
return unflatten_out;
}

// Include JS Glue ---
Expand Down
20 changes: 14 additions & 6 deletions src-cpp/graphviz/main.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
#include <string>
#include "util.hpp"

class Graphviz
{
private:
std::string m_result;

public:
static const char *version();
static const char *lastError();
Expand All @@ -13,7 +10,18 @@ class Graphviz
~Graphviz();

void createFile(const char *path, const char *data);
const char *lastResult();

StringBuffer layout_result;
const char *layout(const char *dot, const char *format, const char *engine);
const char *unflatten(const char *dot, unsigned int MaxMinlen = 0, bool Do_fans = false, unsigned int ChainLimit = 0);

StringBuffer acyclic_outFile;
size_t acyclic_num_rev;
bool acyclic(const char *dot, bool doWrite = false, bool verbose = false);

StringBuffer tred_out;
StringBuffer tred_err;
void tred(const char *dot, bool verbose = false, bool printRemovedEdges = false);

StringBuffer unflatten_out;
const char *unflatten(const char *dot, int maxMinlen = 0, bool do_fans = false, int chainLimit = 0);
};
12 changes: 11 additions & 1 deletion src-cpp/graphviz/main.idl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ interface Graphviz
[Const] static DOMString version();
[Const] static DOMString lastError();
void createFile([Const] DOMString file, [Const] DOMString data);
[Const] DOMString lastResult();

[Const] attribute DOMString layout_result;
[Const] DOMString layout([Const] DOMString dot, [Const] DOMString format, [Const] DOMString engine);

[Const] attribute DOMString acyclic_outFile;
attribute long acyclic_num_rev;
boolean acyclic([Const] DOMString dot, boolean doWrite, boolean verbose);

[Const] attribute DOMString tred_out;
[Const] attribute DOMString tred_err;
void tred([Const] DOMString dot, boolean verbose, boolean printRemovedEdges);

[Const] DOMString unflatten([Const] DOMString dot, long MaxMinlen, boolean Do_fans, long ChainLimit);
};

0 comments on commit 7861b31

Please sign in to comment.