Graphviz 13.0.0~dev.20241220.2304
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 <cgraph/list.h>
17#include <math.h>
18#include <dotgen/dot.h>
19#include <stdbool.h>
20#include <stddef.h>
21#include <util/streq.h>
22
23DEFINE_LIST(edge_list, edge_t*)
24
25typedef struct same_t {
26 char *id; /* group id */
27 edge_list_t l; // edges in the group
29
30static void free_same(same_t s) {
31 edge_list_free(&s.l);
32}
33
35
36static void sameedge(same_list_t *same, edge_t *e, char *id);
37static void sameport(node_t *u, edge_list_t l);
38
40/* merge edge ports in G */
41{
42 node_t *n;
43 edge_t *e;
44 char *id;
45 same_list_t samehead = {0};
46 same_list_t sametail = {0};
47
48 E_samehead = agattr(g, AGEDGE, "samehead", NULL);
49 E_sametail = agattr(g, AGEDGE, "sametail", NULL);
50 if (!(E_samehead || E_sametail))
51 return;
52 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
53 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
54 if (aghead(e) == agtail(e)) continue; /* Don't support same* for loops */
55 if (aghead(e) == n && E_samehead &&
56 (id = agxget(e, E_samehead))[0])
57 sameedge(&samehead, e, id);
58 else if (agtail(e) == n && E_sametail &&
59 (id = agxget(e, E_sametail))[0])
60 sameedge(&sametail, e, id);
61 }
62 for (size_t i = 0; i < same_list_size(&samehead); i++) {
63 if (edge_list_size(&same_list_at(&samehead, i)->l) > 1)
64 sameport(n, same_list_get(&samehead, i).l);
65 }
66 same_list_clear(&samehead);
67 for (size_t i = 0; i < same_list_size(&sametail); i++) {
68 if (edge_list_size(&same_list_at(&sametail, i)->l) > 1)
69 sameport(n, same_list_get(&sametail, i).l);
70 }
71 same_list_clear(&sametail);
72 }
73
74 same_list_free(&samehead);
75 same_list_free(&sametail);
76}
77
79static void sameedge(same_list_t *same, edge_t *e, char *id) {
80 for (size_t i = 0; i < same_list_size(same); i++)
81 if (streq(same_list_get(same, i).id, id)) {
82 edge_list_append(&same_list_at(same, i)->l, e);
83 return;
84 }
85
86 same_t to_append = {.id = id};
87 edge_list_append(&to_append.l, e);
88 same_list_append(same, to_append);
89}
90
91static void sameport(node_t *u, edge_list_t l)
92/* make all edges in L share the same port on U. The port is placed on the
93 node boundary and the average angle between the edges. FIXME: this assumes
94 naively that the edges are straight lines, which is wrong if they are long.
95 In that case something like concentration could be done.
96
97 An arr_port is also computed that's ARR_LEN away from the node boundary.
98 It's used for edges that don't themselves have an arrow.
99*/
100{
101 node_t *v;
102 edge_t *f;
103 double x = 0, y = 0, x1, y1, x2, y2, r;
104
105 /* Compute the direction vector (x,y) of the average direction. We compute
106 with direction vectors instead of angles because else we have to first
107 bring the angles within PI of each other. av(a,b)!=av(a,b+2*PI) */
108 for (size_t i = 0; i < edge_list_size(&l); i++) {
109 edge_t *e = edge_list_get(&l, i);
110 if (aghead(e) == u)
111 v = agtail(e);
112 else
113 v = aghead(e);
114 x1 = ND_coord(v).x - ND_coord(u).x;
115 y1 = ND_coord(v).y - ND_coord(u).y;
116 r = hypot(x1, y1);
117 x += x1 / r;
118 y += y1 / r;
119 }
120 r = hypot(x, y);
121 x /= r;
122 y /= r;
123
124 /* (x1,y1),(x2,y2) is a segment that must cross the node boundary */
125 x1 = ND_coord(u).x;
126 y1 = ND_coord(u).y; /* center of node */
127 r = fmax(ND_lw(u) + ND_rw(u), ND_ht(u) + GD_ranksep(agraphof(u))); // far away
128 x2 = x * r + ND_coord(u).x;
129 y2 = y * r + ND_coord(u).y;
130 { /* now move (x1,y1) to the node boundary */
131 pointf curve[4]; /* bezier control points for a straight line */
132 curve[0].x = x1;
133 curve[0].y = y1;
134 curve[1].x = (2 * x1 + x2) / 3;
135 curve[1].y = (2 * y1 + y2) / 3;
136 curve[2].x = (2 * x2 + x1) / 3;
137 curve[2].y = (2 * y2 + y1) / 3;
138 curve[3].x = x2;
139 curve[3].y = y2;
140
141 shape_clip(u, curve);
142 x1 = curve[0].x - ND_coord(u).x;
143 y1 = curve[0].y - ND_coord(u).y;
144 }
145
146 /* compute PORT on the boundary */
147 port prt = {.p = {.x = round(x1), .y = round(y1)}};
148 prt.bp = 0;
149 prt.order =
150 (MC_SCALE * (ND_lw(u) + prt.p.x)) / (ND_lw(u) + ND_rw(u));
151 prt.constrained = false;
152 prt.defined = true;
153 prt.clip = false;
154 prt.dyna = false;
155 prt.theta = 0;
156 prt.side = 0;
157 prt.name = NULL;
158
159 /* assign one of the ports to every edge */
160 for (size_t i = 0; i < edge_list_size(&l); i++) {
161 edge_t *e = edge_list_get(&l, i);
162 for (; e; e = ED_to_virt(e)) { /* assign to all virt edges of e */
163 for (f = e; f;
164 f = ED_edge_type(f) == VIRTUAL &&
165 ND_node_type(aghead(f)) == VIRTUAL &&
166 ND_out(aghead(f)).size == 1 ?
167 ND_out(aghead(f)).list[0] : NULL) {
168 if (aghead(f) == u)
169 ED_head_port(f) = prt;
170 if (agtail(f) == u)
171 ED_tail_port(f) = prt;
172 }
173 for (f = e; f;
174 f = ED_edge_type(f) == VIRTUAL &&
175 ND_node_type(agtail(f)) == VIRTUAL &&
176 ND_in(agtail(f)).size == 1 ?
177 ND_in(agtail(f)).list[0] : NULL) {
178 if (aghead(f) == u)
179 ED_head_port(f) = prt;
180 if (agtail(f) == u)
181 ED_tail_port(f) = prt;
182 }
183 }
184 }
185
186 ND_has_port(u) = true; /* kinda pointless, because mincross is already done */
187}
#define MC_SCALE
Definition const.h:99
#define VIRTUAL
Definition const.h:25
Agsym_t * E_sametail
Definition globals.h:86
Agsym_t * E_samehead
Definition globals.h:86
node NULL
Definition grammar.y:163
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:338
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:455
#define agtail(e)
Definition cgraph.h:880
#define ED_edge_type(e)
Definition types.h:582
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:85
#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:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#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:185
@ AGEDGE
Definition cgraph.h:207
static uint64_t id
Definition gv2gml.c:42
#define DEFINE_LIST_WITH_DTOR(name, type, dtor)
Definition list.h:34
#define DEFINE_LIST(name, type)
Definition list.h:26
void shape_clip(node_t *n, pointf curve[4])
Definition splines.c:194
static void free_same(same_t s)
Definition sameport.c:30
static void sameport(node_t *u, edge_list_t l)
Definition sameport.c:91
void dot_sameports(graph_t *g)
Definition sameport.c:39
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:79
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
graph or subgraph
Definition cgraph.h:425
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
char * id
Definition sameport.c:26
edge_list_t l
Definition sameport.c:27
Definition grammar.c:93