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.
32 * Copyright (c) 2006 harry eaton.
35 /* implementation for "empty space" routines (needed for via-space tracking
54 #ifdef HAVE_LIBDMALLOC
60 /* mtspace data structures are built on r-trees. */
62 /* ---------------------------------------------------------------------------
66 typedef struct mtspacebox
69 Coord keepaway
; /* the smallest keepaway around this box */
73 /* this is an mtspace_t */
76 /* rtrees keeping track of regions expanded by their required clearance. */
77 /* one for fixed, even, and odd */
78 rtree_t
*ftree
, *etree
, *otree
;
87 /* this is a vetting_t */
90 heap_or_vector untested
;
91 heap_or_vector no_fix
;
93 heap_or_vector hi_candidate
;
96 CheapPointType desired
;
99 #define SPECIAL 823157
102 mtspace_create_box (const BoxType
* box
, Coord keepaway
)
105 assert (box_is_good (box
));
106 mtsb
= (mtspacebox_t
*)malloc (sizeof (*mtsb
));
107 /* the box was sent to us pre-bloated by the keepaway amount */
108 *((BoxTypePtr
) & mtsb
->box
) = *box
;
109 mtsb
->keepaway
= keepaway
;
110 assert (box_is_good (&mtsb
->box
));
114 /* create an "empty space" representation */
116 mtspace_create (void)
120 /* create mtspace data structure */
121 mtspace
= (mtspace_t
*)malloc (sizeof (*mtspace
));
122 mtspace
->ftree
= r_create_tree (NULL
, 0, 0);
123 mtspace
->etree
= r_create_tree (NULL
, 0, 0);
124 mtspace
->otree
= r_create_tree (NULL
, 0, 0);
129 /* destroy an "empty space" representation. */
131 mtspace_destroy (mtspace_t
** mtspacep
)
134 r_destroy_tree (&(*mtspacep
)->ftree
);
135 r_destroy_tree (&(*mtspacep
)->etree
);
136 r_destroy_tree (&(*mtspacep
)->otree
);
150 mts_remove_one (const BoxType
* b
, void *cl
)
152 struct mts_info
*info
= (struct mts_info
*) cl
;
153 mtspacebox_t
*box
= (mtspacebox_t
*) b
;
155 /* there can be duplicate boxes, we just remove one */
156 /* the info box is pre-bloated, so just check equality */
157 if (b
->X1
== info
->box
.X1
&& b
->X2
== info
->box
.X2
&&
158 b
->Y1
== info
->box
.Y1
&& b
->Y2
== info
->box
.Y2
&&
159 box
->keepaway
== info
->keepaway
)
161 r_delete_entry (info
->tree
, b
);
162 longjmp (info
->env
, 1);
168 which_tree (mtspace_t
* mtspace
, mtspace_type_t which
)
173 return mtspace
->ftree
;
175 return mtspace
->etree
;
177 return mtspace
->otree
;
181 /* add a space-filler to the empty space representation. */
183 mtspace_add (mtspace_t
* mtspace
, const BoxType
* box
, mtspace_type_t which
,
186 mtspacebox_t
*filler
= mtspace_create_box (box
, keepaway
);
187 r_insert_entry (which_tree (mtspace
, which
), (const BoxType
*) filler
, 1);
190 /* remove a space-filler from the empty space representation. */
192 mtspace_remove (mtspace_t
* mtspace
,
193 const BoxType
* box
, mtspace_type_t which
,
197 BoxType small_search
;
199 cl
.keepaway
= keepaway
;
201 cl
.tree
= which_tree (mtspace
, which
);
202 small_search
= box_center(box
);
203 if (setjmp (cl
.env
) == 0)
205 r_search (cl
.tree
, &small_search
, NULL
, mts_remove_one
, &cl
);
206 assert (0); /* didn't find it?? */
213 heap_or_vector checking
;
214 heap_or_vector touching
;
215 CheapPointType
*desired
;
216 Coord radius
, keepaway
;
222 heap_append (heap_t
*heap
, CheapPointType
*desired
, BoxType
*newone
)
224 CheapPointType p
= *desired
;
226 closest_point_in_box (&p
, newone
);
227 heap_insert (heap
, ABS(p
.X
- desired
->X
) + (p
.Y
- desired
->Y
), newone
);
231 append (struct query_closure
* qc
, BoxType
*newone
)
234 heap_append (qc
->checking
.h
, qc
->desired
, newone
);
236 vector_append (qc
->checking
.v
, newone
);
239 /* we found some space filler that may intersect this query.
240 * First check if it does intersect, then break it into
241 * overlaping regions that don't intersect this box.
244 query_one (const BoxType
* box
, void *cl
)
246 struct query_closure
*qc
= (struct query_closure
*) cl
;
247 mtspacebox_t
*mtsb
= (mtspacebox_t
*) box
;
249 assert (box_intersect (qc
->cbox
, &mtsb
->box
));
250 /* we need to satisfy the larger of the two keepaways */
251 if (qc
->keepaway
> mtsb
->keepaway
)
252 shrink
= mtsb
->keepaway
;
254 shrink
= qc
->keepaway
;
255 /* if we shrink qc->box by this amount and it doesn't intersect
256 * then we didn't actually touch this box */
257 if (qc
->cbox
->X1
+ shrink
>= mtsb
->box
.X2
||
258 qc
->cbox
->X2
- shrink
<= mtsb
->box
.X1
||
259 qc
->cbox
->Y1
+ shrink
>= mtsb
->box
.Y2
||
260 qc
->cbox
->Y2
- shrink
<= mtsb
->box
.Y1
)
262 /* ok, we do touch this box, now create up to 4 boxes that don't */
263 if (mtsb
->box
.Y1
> qc
->cbox
->Y1
+ shrink
) /* top region exists */
265 Coord Y1
= qc
->cbox
->Y1
;
266 Coord Y2
= mtsb
->box
.Y1
+ shrink
;
267 if (Y2
- Y1
>= 2 * (qc
->radius
+ qc
->keepaway
))
269 BoxType
*newone
= (BoxType
*) malloc (sizeof (BoxType
));
270 newone
->X1
= qc
->cbox
->X1
;
271 newone
->X2
= qc
->cbox
->X2
;
274 assert (newone
->Y2
< qc
->cbox
->Y2
);
278 if (mtsb
->box
.Y2
< qc
->cbox
->Y2
- shrink
) /* bottom region exists */
280 Coord Y1
= mtsb
->box
.Y2
- shrink
;
281 Coord Y2
= qc
->cbox
->Y2
;
282 if (Y2
- Y1
>= 2 * (qc
->radius
+ qc
->keepaway
))
284 BoxType
*newone
= (BoxType
*) malloc (sizeof (BoxType
));
285 newone
->X1
= qc
->cbox
->X1
;
286 newone
->X2
= qc
->cbox
->X2
;
287 newone
->Y2
= qc
->cbox
->Y2
;
289 assert (newone
->Y1
> qc
->cbox
->Y1
);
293 if (mtsb
->box
.X1
> qc
->cbox
->X1
+ shrink
) /* left region exists */
295 Coord X1
= qc
->cbox
->X1
;
296 Coord X2
= mtsb
->box
.X1
+ shrink
;
297 if (X2
- X1
>= 2 * (qc
->radius
+ qc
->keepaway
))
300 newone
= (BoxType
*) malloc (sizeof (BoxType
));
301 newone
->Y1
= qc
->cbox
->Y1
;
302 newone
->Y2
= qc
->cbox
->Y2
;
303 newone
->X1
= qc
->cbox
->X1
;
305 assert (newone
->X2
< qc
->cbox
->X2
);
309 if (mtsb
->box
.X2
< qc
->cbox
->X2
- shrink
) /* right region exists */
311 Coord X1
= mtsb
->box
.X2
- shrink
;
312 Coord X2
= qc
->cbox
->X2
;
313 if (X2
- X1
>= 2 * (qc
->radius
+ qc
->keepaway
))
315 BoxType
*newone
= (BoxType
*) malloc (sizeof (BoxType
));
316 newone
->Y1
= qc
->cbox
->Y1
;
317 newone
->Y2
= qc
->cbox
->Y2
;
318 newone
->X2
= qc
->cbox
->X2
;
320 assert (newone
->X1
> qc
->cbox
->X1
);
326 if (qc
->touch_is_vec
|| !qc
->desired
)
327 vector_append (qc
->touching
.v
, qc
->cbox
);
329 heap_append (qc
->touching
.h
, qc
->desired
, qc
->cbox
);
332 free (qc
->cbox
); /* done with this one */
333 longjmp (qc
->env
, 1);
334 return 1; /* never reached */
337 /* qloop takes a vector (or heap) of regions to check (checking) if they don't intersect
338 * anything. If a region does intersect something, it is broken into
339 * pieces that don't intersect that thing (if possible) which are
340 * put back into the vector/heap of regions to check.
341 * qloop returns false when it finds the first empty region
342 * it returns true if it has exhausted the region vector/heap and never
343 * found an empty area.
346 qloop (struct query_closure
*qc
, rtree_t
* tree
, heap_or_vector res
, bool is_vec
)
352 while (!(qc
->desired
? heap_is_empty (qc
->checking
.h
) : vector_is_empty (qc
->checking
.v
)))
354 cbox
= qc
->desired
? (BoxTypePtr
)heap_remove_smallest (qc
->checking
.h
) : (BoxTypePtr
)vector_remove_last (qc
->checking
.v
);
355 if (setjmp (qc
->env
) == 0)
357 assert (box_is_good (cbox
));
362 r_search (tree
, cbox
, NULL
, query_one
, qc
);
364 /* nothing intersected with this tree, put it in the result vector */
366 vector_append (res
.v
, cbox
);
370 heap_append (res
.h
, qc
->desired
, cbox
);
372 vector_append (res
.v
, cbox
);
374 return; /* found one - perhaps one answer is good enough */
379 /* free the memory used by the vetting structure */
381 mtsFreeWork (vetting_t
** w
)
383 vetting_t
*work
= (*w
);
384 if (work
->desired
.X
!= -SPECIAL
|| work
->desired
.Y
!= -SPECIAL
)
386 heap_free (work
->untested
.h
, free
);
387 heap_destroy (&work
->untested
.h
);
388 heap_free (work
->no_fix
.h
, free
);
389 heap_destroy (&work
->no_fix
.h
);
390 heap_free (work
->no_hi
.h
, free
);
391 heap_destroy (&work
->no_hi
.h
);
392 heap_free (work
->hi_candidate
.h
, free
);
393 heap_destroy (&work
->hi_candidate
.h
);
397 while (!vector_is_empty (work
->untested
.v
))
398 free (vector_remove_last (work
->untested
.v
));
399 vector_destroy (&work
->untested
.v
);
400 while (!vector_is_empty (work
->no_fix
.v
))
401 free (vector_remove_last (work
->no_fix
.v
));
402 vector_destroy (&work
->no_fix
.v
);
403 while (!vector_is_empty (work
->no_hi
.v
))
404 free (vector_remove_last (work
->no_hi
.v
));
405 vector_destroy (&work
->no_hi
.v
);
406 while (!vector_is_empty (work
->hi_candidate
.v
))
407 free (vector_remove_last (work
->hi_candidate
.v
));
408 vector_destroy (&work
->hi_candidate
.v
);
415 /* returns some empty spaces in 'region' (or former narrowed regions)
416 * that may hold a feature with the specified radius and keepaway
417 * It tries first to find Completely empty regions (which are appended
418 * to the free_space_vec vector). If that fails, it looks for regions
419 * filled only by objects generated by the previous pass (which are
420 * appended to the lo_conflict_space_vec vector). Then it looks for
421 * regions that are filled by objects generated during *this* pass
422 * (which are appended to the hi_conflict_space_vec vector). The
423 * current pass identity is given by 'is_odd'. As soon as one completely
424 * free region is found, it returns with that answer. It saves partially
425 * searched regions in vectors "untested", "no_fix", "no_hi", and
426 * "hi_candidate" which can be passed to future calls of this function
427 * to search harder for such regions if the computation becomes
431 mtspace_query_rect (mtspace_t
* mtspace
, const BoxType
* region
,
432 Coord radius
, Coord keepaway
,
434 vector_t
* free_space_vec
,
435 vector_t
* lo_conflict_space_vec
,
436 vector_t
* hi_conflict_space_vec
,
437 bool is_odd
, bool with_conflicts
, CheapPointType
*desired
)
439 struct query_closure qc
;
442 assert (free_space_vec
);
443 assert (lo_conflict_space_vec
);
444 assert (hi_conflict_space_vec
);
445 /* search out to anything that might matter */
449 assert (work
== NULL
);
450 assert (box_is_good (region
));
451 assert(vector_is_empty (free_space_vec
));
452 assert(vector_is_empty (lo_conflict_space_vec
));
453 assert(vector_is_empty (hi_conflict_space_vec
));
454 work
= (vetting_t
*) malloc (sizeof (vetting_t
));
455 work
->keepaway
= keepaway
;
456 work
->radius
= radius
;
457 cbox
= (BoxType
*) malloc (sizeof (BoxType
));
458 *cbox
= bloat_box (region
, keepaway
+ radius
);
461 work
->untested
.h
= heap_create ();
462 work
->no_fix
.h
= heap_create ();
463 work
->hi_candidate
.h
= heap_create ();
464 work
->no_hi
.h
=heap_create ();
465 assert (work
->untested
.h
&& work
->no_fix
.h
&&
466 work
->no_hi
.h
&& work
->hi_candidate
.h
);
467 heap_insert (work
->untested
.h
, 0, cbox
);
468 work
->desired
= *desired
;
472 work
->untested
.v
= vector_create ();
473 work
->no_fix
.v
= vector_create ();
474 work
->hi_candidate
.v
= vector_create ();
475 work
->no_hi
.v
= vector_create ();
476 assert (work
->untested
.v
&& work
->no_fix
.v
&&
477 work
->no_hi
.v
&& work
->hi_candidate
.v
);
478 vector_append (work
->untested
.v
, cbox
);
479 work
->desired
.X
= work
->desired
.Y
= -SPECIAL
;
483 qc
.keepaway
= work
->keepaway
;
484 qc
.radius
= work
->radius
;
485 if (work
->desired
.X
== -SPECIAL
&& work
->desired
.Y
== -SPECIAL
)
488 qc
.desired
= &work
->desired
;
492 heap_or_vector temporary
= {free_space_vec
};
493 /* search the fixed object tree discarding any intersections
494 * and placing empty regions in the no_fix vector.
496 qc
.checking
= work
->untested
;
497 qc
.touching
.v
= NULL
;
498 qloop (&qc
, mtspace
->ftree
, work
->no_fix
, false);
499 /* search the hi-conflict tree placing intersectors in the
500 * hi_candidate vector (if conflicts are allowed) and
501 * placing empty regions in the no_hi vector.
503 qc
.checking
.v
= work
->no_fix
.v
;
504 qc
.touching
.v
= with_conflicts
? work
->hi_candidate
.v
: NULL
;
505 qc
.touch_is_vec
= false;
506 qloop (&qc
, is_odd
? mtspace
->otree
: mtspace
->etree
, work
->no_hi
, false);
507 /* search the lo-conflict tree placing intersectors in the
508 * lo-conflict answer vector (if conflicts allowed) and
509 * placing emptry regions in the free-space answer vector.
511 qc
.checking
= work
->no_hi
;
512 /* XXX lo_conflict_space_vec will be treated like a heap! */
513 qc
.touching
.v
= (with_conflicts
? lo_conflict_space_vec
: NULL
);
514 qc
.touch_is_vec
= true;
515 qloop (&qc
, is_odd
? mtspace
->etree
: mtspace
->otree
, temporary
, true);
517 /* qloop (&qc, is_odd ? mtspace->etree : mtspace->otree, (heap_or_vector)free_space_vec, true); */
518 if (!vector_is_empty (free_space_vec
))
522 if (heap_is_empty (work
->untested
.h
))
527 if (vector_is_empty (work
->untested
.v
))
532 /* finally check the hi-conflict intersectors against the
533 * lo-conflict tree discarding intersectors (two types of conflict is real bad)
534 * and placing empty regions in the hi-conflict answer vector.
538 heap_or_vector temporary
= {hi_conflict_space_vec
};
539 qc
.checking
= work
->hi_candidate
;
540 qc
.touching
.v
= NULL
;
541 qloop (&qc
, is_odd
? mtspace
->etree
: mtspace
->otree
,
544 /* qloop (&qc, is_odd ? mtspace->etree : mtspace->otree, */
545 /* (heap_or_vector)hi_conflict_space_vec, true); */
548 while (!(qc
.desired
? heap_is_empty(work
->untested
.h
) : vector_is_empty (work
->untested
.v
)));
551 if (heap_is_empty (work
->no_fix
.h
) &&
552 heap_is_empty (work
->no_hi
.h
) &&
553 heap_is_empty (work
->hi_candidate
.h
))
561 if (vector_is_empty (work
->no_fix
.v
) &&
562 vector_is_empty (work
->no_hi
.v
) && vector_is_empty (work
->hi_candidate
.v
))
572 mtsBoxCount (vetting_t
* w
)
576 ans
= 3 * vector_size (w
->untested
);
577 ans
+= 2 * vector_size (w
->no_fix
);
578 ans
+= vector_size (w
->no_hi
);
579 ans
+= vector_size (w
->hi_candidate
);