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.
46 #include "intersect.h"
49 #ifdef HAVE_LIBDMALLOC
56 /* ---------------------------------------------------------------------------
57 * some local prototypes
59 static int compareleft (const void *ptr1
, const void *ptr2
);
60 static int compareright (const void *ptr1
, const void *ptr2
);
61 static int comparepos (const void *ptr1
, const void *ptr2
);
62 static int nextpwrof2 (int i
);
64 /* ---------------------------------------------------------------------------
77 SegmentTreeNode
*nodes
;
89 /* ---------------------------------------------------------------------------
90 * Create a sorted list of unique y coords from a BoxList.
93 createSortedYList (BoxListTypePtr boxlist
)
98 /* create sorted list of Y coordinates */
99 yCoords
.size
= 2 * boxlist
->BoxN
;
100 yCoords
.p
= (Coord
*)calloc (yCoords
.size
, sizeof (*yCoords
.p
));
101 for (i
= 0; i
< boxlist
->BoxN
; i
++)
103 yCoords
.p
[2 * i
] = boxlist
->Box
[i
].Y1
;
104 yCoords
.p
[2 * i
+ 1] = boxlist
->Box
[i
].Y2
;
106 qsort (yCoords
.p
, yCoords
.size
, sizeof (*yCoords
.p
), comparepos
);
107 /* count uniq y coords */
109 for (n
= 0, i
= 0; i
< yCoords
.size
; i
++)
110 if (i
== 0 || yCoords
.p
[i
] != last
)
111 yCoords
.p
[n
++] = last
= yCoords
.p
[i
];
116 /* ---------------------------------------------------------------------------
117 * Create an empty segment tree from the given sorted list of uniq y coords.
120 createSegmentTree (Coord
* yCoords
, int N
)
124 /* size is twice the nearest larger power of 2 */
125 st
.size
= 2 * nextpwrof2 (N
);
126 st
.nodes
= (SegmentTreeNode
*)calloc (st
.size
, sizeof (*st
.nodes
));
127 /* initialize the rightmost leaf node */
128 st
.nodes
[st
.size
- 1].left
= (N
> 0) ? yCoords
[--N
] : 10;
129 st
.nodes
[st
.size
- 1].right
= st
.nodes
[st
.size
- 1].left
+ 1;
130 /* initialize the rest of the leaf nodes */
131 for (i
= st
.size
- 2; i
>= st
.size
/ 2; i
--)
133 st
.nodes
[i
].right
= st
.nodes
[i
+ 1].left
;
134 st
.nodes
[i
].left
= (N
> 0) ? yCoords
[--N
] : st
.nodes
[i
].right
- 1;
136 /* initialize the internal nodes */
138 { /* node 0 is not used */
139 st
.nodes
[i
].right
= st
.nodes
[2 * i
+ 1].right
;
140 st
.nodes
[i
].left
= st
.nodes
[2 * i
].left
;
147 insertSegment (SegmentTree
* st
, int n
, Coord Y1
, Coord Y2
)
150 if (st
->nodes
[n
].left
>= Y1
&& st
->nodes
[n
].right
<= Y2
)
152 st
->nodes
[n
].covered
++;
156 assert (n
< st
->size
/ 2);
157 discriminant
= st
->nodes
[n
* 2 + 1 /*right */ ].left
;
158 if (Y1
< discriminant
)
159 insertSegment (st
, n
* 2, Y1
, Y2
);
160 if (discriminant
< Y2
)
161 insertSegment (st
, n
* 2 + 1, Y1
, Y2
);
164 st
->nodes
[n
].area
= (st
->nodes
[n
].covered
> 0) ?
165 (st
->nodes
[n
].right
- st
->nodes
[n
].left
) :
166 (n
>= st
->size
/ 2) ? 0 :
167 st
->nodes
[n
* 2].area
+ st
->nodes
[n
* 2 + 1].area
;
171 deleteSegment (SegmentTree
* st
, int n
, Coord Y1
, Coord Y2
)
174 if (st
->nodes
[n
].left
>= Y1
&& st
->nodes
[n
].right
<= Y2
)
176 assert (st
->nodes
[n
].covered
);
177 --st
->nodes
[n
].covered
;
181 assert (n
< st
->size
/ 2);
182 discriminant
= st
->nodes
[n
* 2 + 1 /*right */ ].left
;
183 if (Y1
< discriminant
)
184 deleteSegment (st
, n
* 2, Y1
, Y2
);
185 if (discriminant
< Y2
)
186 deleteSegment (st
, n
* 2 + 1, Y1
, Y2
);
189 st
->nodes
[n
].area
= (st
->nodes
[n
].covered
> 0) ?
190 (st
->nodes
[n
].right
- st
->nodes
[n
].left
) :
191 (n
>= st
->size
/ 2) ? 0 :
192 st
->nodes
[n
* 2].area
+ st
->nodes
[n
* 2 + 1].area
;
195 /* ---------------------------------------------------------------------------
196 * Compute the area of the intersection of the given rectangles; that is,
197 * the area covered by more than one rectangle (counted twice if the area is
198 * covered by three rectangles, three times if covered by four rectangles,
200 * Runs in O(N ln N) time.
203 ComputeIntersectionArea (BoxListTypePtr boxlist
)
207 /* first get the aggregate area. */
208 for (i
= 0; i
< boxlist
->BoxN
; i
++)
209 area
+= (double) (boxlist
->Box
[i
].X2
- boxlist
->Box
[i
].X1
) *
210 (double) (boxlist
->Box
[i
].Y2
- boxlist
->Box
[i
].Y1
);
211 /* intersection area is aggregate - union. */
212 return area
* 0.0001 - ComputeUnionArea (boxlist
);
215 /* ---------------------------------------------------------------------------
216 * Compute the area of the union of the given rectangles.
220 ComputeUnionArea (BoxListTypePtr boxlist
)
222 BoxTypePtr
*rectLeft
, *rectRight
;
224 LocationList yCoords
;
229 if (boxlist
->BoxN
== 0)
231 /* create sorted list of Y coordinates */
232 yCoords
= createSortedYList (boxlist
);
233 /* now create empty segment tree */
234 segtree
= createSegmentTree (yCoords
.p
, yCoords
.size
);
236 /* create sorted list of left and right X coordinates of rectangles */
237 rectLeft
= (BoxTypePtr
*)calloc (boxlist
->BoxN
, sizeof (*rectLeft
));
238 rectRight
= (BoxTypePtr
*)calloc (boxlist
->BoxN
, sizeof (*rectRight
));
239 for (i
= 0; i
< boxlist
->BoxN
; i
++)
241 assert (boxlist
->Box
[i
].X1
<= boxlist
->Box
[i
].X2
);
242 assert (boxlist
->Box
[i
].Y1
<= boxlist
->Box
[i
].Y2
);
243 rectLeft
[i
] = rectRight
[i
] = &boxlist
->Box
[i
];
245 qsort (rectLeft
, boxlist
->BoxN
, sizeof (*rectLeft
), compareleft
);
246 qsort (rectRight
, boxlist
->BoxN
, sizeof (*rectRight
), compareright
);
247 /* sweep through x segments from left to right */
249 lastX
= rectLeft
[0]->X1
;
250 while (j
< boxlist
->BoxN
)
252 assert (i
<= boxlist
->BoxN
);
253 /* i will step through rectLeft, j will through rectRight */
254 if (i
== boxlist
->BoxN
|| rectRight
[j
]->X2
< rectLeft
[i
]->X1
)
256 /* right edge of rectangle */
257 BoxTypePtr b
= rectRight
[j
++];
261 assert (lastX
< b
->X2
);
262 area
+= (double) (b
->X2
- lastX
) * segtree
.nodes
[1].area
;
265 /* remove a segment from the segment tree. */
266 deleteSegment (&segtree
, 1, b
->Y1
, b
->Y2
);
270 /* left edge of rectangle */
271 BoxTypePtr b
= rectLeft
[i
++];
275 assert (lastX
< b
->X1
);
276 area
+= (double) (b
->X1
- lastX
) * segtree
.nodes
[1].area
;
279 /* add a segment from the segment tree. */
280 insertSegment (&segtree
, 1, b
->Y1
, b
->Y2
);
285 free (segtree
.nodes
);
286 return area
* 0.0001;
289 compareleft (const void *ptr1
, const void *ptr2
)
291 BoxTypePtr
*b1
= (BoxTypePtr
*) ptr1
, *b2
= (BoxTypePtr
*) ptr2
;
292 return (*b1
)->X1
- (*b2
)->X1
;
295 compareright (const void *ptr1
, const void *ptr2
)
297 BoxTypePtr
*b1
= (BoxTypePtr
*) ptr1
, *b2
= (BoxTypePtr
*) ptr2
;
298 return (*b1
)->X2
- (*b2
)->X2
;
301 comparepos (const void *ptr1
, const void *ptr2
)
303 return *((Coord
*) ptr1
) - *((Coord
*) ptr2
);