Fix poly_ComputeInteriorPoint() to work correctly for holes
[geda-pcb/gde.git] / src / thermal.c
blob445b97df7a4bfb587fd6a011e15c128102d979aa
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996,2004,2006 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* this file, thermal.c was written by and is
30 * (C) Copyright 2006, harry eaton
33 /* negative thermal finger polygons
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #ifdef HAVE_STRING_H
43 #include <string.h>
44 #endif
45 #include <assert.h>
46 #include <setjmp.h>
47 #include <memory.h>
48 #include <ctype.h>
49 #include <signal.h>
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/types.h>
53 #include <math.h>
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
57 #ifdef HAVE_PWD_H
58 #include <pwd.h>
59 #endif
61 #include "global.h"
63 #include "create.h"
64 #include "data.h"
65 #include "draw.h"
66 #include "error.h"
67 #include "misc.h"
68 #include "move.h"
69 #include "polygon.h"
70 #include "rtree.h"
71 #include "thermal.h"
72 #include "undo.h"
74 #ifdef HAVE_LIBDMALLOC
75 #include <dmalloc.h>
76 #endif
78 RCSID ("$Id$");
80 static PCBTypePtr pcb;
82 struct cent
84 LocationType x, y;
85 BDimension s, c;
86 char style;
87 POLYAREA *p;
90 static POLYAREA *
91 diag_line (LocationType X, LocationType Y, BDimension l, BDimension w,
92 Boolean rt)
94 PLINE *c;
95 Vector v;
96 BDimension x1, x2, y1, y2;
98 if (rt)
100 x1 = (l - w) * M_SQRT1_2;
101 x2 = (l + w) * M_SQRT1_2;
102 y1 = x1;
103 y2 = x2;
105 else
107 x2 = -(l - w) * M_SQRT1_2;
108 x1 = -(l + w) * M_SQRT1_2;
109 y1 = -x1;
110 y2 = -x2;
113 v[0] = X + x1;
114 v[1] = Y + y2;
115 if ((c = poly_NewContour (v)) == NULL)
116 return NULL;
117 v[0] = X - x2;
118 v[1] = Y - y1;
119 poly_InclVertex (c->head.prev, poly_CreateNode (v));
120 v[0] = X - x1;
121 v[1] = Y - y2;
122 poly_InclVertex (c->head.prev, poly_CreateNode (v));
123 v[0] = X + x2;
124 v[1] = Y + y1;
125 poly_InclVertex (c->head.prev, poly_CreateNode (v));
126 return ContourToPoly (c);
129 static POLYAREA *
130 square_therm (PinTypePtr pin, Cardinal style)
132 POLYAREA *p, *p2;
133 PLINE *c;
134 Vector v;
135 BDimension d, in, out;
137 switch (style)
139 case 1:
140 d = pcb->ThermScale * pin->Clearance * M_SQRT1_2;
141 out = (pin->Thickness + pin->Clearance) / 2;
142 in = pin->Thickness / 2;
143 /* top (actually bottom since +y is down) */
144 v[0] = pin->X - in + d;
145 v[1] = pin->Y + in;
146 if ((c = poly_NewContour (v)) == NULL)
147 return NULL;
148 v[0] = pin->X + in - d;
149 poly_InclVertex (c->head.prev, poly_CreateNode (v));
150 v[0] = pin->X + out - d;
151 v[1] = pin->Y + out;
152 poly_InclVertex (c->head.prev, poly_CreateNode (v));
153 v[0] = pin->X - out + d;
154 poly_InclVertex (c->head.prev, poly_CreateNode (v));
155 p = ContourToPoly (c);
156 /* right */
157 v[0] = pin->X + in;
158 v[1] = pin->Y + in - d;
159 if ((c = poly_NewContour (v)) == NULL)
160 return NULL;
161 v[1] = pin->Y - in + d;
162 poly_InclVertex (c->head.prev, poly_CreateNode (v));
163 v[0] = pin->X + out;
164 v[1] = pin->Y - out + d;
165 poly_InclVertex (c->head.prev, poly_CreateNode (v));
166 v[1] = pin->Y + out - d;
167 poly_InclVertex (c->head.prev, poly_CreateNode (v));
168 p2 = ContourToPoly (c);
169 p->f = p2;
170 p2->b = p;
171 /* left */
172 v[0] = pin->X - in;
173 v[1] = pin->Y - in + d;
174 if ((c = poly_NewContour (v)) == NULL)
175 return NULL;
176 v[1] = pin->Y + in - d;
177 poly_InclVertex (c->head.prev, poly_CreateNode (v));
178 v[0] = pin->X - out;
179 v[1] = pin->Y + out - d;
180 poly_InclVertex (c->head.prev, poly_CreateNode (v));
181 v[1] = pin->Y - out + d;
182 poly_InclVertex (c->head.prev, poly_CreateNode (v));
183 p2 = ContourToPoly (c);
184 p->f->f = p2;
185 p2->b = p->f;
186 /* bottom (actually top since +y is down) */
187 v[0] = pin->X + in - d;
188 v[1] = pin->Y - in;
189 if ((c = poly_NewContour (v)) == NULL)
190 return NULL;
191 v[0] = pin->X - in + d;
192 poly_InclVertex (c->head.prev, poly_CreateNode (v));
193 v[0] = pin->X - out + d;
194 v[1] = pin->Y - out;
195 poly_InclVertex (c->head.prev, poly_CreateNode (v));
196 v[0] = pin->X + out - d;
197 poly_InclVertex (c->head.prev, poly_CreateNode (v));
198 p2 = ContourToPoly (c);
199 p->f->f->f = p2;
200 p2->f = p;
201 p2->b = p->f->f;
202 p->b = p2;
203 return p;
204 case 4:
206 LineType l;
207 d = pin->Thickness / 2 - pcb->ThermScale * pin->Clearance;
208 out = pin->Thickness / 2 + pin->Clearance / 4;
209 in = pin->Clearance / 2;
210 /* top */
211 l.Point1.X = pin->X - d;
212 l.Point2.Y = l.Point1.Y = pin->Y + out;
213 l.Point2.X = pin->X + d;
214 p = LinePoly (&l, in);
215 /* right */
216 l.Point1.X = l.Point2.X = pin->X + out;
217 l.Point1.Y = pin->Y - d;
218 l.Point2.Y = pin->Y + d;
219 p2 = LinePoly (&l, in);
220 p->f = p2;
221 p2->b = p;
222 /* bottom */
223 l.Point1.X = pin->X - d;
224 l.Point2.Y = l.Point1.Y = pin->Y - out;
225 l.Point2.X = pin->X + d;
226 p2 = LinePoly (&l, in);
227 p->f->f = p2;
228 p2->b = p->f;
229 /* left */
230 l.Point1.X = l.Point2.X = pin->X - out;
231 l.Point1.Y = pin->Y - d;
232 l.Point2.Y = pin->Y + d;
233 p2 = LinePoly (&l, in);
234 p->f->f->f = p2;
235 p2->b = p->f->f;
236 p->b = p2;
237 p2->f = p;
238 return p;
240 default: /* style 2 and 5 */
241 d = 0.5 * pcb->ThermScale * pin->Clearance;
242 if (style == 5)
243 d += d;
244 out = (pin->Thickness + pin->Clearance) / 2;
245 in = pin->Thickness / 2;
246 /* topright */
247 v[0] = pin->X + in;
248 v[1] = pin->Y + in;
249 if ((c = poly_NewContour (v)) == NULL)
250 return NULL;
251 v[1] = pin->Y + d;
252 poly_InclVertex (c->head.prev, poly_CreateNode (v));
253 if (style == 2)
255 v[0] = pin->X + out;
256 poly_InclVertex (c->head.prev, poly_CreateNode (v));
258 else
259 frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
260 v[1] = pin->Y + in;
261 poly_InclVertex (c->head.prev, poly_CreateNode (v));
262 /* pivot 1/4 circle to next point */
263 frac_circle (c, pin->X + in, pin->Y + in, v, 4);
264 v[0] = pin->X + d;
265 poly_InclVertex (c->head.prev, poly_CreateNode (v));
266 if (style == 2)
268 poly_InclVertex (c->head.prev, poly_CreateNode (v));
269 v[1] = pin->Y + in;
270 poly_InclVertex (c->head.prev, poly_CreateNode (v));
272 else
273 frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
274 p = ContourToPoly (c);
275 /* bottom right */
276 v[0] = pin->X + in;
277 v[1] = pin->Y - d;
278 if ((c = poly_NewContour (v)) == NULL)
279 return NULL;
280 v[1] = pin->Y - in;
281 poly_InclVertex (c->head.prev, poly_CreateNode (v));
282 v[0] = pin->X + d;
283 poly_InclVertex (c->head.prev, poly_CreateNode (v));
284 if (style == 2)
286 v[1] = pin->Y - out;
287 poly_InclVertex (c->head.prev, poly_CreateNode (v));
289 else
290 frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
291 v[0] = pin->X + in;
292 poly_InclVertex (c->head.prev, poly_CreateNode (v));
293 /* pivot 1/4 circle to next point */
294 frac_circle (c, pin->X + in, pin->Y - in, v, 4);
295 v[1] = pin->Y - d;
296 poly_InclVertex (c->head.prev, poly_CreateNode (v));
297 if (style == 5)
298 frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
299 p2 = ContourToPoly (c);
300 p->f = p2;
301 p2->b = p;
302 /* bottom left */
303 v[0] = pin->X - d;
304 v[1] = pin->Y - in;
305 if ((c = poly_NewContour (v)) == NULL)
306 return NULL;
307 v[0] = pin->X - in;
308 poly_InclVertex (c->head.prev, poly_CreateNode (v));
309 v[1] = pin->Y - d;
310 poly_InclVertex (c->head.prev, poly_CreateNode (v));
311 if (style == 2)
313 v[0] = pin->X - out;
314 poly_InclVertex (c->head.prev, poly_CreateNode (v));
316 else
317 frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
318 v[1] = pin->Y - in;
319 poly_InclVertex (c->head.prev, poly_CreateNode (v));
320 /* pivot 1/4 circle to next point */
321 frac_circle (c, pin->X - in, pin->Y - in, v, 4);
322 v[0] = pin->X - d;
323 poly_InclVertex (c->head.prev, poly_CreateNode (v));
324 if (style == 5)
325 frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
326 p2 = ContourToPoly (c);
327 p->f->f = p2;
328 p2->b = p->f;
329 /* top left */
330 v[0] = pin->X - d;
331 v[1] = pin->Y + out;
332 if ((c = poly_NewContour (v)) == NULL)
333 return NULL;
334 v[0] = pin->X - in;
335 poly_InclVertex (c->head.prev, poly_CreateNode (v));
336 /* pivot 1/4 circle to next point (x-out, y+in) */
337 frac_circle (c, pin->X - in, pin->Y + in, v, 4);
338 v[1] = pin->Y + d;
339 poly_InclVertex (c->head.prev, poly_CreateNode (v));
340 if (style == 2)
342 v[0] = pin->X - in;
343 poly_InclVertex (c->head.prev, poly_CreateNode (v));
345 else
346 frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
347 v[1] = pin->Y + in;
348 poly_InclVertex (c->head.prev, poly_CreateNode (v));
349 v[0] = pin->X - d;
350 poly_InclVertex (c->head.prev, poly_CreateNode (v));
351 if (style == 5)
352 frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
353 p2 = ContourToPoly (c);
354 p->f->f->f = p2;
355 p2->f = p;
356 p2->b = p->f->f;
357 p->b = p2;
358 return p;
362 static POLYAREA *
363 oct_therm (PinTypePtr pin, Cardinal style)
365 POLYAREA *p, *p2, *m;
366 BDimension t = 0.5 * pcb->ThermScale * pin->Clearance;
367 BDimension w = pin->Thickness + pin->Clearance;
369 p = OctagonPoly (pin->X, pin->Y, w);
370 p2 = OctagonPoly (pin->X, pin->Y, pin->Thickness);
371 /* make full clearance ring */
372 poly_Boolean_free (p, p2, &m, PBO_SUB);
373 switch (style)
375 default:
376 case 1:
377 p = diag_line (pin->X, pin->Y, w, t, True);
378 poly_Boolean_free (m, p, &p2, PBO_SUB);
379 p = diag_line (pin->X, pin->Y, w, t, False);
380 poly_Boolean_free (p2, p, &m, PBO_SUB);
381 return m;
382 case 2:
383 p = RectPoly (pin->X - t, pin->X + t, pin->Y - w, pin->Y + w);
384 poly_Boolean_free (m, p, &p2, PBO_SUB);
385 p = RectPoly (pin->X - w, pin->X + w, pin->Y - t, pin->Y + t);
386 poly_Boolean_free (p2, p, &m, PBO_SUB);
387 return m;
388 /* fix me add thermal style 4 */
389 case 5:
391 BDimension t = pin->Thickness / 2;
392 POLYAREA *q;
393 /* cheat by using the square therm's rounded parts */
394 p = square_therm (pin, style);
395 q = RectPoly (pin->X - t, pin->X + t, pin->Y - t, pin->Y + t);
396 poly_Boolean_free (p, q, &p2, PBO_UNITE);
397 poly_Boolean_free (m, p2, &p, PBO_ISECT);
398 return p;
403 /* ThermPoly returns a POLYAREA having all of the clearance that when
404 * subtracted from the plane create the desired thermal fingers.
405 * Usually this is 4 disjoint regions.
408 POLYAREA *
409 ThermPoly (PCBTypePtr p, PinTypePtr pin, Cardinal laynum)
411 ArcType a;
412 POLYAREA *pa, *arc;
413 Cardinal style = GET_THERM (laynum, pin);
415 if (style == 3)
416 return NULL; /* solid connection no clearance */
417 pcb = p;
418 if (TEST_FLAG (SQUAREFLAG, pin))
419 return square_therm (pin, style);
420 if (TEST_FLAG (OCTAGONFLAG, pin))
421 return oct_therm (pin, style);
422 /* must be circular */
423 switch (style)
425 case 1:
426 case 2:
428 POLYAREA *m;
429 BDimension t = (pin->Thickness + pin->Clearance) / 2;
430 BDimension w = 0.5 * pcb->ThermScale * pin->Clearance;
431 pa = CirclePoly (pin->X, pin->Y, t);
432 arc = CirclePoly (pin->X, pin->Y, pin->Thickness / 2);
433 /* create a thin ring */
434 poly_Boolean_free (pa, arc, &m, PBO_SUB);
435 /* fix me needs error checking */
436 if (style == 2)
438 pa = RectPoly (pin->X - t, pin->X + t, pin->Y - w, pin->Y + w);
439 poly_Boolean_free (m, pa, &arc, PBO_SUB);
440 pa = RectPoly (pin->X - w, pin->X + w, pin->Y - t, pin->Y + t);
442 else
444 pa = diag_line (pin->X, pin->Y, t, w, True);
445 poly_Boolean_free (m, pa, &arc, PBO_SUB);
446 pa = diag_line (pin->X, pin->Y, t, w, False);
448 poly_Boolean_free (arc, pa, &m, PBO_SUB);
449 return m;
453 default:
454 a.X = pin->X;
455 a.Y = pin->Y;
456 a.Height = a.Width = pin->Thickness / 2 + pin->Clearance / 4;
457 a.Thickness = 1;
458 a.Clearance = pin->Clearance / 2;
459 a.Flags = NoFlags ();
460 a.Delta =
461 90 -
462 (a.Clearance * (1. + 2. * pcb->ThermScale) * 180) / (M_PI * a.Width);
463 a.StartAngle = 90 - a.Delta / 2 + (style == 4 ? 0 : 45);
464 pa = ArcPoly (&a, a.Clearance);
465 if (!pa)
466 return NULL;
467 a.StartAngle += 90;
468 arc = ArcPoly (&a, a.Clearance);
469 if (!arc)
470 return NULL;
471 pa->f = arc;
472 arc->b = pa;
473 a.StartAngle += 90;
474 arc = ArcPoly (&a, a.Clearance);
475 if (!arc)
476 return NULL;
477 pa->f->f = arc;
478 arc->b = pa->f;
479 a.StartAngle += 90;
480 arc = ArcPoly (&a, a.Clearance);
481 if (!arc)
482 return NULL;
483 pa->b = arc;
484 pa->f->f->f = arc;
485 arc->b = pa->f->f;
486 arc->f = pa;
487 pa->b = arc;
488 return pa;