Graphviz 14.1.3~dev.20260124.0732
Loading...
Searching...
No Matches
sameport.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/* vladimir@cs.ualberta.ca, 9-Dec-1997
13 * merge edges with specified samehead/sametail onto the same port
14 */
15
16#include "config.h"
17
18#include <math.h>
19#include <dotgen/dot.h>
20#include <stdbool.h>
21#include <stddef.h>
22#include <util/list.h>
23#include <util/streq.h>
24
25typedef LIST(edge_t *) edge_list_t;
26
27typedef struct same_t {
28 char *id; /* group id */
29 edge_list_t l; // edges in the group
31
32static void free_same(same_t s) {
33 LIST_FREE(&s.l);
34}
35
36typedef LIST(same_t) same_list_t;
37
38static void sameedge(same_list_t *same, edge_t *e, char *id);
39static void sameport(node_t *u, edge_list_t l);
40
41void dot_sameports(graph_t * g)
42/* merge edge ports in G */
43{
44 node_t *n;
45 edge_t *e;
46 char *id;
47 same_list_t samehead = {.dtor = free_same};
48 same_list_t sametail = {.dtor = free_same};
49
50 E_samehead = agattr_text(g, AGEDGE, "samehead", NULL);
51 E_sametail = agattr_text(g, AGEDGE, "sametail", NULL);
52 if (!(E_samehead || E_sametail))
53 return;
54 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
55 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
56 if (aghead(e) == agtail(e)) continue; /* Don't support same* for loops */
57 if (aghead(e) == n && E_samehead &&
58 (id = agxget(e, E_samehead))[0])
59 sameedge(&samehead, e, id);
60 else if (agtail(e) == n && E_sametail &&
61 (id = agxget(e, E_sametail))[0])
62 sameedge(&sametail, e, id);
63 }
64 for (size_t i = 0; i < LIST_SIZE(&samehead); i++) {
65 if (LIST_SIZE(&LIST_AT(&samehead, i)->l) > 1)
66 sameport(n, LIST_GET(&samehead, i).l);
67 }
68 LIST_CLEAR(&samehead);
69 for (size_t i = 0; i < LIST_SIZE(&sametail); i++) {
70 if (LIST_SIZE(&LIST_AT(&sametail, i)->l) > 1)
71 sameport(n, LIST_GET(&sametail, i).l);
72 }
73 LIST_CLEAR(&sametail);
74 }
75
76 LIST_FREE(&samehead);
77 LIST_FREE(&sametail);
78}
79
81static void sameedge(same_list_t *same, edge_t *e, char *id) {
82 for (size_t i = 0; i < LIST_SIZE(same); i++)
83 if (streq(LIST_GET(same, i).id, id)) {
84 LIST_APPEND(&LIST_AT(same, i)->l, e);
85 return;
86 }
87
88 same_t to_append = {.id = id};
89 LIST_APPEND(&to_append.l, e);
90 LIST_APPEND(same, to_append);
91}
92
93static void sameport(node_t *u, edge_list_t l)
94/* make all edges in L share the same port on U. The port is placed on the
95 node boundary and the average angle between the edges. FIXME: this assumes
96 naively that the edges are straight lines, which is wrong if they are long.
97 In that case something like concentration could be done.
98
99 An arr_port is also computed that's ARR_LEN away from the node boundary.
100 It's used for edges that don't themselves have an arrow.
101*/
102{
103 node_t *v;
104 edge_t *f;
105 double x = 0, y = 0, x1, y1, x2, y2, r;
106
107 /* Compute the direction vector (x,y) of the average direction. We compute
108 with direction vectors instead of angles because else we have to first
109 bring the angles within PI of each other. av(a,b)!=av(a,b+2*PI) */
110 for (size_t i = 0; i < LIST_SIZE(&l); i++) {
111 edge_t *e = LIST_GET(&l, i);
112 if (aghead(e) == u)
113 v = agtail(e);
114 else
115 v = aghead(e);
116 x1 = ND_coord(v).x - ND_coord(u).x;
117 y1 = ND_coord(v).y - ND_coord(u).y;
118 r = hypot(x1, y1);
119 x += x1 / r;
120 y += y1 / r;
121 }
122 r = hypot(x, y);
123 x /= r;
124 y /= r;
125
126 /* (x1,y1),(x2,y2) is a segment that must cross the node boundary */
127 x1 = ND_coord(u).x;
128 y1 = ND_coord(u).y; /* center of node */
129 r = fmax(ND_lw(u) + ND_rw(u), ND_ht(u) + GD_ranksep(agraphof(u))); // far away
130 x2 = x * r + ND_coord(u).x;
131 y2 = y * r + ND_coord(u).y;
132 { /* now move (x1,y1) to the node boundary */
133 pointf curve[4]; /* Bézier control points for a straight line */
134 curve[0].x = x1;
135 curve[0].y = y1;
136 curve[1].x = (2 * x1 + x2) / 3;
137 curve[1].y = (2 * y1 + y2) / 3;
138 curve[2].x = (2 * x2 + x1) / 3;
139 curve[2].y = (2 * y2 + y1) / 3;
140 curve[3].x = x2;
141 curve[3].y = y2;
142
143 shape_clip(u, curve);
144 x1 = curve[0].x - ND_coord(u).x;
145 y1 = curve[0].y - ND_coord(u).y;
146 }
147
148 /* compute PORT on the boundary */
149 port prt = {.p = {.x = round(x1), .y = round(y1)}};
150 prt.bp = 0;
151 prt.order =
152 (MC_SCALE * (ND_lw(u) + prt.p.x)) / (ND_lw(u) + ND_rw(u));
153 prt.constrained = false;
154 prt.defined = true;
155 prt.clip = false;
156 prt.dyna = false;
157 prt.theta = 0;
158 prt.side = 0;
159 prt.name = NULL;
160
161 /* assign one of the ports to every edge */
162 for (size_t i = 0; i < LIST_SIZE(&l); i++) {
163 edge_t *e = LIST_GET(&l, i);
164 for (; e; e = ED_to_virt(e)) { /* assign to all virt edges of e */
165 for (f = e; f;
166 f = ED_edge_type(f) == VIRTUAL &&
167 ND_node_type(aghead(f)) == VIRTUAL &&
168 ND_out(aghead(f)).size == 1 ?
169 ND_out(aghead(f)).list[0] : NULL) {
170 if (aghead(f) == u)
171 ED_head_port(f) = prt;
172 if (agtail(f) == u)
173 ED_tail_port(f) = prt;
174 }
175 for (f = e; f;
176 f = ED_edge_type(f) == VIRTUAL &&
177 ND_node_type(agtail(f)) == VIRTUAL &&
178 ND_in(agtail(f)).size == 1 ?
179 ND_in(agtail(f)).list[0] : NULL) {
180 if (aghead(f) == u)
181 ED_head_port(f) = prt;
182 if (agtail(f) == u)
183 ED_tail_port(f) = prt;
184 }
185 }
186 }
187
188 ND_has_port(u) = true; /* kinda pointless, because mincross is already done */
189}
#define MC_SCALE
Definition const.h:99
#define VIRTUAL
Definition const.h:25
void dot_sameports(Agraph_t *)
Agsym_t * E_sametail
Definition globals.h:87
Agsym_t * E_samehead
Definition globals.h:87
node NULL
Definition grammar.y:181
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:336
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:460
#define agtail(e)
Definition cgraph.h:977
#define ED_edge_type(e)
Definition types.h:582
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
#define ED_head_port(e)
Definition types.h:588
#define ED_tail_port(e)
Definition types.h:597
#define ED_to_virt(e)
Definition types.h:599
#define GD_ranksep(g)
Definition types.h:397
#define ND_ht(n)
Definition types.h:500
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
#define ND_has_port(n)
Definition types.h:495
#define ND_rw(n)
Definition types.h:525
#define ND_node_type(n)
Definition types.h:511
#define ND_lw(n)
Definition types.h:506
#define ND_coord(n)
Definition types.h:490
#define ND_in(n)
Definition types.h:501
#define ND_out(n)
Definition types.h:515
Agraph_t * agraphof(void *obj)
Definition obj.c:187
@ AGEDGE
Definition cgraph.h:207
static uint64_t id
Definition gv2gml.c:42
type-generic dynamically expanding list
#define LIST_AT(list, index)
Definition list.h:168
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_CLEAR(list)
Definition list.h:240
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_GET(list, index)
Definition list.h:155
void shape_clip(node_t *n, pointf curve[4])
Definition splines.c:195
static void free_same(same_t s)
Definition sameport.c:32
static void sameport(node_t *u, edge_list_t l)
Definition sameport.c:93
same_t
Definition sameport.c:30
static void sameedge(same_list_t *same, edge_t *e, char *id)
register e in the same structure of the originating node under id
Definition sameport.c:81
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
graph or subgraph
Definition cgraph.h:424
double x
Definition geom.h:29
double y
Definition geom.h:29
Definition types.h:48
boxf * bp
Definition types.h:51
pointf p
Definition types.h:49
bool dyna
Definition types.h:57
unsigned char side
Definition types.h:59
bool clip
Definition types.h:56
double theta
Definition types.h:50
char * name
Definition types.h:63
unsigned char order
Definition types.h:58
bool constrained
Definition types.h:55
bool defined
Definition types.h:54
Definition grammar.c:90