Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unflatten functionality #56

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cgraph/cgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ func ParseBytes(bytes []byte) (*Graph, error) {
return toGraph(graph), nil
}

func UnflattenGraph(graph *Graph, maxMinlen int, chainLimit int, doFans bool) *Graph {
ccall.Transform(graph.Agraph, maxMinlen, chainLimit, doFans)
return graph
}

func ParseFile(path string) (*Graph, error) {
file, err := ioutil.ReadFile(path)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions graphviz.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func ParseBytes(bytes []byte) (*cgraph.Graph, error) {
return graph, nil
}

func UnflattenGraph(graph *cgraph.Graph, maxMinlen int, chainLimit int, doFans bool) *cgraph.Graph {
return cgraph.UnflattenGraph(graph, maxMinlen, chainLimit, doFans)
}

func New() *Graphviz {
return &Graphviz{
ctx: gvc.New(),
Expand Down
1 change: 1 addition & 0 deletions internal/ccall/unflatten.c
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "unflatten/unflatten.c"
17 changes: 17 additions & 0 deletions internal/ccall/unflatten.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ccall

/*
#cgo CFLAGS: -Iunflatten
#include "unflatten.h"
*/
import "C"

func Transform(g *Agraph, maxMinlen int, chainLimit int, doFans bool) {
var doFansValue int
if doFans {
doFansValue = 1
} else {
doFansValue = 0
}
C.transform(g.c, C.int(maxMinlen), C.int(chainLimit), C.int(doFansValue))
}
132 changes: 132 additions & 0 deletions internal/ccall/unflatten/unflatten.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*************************************************************************
* Copyright (c) 2011 AT&T Intellectual Property
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Details at https://graphviz.org
*************************************************************************/


/*
* Written by Stephen North
* Updated by Emden Gansner
* https://gitlab.com/graphviz/graphviz/-/blob/main/cmd/tools/unflatten.c
*/
#include "config.h"

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <cgraph/cgraph.h>
#include <ingraphs/ingraphs.h>
#include <unflatten/unflatten.h>

#include <getopt.h>

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

/* need outdegree without selfarcs */
int myoutdegree(Agnode_t *n)
{
Agedge_t *e;
int rv = 0;

for (e = agfstout(n->root, n); e; e = agnxtout(n->root, e)) {
if (agtail(e) != aghead(e)) rv++;
}
return rv;
}

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

bool ischainnode(Agnode_t * n)
{
return myindegree(n) == 1 && myoutdegree(n) == 1;
}

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

snprintf(buf, sizeof(buf), "%d", newlen);
agxset(e, sym, buf);
}

Agsym_t *bindedgeattr(Agraph_t * g, char *str)
{
return agattr(g, AGEDGE, str, "");
}

void transform(Agraph_t * g, int maxMinlen, int chainLimit, int doFans)
{
bool Do_fans = doFans == 1;
int chainSize = 0;
Agnode_t *chainNode = NULL;
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, "", 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++;
}
}
}
}
}
3 changes: 3 additions & 0 deletions internal/ccall/unflatten/unflatten.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <cgraph.h>

void transform(Agraph_t * g, int maxMinlen, int chainLimit, int doFans);