hid/gtk: Fix pinout preview rendering for back-side elements
[geda-pcb/pcjc2.git] / src / intersect.c
bloba3ee03f3d747d2441f7c34ebb4aff2c699a1f7d3
1 /* $Id$ */
3 /*
4 * COPYRIGHT
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.
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
41 #include "global.h"
43 #include <assert.h>
45 #include "data.h"
46 #include "intersect.h"
47 #include "mymem.h"
49 #ifdef HAVE_LIBDMALLOC
50 #include <dmalloc.h>
51 #endif
53 RCSID ("$Id$");
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 /* ---------------------------------------------------------------------------
65 * some local types
67 typedef struct
69 Coord left, right;
70 int covered;
71 Coord area;
73 SegmentTreeNode;
75 typedef struct
77 SegmentTreeNode *nodes;
78 int size;
80 SegmentTree;
82 typedef struct
84 Coord *p;
85 int size;
87 LocationList;
89 /* ---------------------------------------------------------------------------
90 * Create a sorted list of unique y coords from a BoxList.
92 static LocationList
93 createSortedYList (BoxListTypePtr boxlist)
95 LocationList yCoords;
96 Coord last;
97 int i, n;
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 */
108 last = 0;
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];
112 yCoords.size = n;
113 return yCoords;
116 /* ---------------------------------------------------------------------------
117 * Create an empty segment tree from the given sorted list of uniq y coords.
119 static SegmentTree
120 createSegmentTree (Coord * yCoords, int N)
122 SegmentTree st;
123 int i;
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 */
137 for (; i > 0; i--)
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;
142 /* done! */
143 return st;
146 void
147 insertSegment (SegmentTree * st, int n, Coord Y1, Coord Y2)
149 Coord discriminant;
150 if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2)
152 st->nodes[n].covered++;
154 else
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);
163 /* fixup area */
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;
170 void
171 deleteSegment (SegmentTree * st, int n, Coord Y1, Coord Y2)
173 Coord discriminant;
174 if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2)
176 assert (st->nodes[n].covered);
177 --st->nodes[n].covered;
179 else
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);
188 /* fixup area */
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,
199 * etc.).
200 * Runs in O(N ln N) time.
202 double
203 ComputeIntersectionArea (BoxListTypePtr boxlist)
205 Cardinal i;
206 double area = 0.0;
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.
217 * O(N ln N) time.
219 double
220 ComputeUnionArea (BoxListTypePtr boxlist)
222 BoxTypePtr *rectLeft, *rectRight;
223 Cardinal i, j;
224 LocationList yCoords;
225 SegmentTree segtree;
226 Coord lastX;
227 double area = 0.0;
229 if (boxlist->BoxN == 0)
230 return 0.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);
235 free (yCoords.p);
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 */
248 i = j = 0;
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++];
258 /* check lastX */
259 if (b->X2 != lastX)
261 assert (lastX < b->X2);
262 area += (double) (b->X2 - lastX) * segtree.nodes[1].area;
263 lastX = b->X2;
265 /* remove a segment from the segment tree. */
266 deleteSegment (&segtree, 1, b->Y1, b->Y2);
268 else
270 /* left edge of rectangle */
271 BoxTypePtr b = rectLeft[i++];
272 /* check lastX */
273 if (b->X1 != lastX)
275 assert (lastX < b->X1);
276 area += (double) (b->X1 - lastX) * segtree.nodes[1].area;
277 lastX = b->X1;
279 /* add a segment from the segment tree. */
280 insertSegment (&segtree, 1, b->Y1, b->Y2);
283 free (rectLeft);
284 free (rectRight);
285 free (segtree.nodes);
286 return area * 0.0001;
288 static int
289 compareleft (const void *ptr1, const void *ptr2)
291 BoxTypePtr *b1 = (BoxTypePtr *) ptr1, *b2 = (BoxTypePtr *) ptr2;
292 return (*b1)->X1 - (*b2)->X1;
294 static int
295 compareright (const void *ptr1, const void *ptr2)
297 BoxTypePtr *b1 = (BoxTypePtr *) ptr1, *b2 = (BoxTypePtr *) ptr2;
298 return (*b1)->X2 - (*b2)->X2;
300 static int
301 comparepos (const void *ptr1, const void *ptr2)
303 return *((Coord *) ptr1) - *((Coord *) ptr2);
305 static int
306 nextpwrof2 (int n)
308 int r = 1;
309 while (n != 0)
311 n /= 2;
312 r *= 2;
314 return r;