hid/gtk (GL): I think the polygon renderer works in mask mode now
[geda-pcb/pcjc2.git] / src / thermal.c
blob083bf5e0399f367fc37780ddd99e529a41706b11
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 <memory.h>
45 #include <ctype.h>
46 #include <signal.h>
47 #include <sys/param.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <math.h>
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #ifdef HAVE_PWD_H
55 #include <pwd.h>
56 #endif
58 #include "global.h"
60 #include "create.h"
61 #include "data.h"
62 #include "draw.h"
63 #include "error.h"
64 #include "misc.h"
65 #include "move.h"
66 #include "polygon.h"
67 #include "rtree.h"
68 #include "thermal.h"
69 #include "undo.h"
71 #ifdef HAVE_LIBDMALLOC
72 #include <dmalloc.h>
73 #endif
75 static PCBType *pcb;
77 struct cent
79 Coord x, y;
80 Coord s, c;
81 char style;
82 POLYAREA *p;
85 static POLYAREA *
86 diag_line (Coord X, Coord Y, Coord l, Coord w, bool rt)
88 PLINE *c;
89 Vector v;
90 Coord x1, x2, y1, y2;
92 if (rt)
94 x1 = (l - w) * M_SQRT1_2;
95 x2 = (l + w) * M_SQRT1_2;
96 y1 = x1;
97 y2 = x2;
99 else
101 x2 = -(l - w) * M_SQRT1_2;
102 x1 = -(l + w) * M_SQRT1_2;
103 y1 = -x1;
104 y2 = -x2;
107 v[0] = X + x1;
108 v[1] = Y + y2;
109 if ((c = poly_NewContour (v)) == NULL)
110 return NULL;
111 v[0] = X - x2;
112 v[1] = Y - y1;
113 poly_InclVertex (c->head.prev, poly_CreateNode (v));
114 v[0] = X - x1;
115 v[1] = Y - y2;
116 poly_InclVertex (c->head.prev, poly_CreateNode (v));
117 v[0] = X + x2;
118 v[1] = Y + y1;
119 poly_InclVertex (c->head.prev, poly_CreateNode (v));
120 return ContourToPoly (c);
123 static POLYAREA *
124 square_therm (PinType *pin, Cardinal style)
126 POLYAREA *p, *p2;
127 PLINE *c;
128 Vector v;
129 Coord d, in, out;
131 switch (style)
133 case 1:
134 d = pcb->ThermScale * pin->Clearance * M_SQRT1_2;
135 out = (pin->Thickness + pin->Clearance) / 2;
136 in = pin->Thickness / 2;
137 /* top (actually bottom since +y is down) */
138 v[0] = pin->X - in + d;
139 v[1] = pin->Y + in;
140 if ((c = poly_NewContour (v)) == NULL)
141 return NULL;
142 v[0] = pin->X + in - d;
143 poly_InclVertex (c->head.prev, poly_CreateNode (v));
144 v[0] = pin->X + out - d;
145 v[1] = pin->Y + out;
146 poly_InclVertex (c->head.prev, poly_CreateNode (v));
147 v[0] = pin->X - out + d;
148 poly_InclVertex (c->head.prev, poly_CreateNode (v));
149 p = ContourToPoly (c);
150 /* right */
151 v[0] = pin->X + in;
152 v[1] = pin->Y + in - d;
153 if ((c = poly_NewContour (v)) == NULL)
154 return NULL;
155 v[1] = pin->Y - in + d;
156 poly_InclVertex (c->head.prev, poly_CreateNode (v));
157 v[0] = pin->X + out;
158 v[1] = pin->Y - out + d;
159 poly_InclVertex (c->head.prev, poly_CreateNode (v));
160 v[1] = pin->Y + out - d;
161 poly_InclVertex (c->head.prev, poly_CreateNode (v));
162 p2 = ContourToPoly (c);
163 p->f = p2;
164 p2->b = p;
165 /* left */
166 v[0] = pin->X - in;
167 v[1] = pin->Y - in + d;
168 if ((c = poly_NewContour (v)) == NULL)
169 return NULL;
170 v[1] = pin->Y + in - d;
171 poly_InclVertex (c->head.prev, poly_CreateNode (v));
172 v[0] = pin->X - out;
173 v[1] = pin->Y + out - d;
174 poly_InclVertex (c->head.prev, poly_CreateNode (v));
175 v[1] = pin->Y - out + d;
176 poly_InclVertex (c->head.prev, poly_CreateNode (v));
177 p2 = ContourToPoly (c);
178 p->f->f = p2;
179 p2->b = p->f;
180 /* bottom (actually top since +y is down) */
181 v[0] = pin->X + in - d;
182 v[1] = pin->Y - in;
183 if ((c = poly_NewContour (v)) == NULL)
184 return NULL;
185 v[0] = pin->X - in + d;
186 poly_InclVertex (c->head.prev, poly_CreateNode (v));
187 v[0] = pin->X - out + d;
188 v[1] = pin->Y - out;
189 poly_InclVertex (c->head.prev, poly_CreateNode (v));
190 v[0] = pin->X + out - d;
191 poly_InclVertex (c->head.prev, poly_CreateNode (v));
192 p2 = ContourToPoly (c);
193 p->f->f->f = p2;
194 p2->f = p;
195 p2->b = p->f->f;
196 p->b = p2;
197 return p;
198 case 4:
200 LineType l;
201 l.Flags = NoFlags ();
202 d = pin->Thickness / 2 - pcb->ThermScale * pin->Clearance;
203 out = pin->Thickness / 2 + pin->Clearance / 4;
204 in = pin->Clearance / 2;
205 /* top */
206 l.Point1.X = pin->X - d;
207 l.Point2.Y = l.Point1.Y = pin->Y + out;
208 l.Point2.X = pin->X + d;
209 p = LinePoly (&l, in);
210 /* right */
211 l.Point1.X = l.Point2.X = pin->X + out;
212 l.Point1.Y = pin->Y - d;
213 l.Point2.Y = pin->Y + d;
214 p2 = LinePoly (&l, in);
215 p->f = p2;
216 p2->b = p;
217 /* bottom */
218 l.Point1.X = pin->X - d;
219 l.Point2.Y = l.Point1.Y = pin->Y - out;
220 l.Point2.X = pin->X + d;
221 p2 = LinePoly (&l, in);
222 p->f->f = p2;
223 p2->b = p->f;
224 /* left */
225 l.Point1.X = l.Point2.X = pin->X - out;
226 l.Point1.Y = pin->Y - d;
227 l.Point2.Y = pin->Y + d;
228 p2 = LinePoly (&l, in);
229 p->f->f->f = p2;
230 p2->b = p->f->f;
231 p->b = p2;
232 p2->f = p;
233 return p;
235 default: /* style 2 and 5 */
236 d = 0.5 * pcb->ThermScale * pin->Clearance;
237 if (style == 5)
238 d += d;
239 out = (pin->Thickness + pin->Clearance) / 2;
240 in = pin->Thickness / 2;
241 /* topright */
242 v[0] = pin->X + in;
243 v[1] = pin->Y + in;
244 if ((c = poly_NewContour (v)) == NULL)
245 return NULL;
246 v[1] = pin->Y + d;
247 poly_InclVertex (c->head.prev, poly_CreateNode (v));
248 if (style == 2)
250 v[0] = pin->X + out;
251 poly_InclVertex (c->head.prev, poly_CreateNode (v));
253 else
254 frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
255 v[1] = pin->Y + in;
256 poly_InclVertex (c->head.prev, poly_CreateNode (v));
257 /* pivot 1/4 circle to next point */
258 frac_circle (c, pin->X + in, pin->Y + in, v, 4);
259 v[0] = pin->X + d;
260 poly_InclVertex (c->head.prev, poly_CreateNode (v));
261 if (style == 2)
263 poly_InclVertex (c->head.prev, poly_CreateNode (v));
264 v[1] = pin->Y + in;
265 poly_InclVertex (c->head.prev, poly_CreateNode (v));
267 else
268 frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
269 p = ContourToPoly (c);
270 /* bottom right */
271 v[0] = pin->X + in;
272 v[1] = pin->Y - d;
273 if ((c = poly_NewContour (v)) == NULL)
274 return NULL;
275 v[1] = pin->Y - in;
276 poly_InclVertex (c->head.prev, poly_CreateNode (v));
277 v[0] = pin->X + d;
278 poly_InclVertex (c->head.prev, poly_CreateNode (v));
279 if (style == 2)
281 v[1] = pin->Y - out;
282 poly_InclVertex (c->head.prev, poly_CreateNode (v));
284 else
285 frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
286 v[0] = pin->X + in;
287 poly_InclVertex (c->head.prev, poly_CreateNode (v));
288 /* pivot 1/4 circle to next point */
289 frac_circle (c, pin->X + in, pin->Y - in, v, 4);
290 v[1] = pin->Y - d;
291 poly_InclVertex (c->head.prev, poly_CreateNode (v));
292 if (style == 5)
293 frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
294 p2 = ContourToPoly (c);
295 p->f = p2;
296 p2->b = p;
297 /* bottom left */
298 v[0] = pin->X - d;
299 v[1] = pin->Y - in;
300 if ((c = poly_NewContour (v)) == NULL)
301 return NULL;
302 v[0] = pin->X - in;
303 poly_InclVertex (c->head.prev, poly_CreateNode (v));
304 v[1] = pin->Y - d;
305 poly_InclVertex (c->head.prev, poly_CreateNode (v));
306 if (style == 2)
308 v[0] = pin->X - out;
309 poly_InclVertex (c->head.prev, poly_CreateNode (v));
311 else
312 frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
313 v[1] = pin->Y - in;
314 poly_InclVertex (c->head.prev, poly_CreateNode (v));
315 /* pivot 1/4 circle to next point */
316 frac_circle (c, pin->X - in, pin->Y - in, v, 4);
317 v[0] = pin->X - d;
318 poly_InclVertex (c->head.prev, poly_CreateNode (v));
319 if (style == 5)
320 frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
321 p2 = ContourToPoly (c);
322 p->f->f = p2;
323 p2->b = p->f;
324 /* top left */
325 v[0] = pin->X - d;
326 v[1] = pin->Y + out;
327 if ((c = poly_NewContour (v)) == NULL)
328 return NULL;
329 v[0] = pin->X - in;
330 poly_InclVertex (c->head.prev, poly_CreateNode (v));
331 /* pivot 1/4 circle to next point (x-out, y+in) */
332 frac_circle (c, pin->X - in, pin->Y + in, v, 4);
333 v[1] = pin->Y + d;
334 poly_InclVertex (c->head.prev, poly_CreateNode (v));
335 if (style == 2)
337 v[0] = pin->X - in;
338 poly_InclVertex (c->head.prev, poly_CreateNode (v));
340 else
341 frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
342 v[1] = pin->Y + in;
343 poly_InclVertex (c->head.prev, poly_CreateNode (v));
344 v[0] = pin->X - d;
345 poly_InclVertex (c->head.prev, poly_CreateNode (v));
346 if (style == 5)
347 frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
348 p2 = ContourToPoly (c);
349 p->f->f->f = p2;
350 p2->f = p;
351 p2->b = p->f->f;
352 p->b = p2;
353 return p;
357 static POLYAREA *
358 oct_therm (PinType *pin, Cardinal style)
360 POLYAREA *p, *p2, *m;
361 Coord t = 0.5 * pcb->ThermScale * pin->Clearance;
362 Coord w = pin->Thickness + pin->Clearance;
364 p = OctagonPoly (pin->X, pin->Y, w);
365 p2 = OctagonPoly (pin->X, pin->Y, pin->Thickness);
366 /* make full clearance ring */
367 poly_Boolean_free (p, p2, &m, PBO_SUB);
368 switch (style)
370 default:
371 case 1:
372 p = diag_line (pin->X, pin->Y, w, t, true);
373 poly_Boolean_free (m, p, &p2, PBO_SUB);
374 p = diag_line (pin->X, pin->Y, w, t, false);
375 poly_Boolean_free (p2, p, &m, PBO_SUB);
376 return m;
377 case 2:
378 p = RectPoly (pin->X - t, pin->X + t, pin->Y - w, pin->Y + w);
379 poly_Boolean_free (m, p, &p2, PBO_SUB);
380 p = RectPoly (pin->X - w, pin->X + w, pin->Y - t, pin->Y + t);
381 poly_Boolean_free (p2, p, &m, PBO_SUB);
382 return m;
383 /* fix me add thermal style 4 */
384 case 5:
386 Coord t = pin->Thickness / 2;
387 POLYAREA *q;
388 /* cheat by using the square therm's rounded parts */
389 p = square_therm (pin, style);
390 q = RectPoly (pin->X - t, pin->X + t, pin->Y - t, pin->Y + t);
391 poly_Boolean_free (p, q, &p2, PBO_UNITE);
392 poly_Boolean_free (m, p2, &p, PBO_ISECT);
393 return p;
398 /* ThermPoly returns a POLYAREA having all of the clearance that when
399 * subtracted from the plane create the desired thermal fingers.
400 * Usually this is 4 disjoint regions.
403 POLYAREA *
404 ThermPoly (PCBType *p, PinType *pin, Cardinal laynum)
406 ArcType a;
407 POLYAREA *pa, *arc;
408 Cardinal style = GET_THERM (laynum, pin);
410 if (style == 3)
411 return NULL; /* solid connection no clearance */
412 pcb = p;
413 if (TEST_FLAG (SQUAREFLAG, pin))
414 return square_therm (pin, style);
415 if (TEST_FLAG (OCTAGONFLAG, pin))
416 return oct_therm (pin, style);
417 /* must be circular */
418 switch (style)
420 case 1:
421 case 2:
423 POLYAREA *m;
424 Coord t = (pin->Thickness + pin->Clearance) / 2;
425 Coord w = 0.5 * pcb->ThermScale * pin->Clearance;
426 pa = CirclePoly (pin->X, pin->Y, t);
427 arc = CirclePoly (pin->X, pin->Y, pin->Thickness / 2);
428 /* create a thin ring */
429 poly_Boolean_free (pa, arc, &m, PBO_SUB);
430 /* fix me needs error checking */
431 if (style == 2)
433 /* t is the theoretically required length, but we use twice that
434 * to avoid descritisation errors in our circle approximation.
436 pa = RectPoly (pin->X - t * 2, pin->X + t * 2, pin->Y - w, pin->Y + w);
437 poly_Boolean_free (m, pa, &arc, PBO_SUB);
438 pa = RectPoly (pin->X - w, pin->X + w, pin->Y - t * 2, pin->Y + t * 2);
440 else
442 /* t is the theoretically required length, but we use twice that
443 * to avoid descritisation errors in our circle approximation.
445 pa = diag_line (pin->X, pin->Y, t * 2, w, true);
446 poly_Boolean_free (m, pa, &arc, PBO_SUB);
447 pa = diag_line (pin->X, pin->Y, t * 2, w, false);
449 poly_Boolean_free (arc, pa, &m, PBO_SUB);
450 return m;
454 default:
455 a.X = pin->X;
456 a.Y = pin->Y;
457 a.Height = a.Width = pin->Thickness / 2 + pin->Clearance / 4;
458 a.Thickness = 1;
459 a.Clearance = pin->Clearance / 2;
460 a.Flags = NoFlags ();
461 a.Delta =
462 90 -
463 (a.Clearance * (1. + 2. * pcb->ThermScale) * 180) / (M_PI * a.Width);
464 a.StartAngle = 90 - a.Delta / 2 + (style == 4 ? 0 : 45);
465 pa = ArcPoly (&a, a.Clearance);
466 if (!pa)
467 return NULL;
468 a.StartAngle += 90;
469 arc = ArcPoly (&a, a.Clearance);
470 if (!arc)
471 return NULL;
472 pa->f = arc;
473 arc->b = pa;
474 a.StartAngle += 90;
475 arc = ArcPoly (&a, a.Clearance);
476 if (!arc)
477 return NULL;
478 pa->f->f = arc;
479 arc->b = pa->f;
480 a.StartAngle += 90;
481 arc = ArcPoly (&a, a.Clearance);
482 if (!arc)
483 return NULL;
484 pa->b = arc;
485 pa->f->f->f = arc;
486 arc->b = pa->f->f;
487 arc->f = pa;
488 pa->b = arc;
489 return pa;