Graphviz 14.1.2~dev.20260119.0928
Loading...
Searching...
No Matches
hedges.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#include "config.h"
12
13#include <assert.h>
14#include <neatogen/hedges.h>
15#include <common/render.h>
16#include <stdbool.h>
17#include <stdlib.h>
18#include <util/alloc.h>
19#include <util/arena.h>
20
21#define DELETED -2
22
25 free(st->hash);
26}
27
29 assert(st != NULL);
30
31 *st = (el_state_t){0};
32
33 st->hashsize = 2 * sqrt_nsites;
34 st->hash = gv_calloc(st->hashsize, sizeof(Halfedge *));
35 st->leftend = HEcreate(st, NULL, 0);
36 st->rightend = HEcreate(st, NULL, 0);
37 st->leftend->ELleft = NULL;
38 st->leftend->ELright = st->rightend;
39 st->rightend->ELleft = st->leftend;
40 st->rightend->ELright = NULL;
41 st->hash[0] = st->leftend;
42 st->hash[st->hashsize - 1] = st->rightend;
43}
44
45Site *hintersect(Halfedge *el1, Halfedge *el2, arena_t *allocator) {
46 assert(allocator != NULL);
47 Edge *e1, *e2, *e;
48 Halfedge *el;
49 double d, xint, yint;
50 bool right_of_site;
51
52 e1 = el1->ELedge;
53 e2 = el2->ELedge;
54 if (e1 == NULL || e2 == NULL)
55 return NULL;
56 if (e1->reg[1] == e2->reg[1])
57 return NULL;
58
59 d = e1->a * e2->b - e1->b * e2->a;
60 if (-1.0e-10 < d && d < 1.0e-10)
61 return NULL;
62
63 xint = (e1->c * e2->b - e2->c * e1->b) / d;
64 yint = (e2->c * e1->a - e1->c * e2->a) / d;
65
66 if (e1->reg[1]->coord.y < e2->reg[1]->coord.y ||
67 (e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
68 e1->reg[1]->coord.x < e2->reg[1]->coord.x)) {
69 el = el1;
70 e = e1;
71 } else {
72 el = el2;
73 e = e2;
74 }
75 right_of_site = xint >= e->reg[1]->coord.x;
76 if ((right_of_site && el->ELpm == le) || (!right_of_site && el->ELpm == re))
77 return NULL;
78
79 Site *const v = ARENA_NEW(allocator, Site);
80 v->coord.x = xint;
81 v->coord.y = yint;
82 return v;
83}
84
85/* returns 1 if p is to right of halfedge e */
86static int right_of(Halfedge *el, Point *p) {
87 Edge *e;
88 Site *topsite;
89 int above, fast;
90 double dxp, dyp, dxs, t1, t2, t3, yl;
91
92 e = el->ELedge;
93 topsite = e->reg[1];
94 bool right_of_site = p->x > topsite->coord.x;
95 if (right_of_site && el->ELpm == le)
96 return 1;
97 if (!right_of_site && el->ELpm == re)
98 return 0;
99
100 if (e->a == 1.0) {
101 dyp = p->y - topsite->coord.y;
102 dxp = p->x - topsite->coord.x;
103 fast = 0;
104 if ((!right_of_site && e->b < 0.0) || (right_of_site && e->b >= 0.0)) {
105 above = dyp >= e->b * dxp;
106 fast = above;
107 } else {
108 above = p->x + p->y * e->b > e->c;
109 if (e->b < 0.0)
110 above = !above;
111 if (!above)
112 fast = 1;
113 }
114 if (!fast) {
115 dxs = topsite->coord.x - (e->reg[0])->coord.x;
116 above = e->b * (dxp * dxp - dyp * dyp) <
117 dxs * dyp * (1.0 + 2.0 * dxp / dxs + e->b * e->b);
118 if (e->b < 0.0)
119 above = !above;
120 }
121 } else { /*e->b==1.0 */
122 yl = e->c - e->a * p->x;
123 t1 = p->y - yl;
124 t2 = p->x - topsite->coord.x;
125 t3 = yl - topsite->coord.y;
126 above = t1 * t1 > t2 * t2 + t3 * t3;
127 }
128 return el->ELpm == le ? above : !above;
129}
130
131Halfedge *HEcreate(el_state_t *st, Edge *e, char pm) {
132 Halfedge *answer = ARENA_NEW(&st->allocated, Halfedge);
133 answer->ELedge = e;
134 answer->ELpm = pm;
135 answer->PQnext = NULL;
136 answer->vertex = NULL;
137 return answer;
138}
139
140
141void ELinsert(Halfedge * lb, Halfedge * new)
142{
143 new->ELleft = lb;
144 new->ELright = lb->ELright;
145 lb->ELright->ELleft = new;
146 lb->ELright = new;
147}
148
149/* Get entry from hash table, pruning any deleted nodes */
150static Halfedge *ELgethash(el_state_t *st, int b) {
151 assert(st != NULL);
152 Halfedge *he;
153
154 if (b < 0 || b >= st->hashsize)
155 return NULL;
156 he = st->hash[b];
157 if (he == NULL || he->ELedge != (Edge *) DELETED)
158 return he;
159
160/* Hash table points to deleted half edge. Patch as necessary. */
161 st->hash[b] = NULL;
162 return NULL;
163}
164
171static int clamp(int lower, double v, int upper) {
172 assert(upper >= lower);
173 if (v < lower) {
174 return lower;
175 }
176 if (v > upper) {
177 return upper;
178 }
179 return (int)v;
180}
181
183 assert(st != NULL);
184 int i;
185 Halfedge *he;
186
187/* Use hash table to get close to desired halfedge */
188 const int bucket =
189 clamp(0, (p->x - xmin) / deltax * st->hashsize, st->hashsize - 1);
190 he = ELgethash(st, bucket);
191 if (he == NULL) {
192 for (i = 1; ; ++i) {
193 if ((he = ELgethash(st, bucket - i)) != NULL)
194 break;
195 if ((he = ELgethash(st, bucket + i)) != NULL)
196 break;
197 }
198 }
199/* Now search linear list of halfedges for the corect one */
200 if (he == st->leftend || (he != st->rightend && right_of(he, p))) {
201 do {
202 he = he->ELright;
203 } while (he != st->rightend && right_of(he, p));
204 he = he->ELleft;
205 } else
206 do {
207 he = he->ELleft;
208 } while (he != st->leftend && !right_of(he, p));
209
210/* Update hash table */
211 if (bucket > 0 && bucket < st->hashsize - 1) {
212 st->hash[bucket] = he;
213 }
214 return he;
215}
216
217
218/* This delete routine can't reclaim node, since pointers from hash
219 table may be present. */
221{
222 he->ELleft->ELright = he->ELright;
223 he->ELright->ELleft = he->ELleft;
224 he->ELedge = (Edge *) DELETED;
225}
226
227
229{
230 return he->ELright;
231}
232
234{
235 return he->ELleft;
236}
237
238
240{
241 if (he->ELedge == NULL)
242 return bottomsite;
243 return he->ELpm == le ? he->ELedge->reg[le] : he->ELedge->reg[re];
244}
245
247{
248 if (he->ELedge == NULL)
249 return bottomsite;
250 return he->ELpm == le ? he->ELedge->reg[re] : he->ELedge->reg[le];
251}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
void gv_arena_reset(arena_t *arena)
Definition arena.c:166
Region-based memory allocator.
#define ARENA_NEW(arena, type)
Definition arena.h:55
#define le
Definition edges.h:29
#define re
Definition edges.h:30
double deltax
Definition geometry.c:18
double xmin
Definition geometry.c:17
int sqrt_nsites
Definition geometry.c:21
void free(void *)
node NULL
Definition grammar.y:181
static Halfedge * ELgethash(el_state_t *st, int b)
Definition hedges.c:150
Site * hintersect(Halfedge *el1, Halfedge *el2, arena_t *allocator)
Definition hedges.c:45
Halfedge * ELright(Halfedge *he)
Definition hedges.c:228
void ELcleanup(el_state_t *st)
Definition hedges.c:23
void ELinitialize(el_state_t *st)
Definition hedges.c:28
void ELinsert(Halfedge *lb, Halfedge *new)
Definition hedges.c:141
static int right_of(Halfedge *el, Point *p)
Definition hedges.c:86
Site * rightreg(Halfedge *he)
Definition hedges.c:246
Halfedge * ELleft(Halfedge *he)
Definition hedges.c:233
static int clamp(int lower, double v, int upper)
Definition hedges.c:171
Halfedge * ELleftbnd(el_state_t *st, Point *p)
Definition hedges.c:182
#define DELETED
Definition hedges.c:21
void ELdelete(Halfedge *he)
Definition hedges.c:220
Halfedge * HEcreate(el_state_t *st, Edge *e, char pm)
Definition hedges.c:131
Site * leftreg(Halfedge *he)
Definition hedges.c:239
pointf coord(node_t *n)
Definition utils.c:156
Site * bottomsite
Definition site.c:16
Definition edges.h:23
double b
Definition edges.h:24
double c
Definition edges.h:24
Site * reg[2]
Definition edges.h:26
double a
Definition edges.h:24
Edge * ELedge
Definition hedges.h:25
struct Halfedge * PQnext
Definition hedges.h:29
char ELpm
Definition hedges.h:26
Site * vertex
Definition hedges.h:27
struct Halfedge * ELleft
Definition hedges.h:24
struct Halfedge * ELright
Definition hedges.h:24
double x
Definition geometry.h:24
double y
Definition geometry.h:24
Definition site.h:23
Point coord
Definition site.h:24
int hashsize
Definition hedges.h:34
Halfedge * leftend
Definition hedges.h:36
Halfedge ** hash
Definition hedges.h:35
arena_t allocated
outstanding dynamic allocations
Definition hedges.h:33
Halfedge * rightend
Definition hedges.h:37
double x
Definition geom.h:29