1
/* $Id: mtspace.c,v 1.11 2005/01/03 12:57:00 danmc Exp $ */
6
* PCB, interactive printed circuit board design
7
* Copyright (C) 1994,1995,1996 Thomas Nau
8
* Copyright (C) 1998,1999,2000,2001 harry eaton
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
* Contact addresses for paper mail and Email:
25
* harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
26
* haceaton@aplcomm.jhuapl.edu
30
/* this file, mtspace.c, was written and is
31
* Copyright (c) 2001 C. Scott Ananian.
34
/* implementation for "empty space" routines (needed for via-space tracking
52
#ifdef HAVE_LIBDMALLOC
56
RCSID("$Id: mtspace.c,v 1.11 2005/01/03 12:57:00 danmc Exp $");
59
/* define this for more thorough self-checking of data structures */
60
#define SLOW_ASSERTIONS
62
/* mtspace data structures are built on r-trees. */
64
/* ---------------------------------------------------------------------------
67
typedef struct mtspacebox
73
BDimension keepaway; /* the smallest keepaway around this box */
77
/* this is an mtspace_t */
80
/* r-tree keeping track of "empty" regions. */
88
__mtspace_box_is_good (mtspacebox_t * mtsb)
91
__box_is_good (&mtsb->box) &&
92
mtsb->fixed_count >= 0 && mtsb->even_count >= 0 && mtsb->odd_count >= 0 &&
93
mtsb->keepaway > 0 && 1;
98
__mtspace_is_good (mtspace_t * mtspace)
100
int r = mtspace && mtspace->rtree && __box_is_good (&mtspace->bounds) &&
101
/* XXX: check that no boxed in mtspace tree overlap */
109
mtspace_create_box (const BoxType * box, int fixed, int even, int odd)
112
assert (__box_is_good (box));
113
mtsb = calloc (1, sizeof (*mtsb));
114
*((BoxTypePtr) & mtsb->box) = *box;
115
mtsb->fixed_count = fixed;
116
mtsb->even_count = even;
117
mtsb->odd_count = odd;
118
mtsb->keepaway = MAX_COORD; /* impossibly large start */
119
assert (__mtspace_box_is_good (mtsb));
123
/* create an "empty space" representation */
125
mtspace_create (const BoxType * bounds, BDimension keepaway)
127
BoxType smaller_bounds;
131
assert (__box_is_good (bounds));
132
/* create initial "empty region" */
133
smaller_bounds = shrink_box (bounds, keepaway);
134
mtsb = mtspace_create_box (&smaller_bounds, 0, 0, 0);
135
mtsb->keepaway = keepaway;
136
/* create mtspace data structure */
137
mtspace = calloc (1, sizeof (*mtspace));
138
mtspace->rtree = r_create_tree ((const BoxType **) &mtsb, 1, 1);
139
mtspace->bounds = smaller_bounds;
141
assert (__mtspace_is_good (mtspace));
145
/* destroy an "empty space" representation. */
147
mtspace_destroy (mtspace_t ** mtspacep)
149
assert (mtspacep && __mtspace_is_good (*mtspacep));
150
r_destroy_tree (&(*mtspacep)->rtree);
155
struct coalesce_closure
158
vector_t *remove_vec;
159
/* these are for convenience */
166
boxtype (mtspacebox_t * mtsb)
168
assert (__mtspace_box_is_good (mtsb));
170
((mtsb->fixed_count > 0) ? 1 : 0) |
171
((mtsb->even_count > 0) ? 2 : 0) | ((mtsb->odd_count > 0) ? 4 : 0);
174
/* look at last element in add_vec to see if it can be coalesced with
175
* adjacent rectangles. If it can, add the adjacent rectangle to the
176
* remove_vec and replace the item in add_vec with the coalesced rect.
177
* then remove all in remove_vec and invoke again. otherwise, we
178
* add the rectangle in add_vec and invoke again, until add_vec is empty. */
180
check_one (const BoxType * box, void *cl)
182
struct coalesce_closure *cc = (struct coalesce_closure *) cl;
183
mtspacebox_t *adj = (mtspacebox_t *) box, *nb;
188
float new_area, area_a, area_b;
189
assert (__mtspace_box_is_good (cc->mtsb));
190
assert (__mtspace_box_is_good (adj));
191
/* nothing should intersect mtsb */
192
assert (!box_intersect (&adj->box, &cc->mtsb->box));
193
/* if the box types are different, we can't coalesce */
194
if (cc->mtsb->fixed_count != adj->fixed_count)
196
if (cc->mtsb->even_count != adj->even_count)
198
if (cc->mtsb->odd_count != adj->odd_count)
200
/* determine on which side (if any) adj is adjacent to cc->mtsb */
201
if (0) /* this is just to justify the lines below */ ;
202
else if (adj->box.X1 == cc->mtsb->box.X2)
204
else if (adj->box.X2 == cc->mtsb->box.X1)
206
else if (adj->box.Y1 == cc->mtsb->box.Y2)
208
else if (adj->box.Y2 == cc->mtsb->box.Y1)
211
return 0; /* not adjacent */
214
ROTATEBOX_TO_NORTH (a, d);
215
ROTATEBOX_TO_NORTH (b, d);
216
assert (a.Y2 == b.Y1);
217
x1 = MAX (a.X1, b.X1);
218
x2 = MIN (a.X2, b.X2);
219
assert (x1 <= x2); /* overlap */
220
/* area of new coalesced box is (b.Y2-a.Y1)*(x2-x1). this must be
221
* larger than area of either box a or box b for this to be a win */
222
new_area = (float) (b.Y2 - a.Y1) * (float) (x2 - x1);
223
area_a = (float) (a.Y2 - a.Y1) * (float) (a.X2 - a.X1);
224
area_b = (float) (b.Y2 - b.Y1) * (float) (b.X2 - b.X1);
225
if ((new_area <= area_a) || (new_area <= area_b))
227
/* okay! coalesce these boxes! */
228
/* add the adjacent rectangle to remove_vec... */
229
vector_append (cc->remove_vec, adj);
230
/* ...and add the split/coalesced rectangles to add_vec */
231
for (i = 0; i < 5; i++)
232
{ /* five possible rectangles (only 3 ever created) */
240
break; /* left top */
244
break; /* right top */
248
break; /* left bottom */
252
break; /* right bottom */
258
break; /* coalesced box */
262
ROTATEBOX_FROM_NORTH (c, d);
263
nb = mtspace_create_box
264
(&c, adj->fixed_count, adj->even_count, adj->odd_count);
265
nb->keepaway = MIN (adj->keepaway, cc->mtsb->keepaway);
266
vector_append (cc->add_vec, nb);
269
/* done coalescing! */
270
longjmp (cc->env, 1); /* don't continue searching */
271
return 1; /* never reached! */
274
mtspace_coalesce (mtspace_t * mtspace, struct coalesce_closure *cc)
278
/* first, remove anything in remove_vec */
279
while (!vector_is_empty (cc->remove_vec))
281
mtspacebox_t *mtsb = (mtspacebox_t *)
282
vector_remove_last (cc->remove_vec);
283
r_delete_entry (mtspace->rtree, &mtsb->box);
285
assert (vector_is_empty (cc->remove_vec));
286
assert (!vector_is_empty (cc->add_vec));
287
cc->mtsb = (mtspacebox_t *) vector_remove_last (cc->add_vec);
288
if (setjmp (cc->env) == 0)
290
/* search region is one larger than mtsb on all sides */
291
BoxType region = bloat_box (&cc->mtsb->box, 1);
293
r = r_search (mtspace->rtree, ®ion, NULL, check_one, cc);
294
assert (r == 0); /* otherwise we would have called 'longjmp' */
295
/* ----- didn't find anything to coalesce ----- */
297
r = r_region_is_empty (mtspace->rtree, &cc->mtsb->box);
300
r_insert_entry (mtspace->rtree, &cc->mtsb->box, 1);
304
/* ----- found something to coalesce and added it to add_vec ---- */
309
while (!vector_is_empty (cc->add_vec));
310
assert (vector_is_empty (cc->add_vec));
311
assert (vector_is_empty (cc->remove_vec));
312
assert (__mtspace_is_good (mtspace));
315
/* for every box which intersects mtsb->box, split off a chunk with
316
* altered counts. Add original to remove_vec and add replacements to
319
remove_one (const BoxType * box, void *cl)
321
struct coalesce_closure *cc = (struct coalesce_closure *) cl;
322
mtspacebox_t *ibox = (mtspacebox_t *) box, *nb;
325
assert (__mtspace_box_is_good (cc->mtsb));
326
assert (__mtspace_box_is_good (ibox));
327
/* some of the candidates won't intersect */
328
if (!box_intersect (&ibox->box, &cc->mtsb->box))
330
/* remove the intersecting box by adding it to remove_vec */
331
vector_append (cc->remove_vec, ibox);
332
/* there are nine possible split boxes to add */
334
for (i = 0; i < 3; i++)
336
for (j = 0; j < 3; j++)
344
b.X2 = MIN (b.X2, a.X1);
347
b.X1 = MAX (b.X1, a.X1);
348
b.X2 = MIN (b.X2, a.X2);
351
b.X1 = MAX (b.X1, a.X2);
359
b.Y2 = MIN (b.Y2, a.Y1);
362
b.Y1 = MAX (b.Y1, a.Y1);
363
b.Y2 = MIN (b.Y2, a.Y2);
366
b.Y1 = MAX (b.Y1, a.Y2);
369
if (b.X1 < b.X2 && b.Y1 < b.Y2)
371
nb = mtspace_create_box
372
(&b, ibox->fixed_count, ibox->even_count, ibox->odd_count);
373
nb->keepaway = MIN (nb->keepaway, cc->mtsb->keepaway);
374
if (i == 1 && j == 1)
375
{ /* this is the intersecting piece */
376
assert (box_intersect (&nb->box, &cc->mtsb->box));
379
nb->fixed_count += cc->mtsb->fixed_count;
380
nb->even_count += cc->mtsb->even_count;
381
nb->odd_count += cc->mtsb->odd_count;
385
nb->fixed_count -= cc->mtsb->fixed_count;
386
nb->even_count -= cc->mtsb->even_count;
387
nb->odd_count -= cc->mtsb->odd_count;
391
assert (!box_intersect (&nb->box, &cc->mtsb->box));
392
vector_append (cc->add_vec, nb);
399
mtspace_remove_chunk (mtspace_t * mtspace, struct coalesce_closure *cc)
401
return r_search (mtspace->rtree, &cc->mtsb->box, NULL, remove_one, cc);
404
/* add/remove a chunk from the empty-space representation */
406
mtspace_mutate (mtspace_t * mtspace,
407
const BoxType * box, mtspace_type_t which,
408
BDimension keepaway, Boolean is_add)
410
struct coalesce_closure cc;
412
assert (__mtspace_is_good (mtspace));
413
assert (__box_is_good (box));
414
assert (which == FIXED || which == ODD || which == EVEN);
415
/* create coalesce_closure */
416
cc.add_vec = vector_create ();
417
cc.remove_vec = vector_create ();
420
bloated = bloat_box (box, keepaway);
421
bloated = clip_box (&bloated, &mtspace->bounds);
422
assert (__box_is_good (&bloated));
423
cc.mtsb = mtspace_create_box
424
(&bloated, which == FIXED ? 1 : 0, which == EVEN ? 1 : 0,
425
which == ODD ? 1 : 0);
426
cc.mtsb->keepaway = keepaway;
427
assert (boxtype (cc.mtsb) != 0);
428
/* take a chunk out of anything which intersects our clipped bloated box */
429
mtspace_remove_chunk (mtspace, &cc);
431
/* coalesce adjacent chunks */
432
mtspace_coalesce (mtspace, &cc);
433
/* clean up coalesce_closure */
434
vector_destroy (&cc.add_vec);
435
vector_destroy (&cc.remove_vec);
440
/* add a space-filler to the empty space representation. */
442
mtspace_add (mtspace_t * mtspace, const BoxType * box, mtspace_type_t which,
445
mtspace_mutate (mtspace, box, which, keepaway, True);
448
/* remove a space-filler from the empty space representation. */
450
mtspace_remove (mtspace_t * mtspace,
451
const BoxType * box, mtspace_type_t which, BDimension keepaway)
453
mtspace_mutate (mtspace, box, which, keepaway, False);
458
const BoxType *region;
459
vector_t *free_space_vec;
460
vector_t *lo_conflict_space_vec;
461
vector_t *hi_conflict_space_vec;
462
BDimension radius, keepaway;
467
query_one (const BoxType * box, void *cl)
469
struct query_closure *qc = (struct query_closure *) cl;
470
mtspacebox_t *mtsb = (mtspacebox_t *) box;
471
BDimension shrink = 0;
473
assert (box_intersect (qc->region, &mtsb->box));
474
if (mtsb->fixed_count > 0)
475
/* ignore fixed boxes */
477
if (qc->keepaway > mtsb->keepaway)
478
shrink = qc->keepaway - mtsb->keepaway;
479
shrink += qc->radius;
480
shrunk = (BoxType *) calloc (1, sizeof(*shrunk));
481
*shrunk = shrink_box (box, shrink);
482
if (shrunk->X2 <= shrunk->X1
483
|| shrunk->Y2 <= shrunk->Y1 ||
484
!box_intersect (qc->region, shrunk))
489
else if ((qc->is_odd ? mtsb->odd_count : mtsb->even_count) > 0)
491
/* this is a hi_conflict */
492
vector_append (qc->hi_conflict_space_vec, shrunk);
494
else if (mtsb->odd_count > 0 || mtsb->even_count > 0)
496
/* this is a lo_conflict */
497
vector_append (qc->lo_conflict_space_vec, shrunk);
502
assert (boxtype (mtsb) == 0);
503
vector_append (qc->free_space_vec, shrunk);
508
/* returns all empty spaces in 'region' which may hold a feature with the
509
* mtspace feature_radius with the specified minimum keepaway. Completely
510
* empty regions are appended to the free_space_vec vector; regions which
511
* are filled by objects generated by the previous pass are appended to the
512
* lo_conflict_space_vec vector, and regions which are filled by objects
513
* generated during *this* pass are appended to the hi_conflict_space_vec
514
* vector. The current pass identity is given by 'is_odd'. Regions which
515
* are filled by fixed objects are not returned at all. */
517
mtspace_query_rect (mtspace_t * mtspace, const BoxType * region,
518
BDimension radius, BDimension keepaway,
519
vector_t * free_space_vec,
520
vector_t * lo_conflict_space_vec,
521
vector_t * hi_conflict_space_vec, Boolean is_odd)
523
struct query_closure qc;
525
assert (__mtspace_is_good (mtspace));
526
assert (__box_is_good (region));
527
assert (free_space_vec && vector_is_empty (free_space_vec));
528
assert (lo_conflict_space_vec && vector_is_empty (lo_conflict_space_vec));
529
assert (hi_conflict_space_vec && vector_is_empty (hi_conflict_space_vec));
530
/* initialize closure */
532
qc.free_space_vec = free_space_vec;
533
qc.lo_conflict_space_vec = lo_conflict_space_vec;
534
qc.hi_conflict_space_vec = hi_conflict_space_vec;
536
qc.keepaway = keepaway;
539
r_search (mtspace->rtree, region, NULL, query_one, &qc);
540
/* post-assertions */
542
#ifdef SLOW_ASSERTIONS
543
{ /* assert that all returned boxes are inside the given search region */
545
for (i = 0; i < 3; i++)
548
(i == 0) ? free_space_vec :
549
(i == 1) ? lo_conflict_space_vec : hi_conflict_space_vec;
550
for (j = 0; j < vector_size (v); j++)
552
const BoxType *b = (const BoxType *) vector_element (v, j);
553
assert (__box_is_good (b));
554
assert (box_intersect (region, b));
558
#endif /* SLOW_ASSERTIONS */