4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
6 * Copyright (C) 1998,1999,2000,2001 harry eaton
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * Contact addresses for paper mail and Email:
23 * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA
24 * haceaton@aplcomm.jhuapl.edu
28 /* this file, intersect.c, was written and is
29 * Copyright (c) 2001 C. Scott Ananian
32 /* rectangle intersection/union routines.
44 #include "intersect.h"
47 #ifdef HAVE_LIBDMALLOC
51 /* ---------------------------------------------------------------------------
52 * some local prototypes
54 static int compareleft (const void *ptr1
, const void *ptr2
);
55 static int compareright (const void *ptr1
, const void *ptr2
);
56 static int comparepos (const void *ptr1
, const void *ptr2
);
57 static int nextpwrof2 (int i
);
59 /* ---------------------------------------------------------------------------
72 SegmentTreeNode
*nodes
;
84 /* ---------------------------------------------------------------------------
85 * Create a sorted list of unique y coords from a BoxList.
88 createSortedYList (BoxListType
*boxlist
)
93 /* create sorted list of Y coordinates */
94 yCoords
.size
= 2 * boxlist
->BoxN
;
95 yCoords
.p
= (Coord
*)calloc (yCoords
.size
, sizeof (*yCoords
.p
));
96 for (i
= 0; i
< boxlist
->BoxN
; i
++)
98 yCoords
.p
[2 * i
] = boxlist
->Box
[i
].Y1
;
99 yCoords
.p
[2 * i
+ 1] = boxlist
->Box
[i
].Y2
;
101 qsort (yCoords
.p
, yCoords
.size
, sizeof (*yCoords
.p
), comparepos
);
102 /* count uniq y coords */
104 for (n
= 0, i
= 0; i
< yCoords
.size
; i
++)
105 if (i
== 0 || yCoords
.p
[i
] != last
)
106 yCoords
.p
[n
++] = last
= yCoords
.p
[i
];
111 /* ---------------------------------------------------------------------------
112 * Create an empty segment tree from the given sorted list of uniq y coords.
115 createSegmentTree (Coord
* yCoords
, int N
)
119 /* size is twice the nearest larger power of 2 */
120 st
.size
= 2 * nextpwrof2 (N
);
121 st
.nodes
= (SegmentTreeNode
*)calloc (st
.size
, sizeof (*st
.nodes
));
122 /* initialize the rightmost leaf node */
123 st
.nodes
[st
.size
- 1].left
= (N
> 0) ? yCoords
[--N
] : 10;
124 st
.nodes
[st
.size
- 1].right
= st
.nodes
[st
.size
- 1].left
+ 1;
125 /* initialize the rest of the leaf nodes */
126 for (i
= st
.size
- 2; i
>= st
.size
/ 2; i
--)
128 st
.nodes
[i
].right
= st
.nodes
[i
+ 1].left
;
129 st
.nodes
[i
].left
= (N
> 0) ? yCoords
[--N
] : st
.nodes
[i
].right
- 1;
131 /* initialize the internal nodes */
133 { /* node 0 is not used */
134 st
.nodes
[i
].right
= st
.nodes
[2 * i
+ 1].right
;
135 st
.nodes
[i
].left
= st
.nodes
[2 * i
].left
;
142 insertSegment (SegmentTree
* st
, int n
, Coord Y1
, Coord Y2
)
145 if (st
->nodes
[n
].left
>= Y1
&& st
->nodes
[n
].right
<= Y2
)
147 st
->nodes
[n
].covered
++;
151 assert (n
< st
->size
/ 2);
152 discriminant
= st
->nodes
[n
* 2 + 1 /*right */ ].left
;
153 if (Y1
< discriminant
)
154 insertSegment (st
, n
* 2, Y1
, Y2
);
155 if (discriminant
< Y2
)
156 insertSegment (st
, n
* 2 + 1, Y1
, Y2
);
159 st
->nodes
[n
].area
= (st
->nodes
[n
].covered
> 0) ?
160 (st
->nodes
[n
].right
- st
->nodes
[n
].left
) :
161 (n
>= st
->size
/ 2) ? 0 :
162 st
->nodes
[n
* 2].area
+ st
->nodes
[n
* 2 + 1].area
;
166 deleteSegment (SegmentTree
* st
, int n
, Coord Y1
, Coord Y2
)
169 if (st
->nodes
[n
].left
>= Y1
&& st
->nodes
[n
].right
<= Y2
)
171 assert (st
->nodes
[n
].covered
);
172 --st
->nodes
[n
].covered
;
176 assert (n
< st
->size
/ 2);
177 discriminant
= st
->nodes
[n
* 2 + 1 /*right */ ].left
;
178 if (Y1
< discriminant
)
179 deleteSegment (st
, n
* 2, Y1
, Y2
);
180 if (discriminant
< Y2
)
181 deleteSegment (st
, n
* 2 + 1, Y1
, Y2
);
184 st
->nodes
[n
].area
= (st
->nodes
[n
].covered
> 0) ?
185 (st
->nodes
[n
].right
- st
->nodes
[n
].left
) :
186 (n
>= st
->size
/ 2) ? 0 :
187 st
->nodes
[n
* 2].area
+ st
->nodes
[n
* 2 + 1].area
;
190 /* ---------------------------------------------------------------------------
191 * Compute the area of the intersection of the given rectangles; that is,
192 * the area covered by more than one rectangle (counted twice if the area is
193 * covered by three rectangles, three times if covered by four rectangles,
195 * Runs in O(N ln N) time.
198 ComputeIntersectionArea (BoxListType
*boxlist
)
202 /* first get the aggregate area. */
203 for (i
= 0; i
< boxlist
->BoxN
; i
++)
204 area
+= (double) (boxlist
->Box
[i
].X2
- boxlist
->Box
[i
].X1
) *
205 (double) (boxlist
->Box
[i
].Y2
- boxlist
->Box
[i
].Y1
);
206 /* intersection area is aggregate - union. */
207 return area
* 0.0001 - ComputeUnionArea (boxlist
);
210 /* ---------------------------------------------------------------------------
211 * Compute the area of the union of the given rectangles.
215 ComputeUnionArea (BoxListType
*boxlist
)
217 BoxType
**rectLeft
, **rectRight
;
219 LocationList yCoords
;
224 if (boxlist
->BoxN
== 0)
226 /* create sorted list of Y coordinates */
227 yCoords
= createSortedYList (boxlist
);
228 /* now create empty segment tree */
229 segtree
= createSegmentTree (yCoords
.p
, yCoords
.size
);
231 /* create sorted list of left and right X coordinates of rectangles */
232 rectLeft
= (BoxType
**)calloc (boxlist
->BoxN
, sizeof (*rectLeft
));
233 rectRight
= (BoxType
**)calloc (boxlist
->BoxN
, sizeof (*rectRight
));
234 for (i
= 0; i
< boxlist
->BoxN
; i
++)
236 assert (boxlist
->Box
[i
].X1
<= boxlist
->Box
[i
].X2
);
237 assert (boxlist
->Box
[i
].Y1
<= boxlist
->Box
[i
].Y2
);
238 rectLeft
[i
] = rectRight
[i
] = &boxlist
->Box
[i
];
240 qsort (rectLeft
, boxlist
->BoxN
, sizeof (*rectLeft
), compareleft
);
241 qsort (rectRight
, boxlist
->BoxN
, sizeof (*rectRight
), compareright
);
242 /* sweep through x segments from left to right */
244 lastX
= rectLeft
[0]->X1
;
245 while (j
< boxlist
->BoxN
)
247 assert (i
<= boxlist
->BoxN
);
248 /* i will step through rectLeft, j will through rectRight */
249 if (i
== boxlist
->BoxN
|| rectRight
[j
]->X2
< rectLeft
[i
]->X1
)
251 /* right edge of rectangle */
252 BoxType
*b
= rectRight
[j
++];
256 assert (lastX
< b
->X2
);
257 area
+= (double) (b
->X2
- lastX
) * segtree
.nodes
[1].area
;
260 /* remove a segment from the segment tree. */
261 deleteSegment (&segtree
, 1, b
->Y1
, b
->Y2
);
265 /* left edge of rectangle */
266 BoxType
*b
= rectLeft
[i
++];
270 assert (lastX
< b
->X1
);
271 area
+= (double) (b
->X1
- lastX
) * segtree
.nodes
[1].area
;
274 /* add a segment from the segment tree. */
275 insertSegment (&segtree
, 1, b
->Y1
, b
->Y2
);
280 free (segtree
.nodes
);
281 return area
* 0.0001;
284 compareleft (const void *ptr1
, const void *ptr2
)
286 BoxType
**b1
= (BoxType
**) ptr1
;
287 BoxType
**b2
= (BoxType
**) ptr2
;
288 return (*b1
)->X1
- (*b2
)->X1
;
291 compareright (const void *ptr1
, const void *ptr2
)
293 BoxType
**b1
= (BoxType
**) ptr1
;
294 BoxType
**b2
= (BoxType
**) ptr2
;
295 return (*b1
)->X2
- (*b2
)->X2
;
298 comparepos (const void *ptr1
, const void *ptr2
)
300 return *((Coord
*) ptr1
) - *((Coord
*) ptr2
);