1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/**
* @file
* @brief API fdpgen/fdp.h: @ref fdp_init_node_edge, @ref fdp_cleanup
*/
/*************************************************************************
* 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
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors: Details at https://graphviz.org
*************************************************************************/
/* fdpinit.c:
* Written by Emden R. Gansner
*
* Mostly boilerplate initialization and cleanup code.
*/
/* uses PRIVATE interface */
#define FDP_PRIVATE 1
#include <fdpgen/tlayout.h>
#include <neatogen/neatoprocs.h>
#include <stdbool.h>
#include <util/agxbuf.h>
#include <util/alloc.h>
static void initialPositions(graph_t * g)
{
int i;
node_t *np;
attrsym_t *possym;
attrsym_t *pinsym;
double *pvec;
char *p;
char c;
possym = agattr_text(g,AGNODE, "pos", NULL);
if (!possym)
return;
pinsym = agattr_text(g,AGNODE, "pin", NULL);
for (i = 0; (np = GD_neato_nlist(g)[i]); i++) {
p = agxget(np, possym);
if (p[0]) {
pvec = ND_pos(np);
c = '\0';
if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) {
if (PSinputscale > 0.0) {
int j;
for (j = 0; j < NDIM; j++)
pvec[j] = pvec[j] / PSinputscale;
}
ND_pinned(np) = P_SET;
if (c == '!'
|| (pinsym && mapbool(agxget(np, pinsym))))
ND_pinned(np) = P_PIN;
} else
fprintf(stderr,
"Warning: node %s, position %s, expected two floats\n",
agnameof(np), p);
}
}
}
/* init_edge:
*/
static void init_edge(edge_t * e, attrsym_t * E_len)
{
agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //node custom data
ED_factor(e) = late_double(e, E_weight, 1.0, 0.0);
ED_dist(e) = late_double(e, E_len, fdp_parms->K, 0.0);
common_init_edge(e);
}
static void init_node(node_t * n)
{
common_init_node(n);
ND_pos(n) = gv_calloc(GD_ndim(agraphof(n)), sizeof(double));
gv_nodesize(n, GD_flip(agraphof(n)));
}
void fdp_init_node_edge(graph_t * g)
{
attrsym_t *E_len;
node_t *n;
edge_t *e;
int nn;
int i;
aginit(g, AGNODE, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true);
processClusterEdges(g);
/* Get node count after processClusterEdges(), as this function may
* add new nodes.
*/
nn = agnnodes(g);
GD_neato_nlist(g) = gv_calloc(nn + 1, sizeof(node_t*));
for (i = 0, n = agfstnode(g); n; n = agnxtnode(g, n)) {
init_node (n);
GD_neato_nlist(g)[i] = n;
ND_id(n) = i++;
}
E_len = agattr_text(g,AGEDGE, "len", NULL);
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
init_edge(e, E_len);
}
}
initialPositions(g);
}
static void cleanup_subgs(graph_t * g)
{
graph_t *subg;
int i;
for (i = 1; i <= GD_n_cluster(g); i++) {
subg = GD_clust(g)[i];
free_label(GD_label(subg));
if (GD_alg(subg)) {
free(PORTS(subg));
free(GD_alg(subg));
}
cleanup_subgs(subg);
}
free (GD_clust(g));
}
static void fdp_cleanup_graph(graph_t * g)
{
cleanup_subgs(g);
free(GD_neato_nlist(g));
free(GD_alg(g));
}
void fdp_cleanup(graph_t * g)
{
node_t *n;
edge_t *e;
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
gv_cleanup_edge(e);
}
gv_cleanup_node(n);
}
fdp_cleanup_graph(g);
}
/**
* @dir lib/fdpgen
* @brief [Force-Directed Placement](https://en.wikipedia.org/wiki/Force-directed_graph_drawing) layout engine, API fdpgen/fdp.h
* @ingroup engines
*
* [FDP layout user manual](https://graphviz.org/docs/layouts/fdp/)
*
* Other @ref engines
*/
|