1
/* $Id: intersect.c,v 1.6 2005/01/03 12:56:59 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, intersect.c, was written and is
31
* Copyright (c) 2001 C. Scott Ananian
34
/* rectangle intersection/union routines.
47
#include "intersect.h"
50
#ifdef HAVE_LIBDMALLOC
54
RCSID("$Id: intersect.c,v 1.6 2005/01/03 12:56:59 danmc Exp $");
57
/* ---------------------------------------------------------------------------
58
* some local prototypes
60
static int compareleft (const void *ptr1, const void *ptr2);
61
static int compareright (const void *ptr1, const void *ptr2);
62
static int comparepos (const void *ptr1, const void *ptr2);
63
static int nextpwrof2 (int i);
65
/* ---------------------------------------------------------------------------
70
LocationType left, right;
78
SegmentTreeNode *nodes;
90
/* ---------------------------------------------------------------------------
91
* Create a sorted list of unique y coords from a BoxList.
94
createSortedYList (BoxListTypePtr boxlist)
99
/* create sorted list of Y coordinates */
100
yCoords.size = 2 * boxlist->BoxN;
101
yCoords.p = MyCalloc (yCoords.size, sizeof (*yCoords.p),
102
"createSortedYList");
103
for (i = 0; i < boxlist->BoxN; i++)
105
yCoords.p[2 * i] = boxlist->Box[i].Y1;
106
yCoords.p[2 * i + 1] = boxlist->Box[i].Y2;
108
qsort (yCoords.p, yCoords.size, sizeof (*yCoords.p), comparepos);
109
/* count uniq y coords */
111
for (n = 0, i = 0; i < yCoords.size; i++)
112
if (i == 0 || yCoords.p[i] != last)
113
yCoords.p[n++] = last = yCoords.p[i];
118
/* ---------------------------------------------------------------------------
119
* Create an empty segment tree from the given sorted list of uniq y coords.
122
createSegmentTree (LocationType * yCoords, int N)
126
/* size is twice the nearest larger power of 2 */
127
st.size = 2 * nextpwrof2 (N);
128
st.nodes = MyCalloc (st.size, sizeof (*st.nodes), "createSegmentTree");
129
/* initialize the rightmost leaf node */
130
st.nodes[st.size - 1].left = (N > 0) ? yCoords[--N] : 10;
131
st.nodes[st.size - 1].right = st.nodes[st.size - 1].left + 1;
132
/* initialize the rest of the leaf nodes */
133
for (i = st.size - 2; i >= st.size / 2; i--)
135
st.nodes[i].right = st.nodes[i + 1].left;
136
st.nodes[i].left = (N > 0) ? yCoords[--N] : st.nodes[i].right - 1;
138
/* initialize the internal nodes */
140
{ /* node 0 is not used */
141
st.nodes[i].right = st.nodes[2 * i + 1].right;
142
st.nodes[i].left = st.nodes[2 * i].left;
149
insertSegment (SegmentTree * st, int n, LocationType Y1, LocationType Y2)
151
LocationType discriminant;
152
if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2)
154
st->nodes[n].covered++;
158
assert (n < st->size / 2);
159
discriminant = st->nodes[n * 2 + 1 /*right */ ].left;
160
if (Y1 < discriminant)
161
insertSegment (st, n * 2, Y1, Y2);
162
if (discriminant < Y2)
163
insertSegment (st, n * 2 + 1, Y1, Y2);
166
st->nodes[n].area = (st->nodes[n].covered > 0) ?
167
(st->nodes[n].right - st->nodes[n].left) :
168
(n >= st->size / 2) ? 0 :
169
st->nodes[n * 2].area + st->nodes[n * 2 + 1].area;
173
deleteSegment (SegmentTree * st, int n, LocationType Y1, LocationType Y2)
175
LocationType discriminant;
176
if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2)
178
assert (st->nodes[n].covered);
179
--st->nodes[n].covered;
183
assert (n < st->size / 2);
184
discriminant = st->nodes[n * 2 + 1 /*right */ ].left;
185
if (Y1 < discriminant)
186
deleteSegment (st, n * 2, Y1, Y2);
187
if (discriminant < Y2)
188
deleteSegment (st, n * 2 + 1, Y1, Y2);
191
st->nodes[n].area = (st->nodes[n].covered > 0) ?
192
(st->nodes[n].right - st->nodes[n].left) :
193
(n >= st->size / 2) ? 0 :
194
st->nodes[n * 2].area + st->nodes[n * 2 + 1].area;
197
/* ---------------------------------------------------------------------------
198
* Compute the area of the intersection of the given rectangles; that is,
199
* the area covered by more than one rectangle (counted twice if the area is
200
* covered by three rectangles, three times if covered by four rectangles,
202
* Runs in O(N ln N) time.
205
ComputeIntersectionArea (BoxListTypePtr boxlist)
209
/* first get the aggregate area. */
210
for (i = 0; i < boxlist->BoxN; i++)
211
area += (double)(boxlist->Box[i].X2 - boxlist->Box[i].X1) *
212
(double) (boxlist->Box[i].Y2 - boxlist->Box[i].Y1);
213
/* intersection area is aggregate - union. */
214
return area * 0.0001 - ComputeUnionArea (boxlist);
217
/* ---------------------------------------------------------------------------
218
* Compute the area of the union of the given rectangles.
222
ComputeUnionArea (BoxListTypePtr boxlist)
224
BoxTypePtr *rectLeft, *rectRight;
226
LocationList yCoords;
230
/* create sorted list of Y coordinates */
231
yCoords = createSortedYList (boxlist);
232
/* now create empty segment tree */
233
segtree = createSegmentTree (yCoords.p, yCoords.size);
235
/* create sorted list of left and right X coordinates of rectangles */
236
rectLeft = MyCalloc (boxlist->BoxN, sizeof (*rectLeft),
237
"ComputeUnionArea(1)");
238
rectRight = MyCalloc (boxlist->BoxN, sizeof (*rectRight),
239
"ComputeUnionArea(2)");
240
for (i = 0; i < boxlist->BoxN; i++)
242
assert (boxlist->Box[i].X1 <= boxlist->Box[i].X2);
243
assert (boxlist->Box[i].Y1 <= boxlist->Box[i].Y2);
244
rectLeft[i] = rectRight[i] = &boxlist->Box[i];
246
qsort (rectLeft, boxlist->BoxN, sizeof (*rectLeft), compareleft);
247
qsort (rectRight, boxlist->BoxN, sizeof (*rectRight), compareright);
248
/* sweep through x segments from left to right */
250
lastX = rectLeft[0]->X1;
251
while (j < boxlist->BoxN)
253
assert (i <= boxlist->BoxN);
254
/* i will step through rectLeft, j will through rectRight */
255
if (i == boxlist->BoxN || rectRight[j]->X2 < rectLeft[i]->X1)
257
/* right edge of rectangle */
258
BoxTypePtr b = rectRight[j++];
262
assert (lastX < b->X2);
263
area += (double)(b->X2 - lastX) * segtree.nodes[1].area;
266
/* remove a segment from the segment tree. */
267
deleteSegment (&segtree, 1, b->Y1, b->Y2);
271
/* left edge of rectangle */
272
BoxTypePtr b = rectLeft[i++];
276
assert (lastX < b->X1);
277
area += (double)(b->X1 - lastX) * segtree.nodes[1].area;
280
/* add a segment from the segment tree. */
281
insertSegment (&segtree, 1, b->Y1, b->Y2);
286
free (segtree.nodes);
287
return area * 0.0001;
290
compareleft (const void *ptr1, const void *ptr2)
292
BoxTypePtr *b1 = (BoxTypePtr *) ptr1, *b2 = (BoxTypePtr *) ptr2;
293
return (*b1)->X1 - (*b2)->X1;
296
compareright (const void *ptr1, const void *ptr2)
298
BoxTypePtr *b1 = (BoxTypePtr *) ptr1, *b2 = (BoxTypePtr *) ptr2;
299
return (*b1)->X2 - (*b2)->X2;
302
comparepos (const void *ptr1, const void *ptr2)
304
return *((LocationType *) ptr1) - *((LocationType *) ptr2);