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