7
ERnode_t *er_nd(Agnode_t *n) {return (ERnode_t*)(AGDATA(n));}
8
ERedge_t *er_ed(Agedge_t *e) {return (ERedge_t*)(AGDATA(e));}
9
Agraph_t *ergraph(ERview_t *D) {return BASE(D)->model.main;}
12
Set_t *ERmake_set(ERview_t *D)
15
rv = agalloc(ergraph(D),sizeof(Set_t));
17
rv->list = agalloc(ergraph(D),rv->extent * sizeof(void*));
21
void ERfree_set(ERview_t *D, Set_t *set)
23
if (set) {agfree(ergraph(D),set->list); agfree(ergraph(D),set);}
26
void ERset_append(ERview_t *D, Set_t *set, void *obj)
28
assert(set->extent > 0);
29
if (set->size >= set->extent - 1) {
30
set->list = agrealloc(ergraph(D),set->list,
31
set->extent*sizeof(void*),set->extent * 2 * sizeof(void*));
32
set->extent = set->extent * 2;
34
set->list[set->size++] = obj;
37
void ERset_delete(Set_t *set, void *obj)
42
for (i = 0; (obj0 = set->list[i]); i++) {
44
if (i < set->size - 1)
45
set->list[i] = set->list[set->size - 1];
47
set->list[set->size] = NIL(void*);
55
Tileset_t *ERmake_tileset(ERview_t *D)
56
{ return (Tileset_t*) ERmake_set(D); }
57
void ERfree_tileset(ERview_t *D, Tileset_t *set)
58
{ ERfree_set(D,(Set_t*)set);}
59
void ERtileset_append(ERview_t *D, Tileset_t *set, Tile_t *b)
60
{ ERset_append(D,(Set_t*)set,b); }
61
void ERtileset_delete(Tileset_t *set, Tile_t *b)
62
{ ERset_delete((Set_t*)set,b); }
65
Seglist_t *ERmake_seglist(ERview_t *D)
66
{return (Seglist_t*) ERmake_set(D); }
67
void ERfree_seglist(ERview_t *D, Seglist_t *set) {ERfree_set(D,(Set_t*)set);}
68
void ERseglist_append(ERview_t *D, Seglist_t *set, Seg_t *s)
69
{ ERset_append(D,(Set_t*)set,s); }
70
void ERseglist_delete(Seglist_t *set, Seg_t *seg)
71
{ ERset_delete((Set_t*)set,seg); }
74
Pt_t ERmkpoint(double x, double y) {Pt_t rv; rv.c[0] = x; rv.c[1] = y; return rv;}
75
Pt_t ERaddpoint(Pt_t p0, Pt_t p1) {return ERmkpoint( x(p0) + x(p1), y(p0) + y(p1)); }
76
Pt_t ERavgpt(Pt_t p0, Pt_t p1) {return ERmkpoint((x(p0)+x(p1))/2.,(y(p0)+y(p1))/2.);}
78
Pt_t ERcombine(Pt_t p, Pt_t q, ilbool px)
81
if (px) {x = x(p); y = y(q);}
82
else {x = x(q); y = y(p);}
83
return ERmkpoint(x,y);
87
/* points of compass & orientation */
90
char *name_of_dir(Dir_t arg)
92
static char *n[] = {"west","north","east","south","nosuchdir"};
97
/* returns true if horizontal, false if vertical */
98
ilbool ERhorizontal(Seg_t *seg)
100
if (y(seg->p[0]) == y(seg->p[1])) return TRUE;
101
assert(x(seg->p[0]) == x(seg->p[1]));
106
/* construct a tile from two points.
107
* seglists are initially empty.
108
* the tile is not entered into the global configuration.
110
Tile_t *ERmake_tile(ERview_t *D, Pt_t p0, Pt_t p1)
115
static int next_id = 0;
117
assert (x(p0) != x(p1));
118
assert (y(p0) != y(p1));
120
rv = agalloc(ergraph(D),sizeof(Tile_t));
121
for (d = 0; d < 2; d++) {
122
rv->LL.c[d] = MIN(p0.c[d],p1.c[d]);
123
rv->UR.c[d] = MAX(p0.c[d],p1.c[d]);
125
for (i = 0; i < NSIDES; i++) {
126
segs = rv->segs[i] = ERmake_seglist(D);
132
void ERfree_tile(ERview_t *D, Tile_t *b) {
134
for (side = 0; side < NSIDES; side++) ERfree_seglist(D,b->segs[side]);
135
agfree(ergraph(D),b);
138
Pt_t ERtile_LL(Tile_t *b) {return b->LL;}
139
Pt_t ERtile_LR(Tile_t *b) {return ERmkpoint(x(b->UR),y(b->LL));}
140
Pt_t ERtile_UR(Tile_t *b) {return b->UR;}
141
Pt_t ERtile_UL(Tile_t *b) {return ERmkpoint(x(b->LL),y(b->UR));}
143
void ERcorners(Tile_t *b, Pt_t *p)
151
/* note, must return points in ascending order. */
152
void ERget_tile_side(Tile_t *b, Dir_t side, Pt_t *p)
155
case north: p[0] = ERtile_UL(b); p[1] = ERtile_UR(b); break;
156
case east: p[0] = ERtile_LR(b); p[1] = ERtile_UR(b); break;
157
case south: p[0] = ERtile_LL(b); p[1] = ERtile_LR(b); break;
158
case west: p[0] = ERtile_LL(b); p[1] = ERtile_UL(b); break;
163
Dir_t ERtile_side_of(Tile_t *b, Pt_t p, Pt_t q)
165
Dir_t side = nosuchdir;
168
if (NONDECREASING(y(b->LL),y(p),y(b->UR))
169
&& NONDECREASING(y(b->LL),y(q),y(b->UR))) {
170
if (x(p) == x(b->LL)) side = west;
171
else if (x(p) == x(b->UR)) side = east;
175
assert (y(p) == y(q));
176
if (NONDECREASING(x(b->LL),x(p),x(b->UR))
177
&& NONDECREASING(x(b->LL),x(q),x(b->UR))) {
178
if (y(p) == y(b->LL)) side = south;
179
else if (y(p) == y(b->UR)) side = north;
185
static ilbool on_side(Tile_t *b, Pt_t p, Pt_t q)
187
return (ERtile_side_of(b,p,q) != nosuchdir);
190
static ilbool pt_in_tile(Pt_t p, Tile_t *b) {
191
return (NONDECREASING(x(b->LL),x(p),x(b->UR)) &&
192
NONDECREASING(y(b->LL),y(p),y(b->UR)));
195
ilbool ERpt_strictly_in_tile(Pt_t p, Tile_t *b) {
196
return (INCREASING(x(b->LL),x(p),x(b->UR)) &&
197
INCREASING(y(b->LL),y(p),y(b->UR)));
200
ilbool ERtiles_nontrivially_intersect(Tile_t *b0, Tile_t *b1) {
201
if ((x(b0->UR) <= x(b1->LL)) /* b0 is left */
202
|| (x(b0->LL) >= x(b1->UR)) /* b0 is right */
203
|| (y(b0->UR) <= y(b1->LL)) /* b0 is below */
204
|| (y(b0->LL) >= y(b1->UR))) /* b0 is above */
209
ilbool ERtile_covers_tile(Tile_t *outer, Tile_t *inner)
211
if ((x(outer->LL) > x(inner->LL))
212
|| (x(outer->UR) < x(inner->UR))
213
|| (y(outer->LL) > x(inner->LL))
214
|| (y(outer->UR) < x(inner->UR))) return FALSE;
220
Seg_t *ERmkseg(ERview_t *D, Pt_t p, Pt_t q, Tile_t *b0, Tile_t *b1, Segkind_t kind) {
224
if ( (x(p) == x(q)) + (y(p) == y(q)) != 1) abort();
225
if NOT(on_side(b0,p,q)) abort();
226
if NOT(on_side(b1,p,q)) abort();
228
if ( ((y(p) == y(q)) && (x(p) > x(q))) ||
229
((x(p) == x(q)) && (y(p) > y(q))))
230
{ t = p; p = q; q = t; } /* pts always in ascending order */
231
rv = agalloc(ergraph(D),sizeof(Seg_t));
232
rv->p[0] = p; rv->p[1] = q;
233
rv->b[0] = b0; rv->b[1] = b1;
238
void ERfree_seg(ERview_t *D, Seg_t *s) {agfree(ergraph(D),s);}
240
void ERinstall_new_seg(ERview_t *D, Pt_t p, Pt_t q, Segkind_t kind, Tile_t *b0, Dir_t side, Tile_t *b1)
243
newseg = ERmkseg(D,p,q,b0,b1,kind);
244
ERseglist_append(D,b0->segs[side],newseg);
245
ERseglist_append(D,b1->segs[opposite(side)],newseg);
249
static Dir_t ERside_toward(Tile_t *b, Pt_t p)
253
if (y(p) > y(b->UR)) side = north;
254
else if (y(p) < y(b->LL)) side = south;
255
else if (x(p) > x(b->UR)) side = east;
256
else if (x(p) < x(b->LL)) side = west;
257
else side = nosuchdir;
261
static int varying(Dir_t side) /* depends on internal values of Dir_t enum */
263
return (side + 1) % 2;
266
/* walk one step from b toward p */
267
Tile_t *ERneighbor(Tile_t *b, Pt_t p)
274
side = ERside_toward(b,p);
275
if (side == nosuchdir) rv = b;
278
for (i = 0; (seg = b->segs[side]->list[i]); i++)
279
if (NONDECREASING(seg->p[0].c[c],p.c[c],seg->p[1].c[c])) break;
280
if (b != seg->b[0]) rv = seg->b[0]; else rv = seg->b[1];
285
static Seg_t *find_seg(Tile_t *b, Pt_t p)
293
for (side = 0; side < NSIDES; side++) {
294
ERget_tile_side(b,side,cp);
295
d1 = side % 2; d0 = !d1;
296
if (p.c[d1] == cp[0].c[d1]) {
297
if (NONDECREASING(cp[0].c[d0],p.c[d0],cp[1].c[d0])) {
298
seglist = b->segs[side];
299
for (i = 0; (seg = seglist->list[i]); i++) {
300
if (NONDECREASING(seg->p[0].c[d0],p.c[d0],seg->p[1].c[d0]))
311
/* locate the tile of a given point */
312
Tile_t *ERlocate(ERview_t *D, Pt_t p)
317
for (i = 0; (b = D->config->list[i]); i++)
318
if (pt_in_tile(p,b)) break;
322
void ERlocate_endpoint(ERview_t *D, Tile_t *user_node, Pt_t pt,
323
Tile_t **pb, Seg_t **pseg)
329
seg = find_seg(b,pt);
331
if (NOT(ERtiles_nontrivially_intersect(user_node,b)))
332
b = (b != seg->b[0]? seg->b[0] : seg->b[1]);
334
else b = NIL(Tile_t*);
339
static Pt_t snap_to(Pt_t p, Tile_t *b)
343
for (c = 0; c < 2; c++) {
344
if (p.c[c] < b->LL.c[c]) p.c[c] = b->LL.c[c];
345
else if (p.c[c] > b->UR.c[c]) p.c[c] = b->UR.c[c];
350
/* split the configuration by a given line segment */
352
void ERmark_segs(ERview_t *D, Pt_t p, Pt_t q, Segkind_t kind)
360
if (y(p) == y(q)) {c = 0; d = 1;}
362
if (p.c[c] > q.c[c]) {Pt_t t; t = p; p = q; q = t;}
366
assert(p0.c[d] == p.c[d]);
367
assert(p0.c[d] == q.c[d]);
368
if (NOT(pt_eq(p,p0))) {
369
side = ERtile_side_of(b,p,p0);
370
for (i = 0; (seg = b->segs[side]->list[i]); i++) {
371
if ((seg->p[0].c[c] < q.c[c]) &&
372
(seg->p[1].c[c] > p.c[c])) {
380
} while (b != last_b);
383
void ERmark_container_segs(ERview_t *d, Tile_t *b, Segkind_t kind)
390
for (i = 0; (nb = d->nodes->list[i]); i++) {
391
if (ERtile_covers_tile(nb,b)) {
393
for (side = 0; side < NSIDES; side++) {
394
ERmark_segs(d,corner[side],corner[(side+1)%4],kind);
400
Dir_t ERtiles_share_side(Tile_t *b, Tile_t *cb, Pt_t *res)
404
Pt_t bseg[2],cbseg[2];
406
for (side = 0; side < NSIDES; side++) {
409
opp = opposite(side);
410
ERget_tile_side(b,side,bseg);
411
ERget_tile_side(cb,opp,cbseg);
412
if (bseg[0].c[d0] != cbseg[0].c[d0]) continue;
413
if (bseg[1].c[d1] <= cbseg[0].c[d1]) continue;
414
if (bseg[0].c[d1] >= cbseg[1].c[d1]) continue;
415
if (bseg[0].c[d1] < cbseg[0].c[d1]) res[0] = cbseg[0];
416
else res[0] = bseg[0];
417
if (bseg[1].c[d1] > cbseg[1].c[d1]) res[1] = cbseg[1];
418
else res[1] = bseg[1];
419
if NOT(on_side(b,res[0],res[1])) abort();
420
if NOT(on_side(cb,res[0],res[1])) abort();