4 * \brief Negative thermal finger polygons.
6 * Thermals are normal lines on the layout
8 * The only thing unique about them is that they have the USETHERMALFLAG
9 * set so that they can be identified as thermals.
11 * It is handy for pcb to automatically make adjustments to the thermals
12 * when the user performs certain operations, and the functions in
13 * thermal.h help implement that.
15 * \author This file, thermal.c was written by and is
16 * (C) Copyright 2006, harry eaton
20 * <h1><b>Copyright.</b></h1>\n
22 * PCB, interactive printed circuit board design
24 * Copyright (C) 1994,1995,1996,2004,2006 Thomas Nau
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 2 of the License, or
29 * (at your option) any later version.
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public License
37 * along with this program; if not, write to the Free Software
38 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
40 * Contact addresses for paper mail and Email:
42 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
44 * Thomas.Nau@rz.uni-ulm.de
60 #include <sys/param.h>
62 #include <sys/types.h>
84 #ifdef HAVE_LIBDMALLOC
99 diag_line (Coord X
, Coord Y
, Coord l
, Coord w
, bool rt
)
103 Coord x1
, x2
, y1
, y2
;
107 x1
= (l
- w
) * M_SQRT1_2
;
108 x2
= (l
+ w
) * M_SQRT1_2
;
114 x2
= -(l
- w
) * M_SQRT1_2
;
115 x1
= -(l
+ w
) * M_SQRT1_2
;
122 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
126 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
129 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
132 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
133 return ContourToPoly (c
);
137 M_Poly_prepend (POLYAREA
*a
, POLYAREA
*b
)
154 square_therm (PinType
*pin
, Cardinal style
)
164 d
= pcb
->ThermScale
* pin
->Clearance
* M_SQRT1_2
;
165 out
= (pin
->Thickness
+ pin
->Clearance
) / 2;
166 in
= pin
->Thickness
/ 2;
167 /* top (actually bottom since +y is down) */
168 v
[0] = pin
->X
- in
+ d
;
170 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
172 v
[0] = pin
->X
+ in
- d
;
173 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
174 v
[0] = pin
->X
+ out
- d
;
176 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
177 v
[0] = pin
->X
- out
+ d
;
178 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
179 p
= ContourToPoly (c
);
182 v
[1] = pin
->Y
+ in
- d
;
183 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
185 v
[1] = pin
->Y
- in
+ d
;
186 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
188 v
[1] = pin
->Y
- out
+ d
;
189 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
190 v
[1] = pin
->Y
+ out
- d
;
191 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
192 p
= M_Poly_prepend (p
, ContourToPoly (c
));
195 v
[1] = pin
->Y
- in
+ d
;
196 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
198 v
[1] = pin
->Y
+ in
- d
;
199 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
201 v
[1] = pin
->Y
+ out
- d
;
202 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
203 v
[1] = pin
->Y
- out
+ d
;
204 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
205 p
= M_Poly_prepend (p
, ContourToPoly (c
));
206 /* bottom (actually top since +y is down) */
207 v
[0] = pin
->X
+ in
- d
;
209 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
211 v
[0] = pin
->X
- in
+ d
;
212 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
213 v
[0] = pin
->X
- out
+ d
;
215 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
216 v
[0] = pin
->X
+ out
- d
;
217 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
218 p
= M_Poly_prepend (p
, ContourToPoly (c
));
223 l
.Flags
= NoFlags ();
224 d
= pin
->Thickness
/ 2 - pcb
->ThermScale
* pin
->Clearance
;
225 out
= pin
->Thickness
/ 2 + pin
->Clearance
/ 4;
226 in
= pin
->Clearance
/ 2;
228 l
.Point1
.X
= pin
->X
- d
;
229 l
.Point2
.Y
= l
.Point1
.Y
= pin
->Y
+ out
;
230 l
.Point2
.X
= pin
->X
+ d
;
231 p
= LinePoly (&l
, in
, NULL
);
233 l
.Point1
.X
= l
.Point2
.X
= pin
->X
+ out
;
234 l
.Point1
.Y
= pin
->Y
- d
;
235 l
.Point2
.Y
= pin
->Y
+ d
;
236 p
= M_Poly_prepend (p
, LinePoly (&l
, in
, NULL
));
238 l
.Point1
.X
= pin
->X
- d
;
239 l
.Point2
.Y
= l
.Point1
.Y
= pin
->Y
- out
;
240 l
.Point2
.X
= pin
->X
+ d
;
241 p
= M_Poly_prepend (p
, LinePoly (&l
, in
, NULL
));
243 l
.Point1
.X
= l
.Point2
.X
= pin
->X
- out
;
244 l
.Point1
.Y
= pin
->Y
- d
;
245 l
.Point2
.Y
= pin
->Y
+ d
;
246 p
= M_Poly_prepend (p
, LinePoly (&l
, in
, NULL
));
249 default: /* style 2 and 5 */
250 d
= 0.5 * pcb
->ThermScale
* pin
->Clearance
;
253 out
= (pin
->Thickness
+ pin
->Clearance
) / 2;
254 in
= pin
->Thickness
/ 2;
258 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
261 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
265 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
269 frac_circle2 (c
, v
[0] + pin
->Clearance
/ 4, v
[1], v
, 2);
272 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
275 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
276 /* pivot 1/4 circle to next point */
277 frac_circle2 (c
, pin
->X
+ in
, pin
->Y
+ in
, v
, 4);
280 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
283 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
286 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
288 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
292 frac_circle2 (c
, v
[0], v
[1] - pin
->Clearance
/ 4, v
, 2);
295 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
297 p
= ContourToPoly (c
);
301 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
304 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
306 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
310 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
314 frac_circle2 (c
, v
[0], v
[1] - pin
->Clearance
/ 4, v
, 2);
317 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
320 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
321 /* pivot 1/4 circle to next point */
322 frac_circle2 (c
, pin
->X
+ in
, pin
->Y
- in
, v
, 4);
325 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
327 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
330 frac_circle2 (c
, v
[0] - pin
->Clearance
/ 4, v
[1], v
, 2);
333 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
335 p
= M_Poly_prepend (p
, ContourToPoly (c
));
339 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
342 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
344 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
348 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
352 frac_circle2 (c
, v
[0] - pin
->Clearance
/ 4, v
[1], v
, 2);
355 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
358 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
359 /* pivot 1/4 circle to next point */
360 frac_circle2 (c
, pin
->X
- in
, pin
->Y
- in
, v
, 4);
363 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
365 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
368 frac_circle2 (c
, v
[0], v
[1] + pin
->Clearance
/ 4, v
, 2);
371 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
373 p
= M_Poly_prepend (p
, ContourToPoly (c
));
377 if ((c
= poly_NewContour (poly_CreateNode (v
))) == NULL
)
380 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
381 /* pivot 1/4 circle to next point (x-out, y+in) */
382 frac_circle2 (c
, pin
->X
- in
, pin
->Y
+ in
, v
, 4);
385 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
387 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
391 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
395 frac_circle2 (c
, v
[0] + pin
->Clearance
/ 4, v
[1], v
, 2);
398 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
401 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
403 poly_InclVertex (c
->head
.prev
, poly_CreateNode (v
));
405 frac_circle2 (c
, v
[0], v
[1] + pin
->Clearance
/ 4, v
, 2);
406 p
= M_Poly_prepend (p
, ContourToPoly (c
));
412 oct_therm (PinType
*pin
, Cardinal style
)
414 POLYAREA
*p
, *p2
, *m
;
415 Coord t
= 0.5 * pcb
->ThermScale
* pin
->Clearance
;
416 Coord w
= pin
->Thickness
+ pin
->Clearance
;
418 p
= OctagonPoly (pin
->X
, pin
->Y
, w
);
419 p2
= OctagonPoly (pin
->X
, pin
->Y
, pin
->Thickness
);
420 /* make full clearance ring */
421 poly_Boolean_free (p
, p2
, &m
, PBO_SUB
);
426 p
= diag_line (pin
->X
, pin
->Y
, w
, t
, true);
427 poly_Boolean_free (m
, p
, &p2
, PBO_SUB
);
428 p
= diag_line (pin
->X
, pin
->Y
, w
, t
, false);
429 poly_Boolean_free (p2
, p
, &m
, PBO_SUB
);
432 p
= RectPoly (pin
->X
- t
, pin
->X
+ t
, pin
->Y
- w
, pin
->Y
+ w
);
433 poly_Boolean_free (m
, p
, &p2
, PBO_SUB
);
434 p
= RectPoly (pin
->X
- w
, pin
->X
+ w
, pin
->Y
- t
, pin
->Y
+ t
);
435 poly_Boolean_free (p2
, p
, &m
, PBO_SUB
);
437 /* fix me add thermal style 4 */
440 Coord t
= pin
->Thickness
/ 2;
442 /* cheat by using the square therm's rounded parts */
443 p
= square_therm (pin
, style
);
444 q
= RectPoly (pin
->X
- t
, pin
->X
+ t
, pin
->Y
- t
, pin
->Y
+ t
);
445 poly_Boolean_free (p
, q
, &p2
, PBO_UNITE
);
446 poly_Boolean_free (m
, p2
, &p
, PBO_ISECT
);
455 * \return ThermPoly returns a POLYAREA having all of the clearance that
456 * when subtracted from the plane create the desired thermal fingers.
457 * Usually this is 4 disjoint regions.
459 /* XXX: Could check for polygon with hole as output... indicating the geometry isolated the pin? */
461 ThermPoly (PCBType
*p
, PinType
*pin
, Cardinal laynum
)
465 Cardinal style
= GET_THERM (laynum
, pin
);
468 return NULL
; /* solid connection no clearance */
470 if (TEST_FLAG (SQUAREFLAG
, pin
))
471 return square_therm (pin
, style
);
472 if (TEST_FLAG (OCTAGONFLAG
, pin
))
473 return oct_therm (pin
, style
);
474 /* must be circular */
481 Coord t
= (pin
->Thickness
+ pin
->Clearance
) / 2;
482 Coord w
= 0.5 * pcb
->ThermScale
* pin
->Clearance
;
483 pa
= CirclePoly (pin
->X
, pin
->Y
, t
, NULL
);
484 arc
= CirclePoly (pin
->X
, pin
->Y
, pin
->Thickness
/ 2, NULL
);
485 /* create a thin ring */
486 poly_Boolean_free (pa
, arc
, &m
, PBO_SUB
);
487 /* fix me needs error checking */
490 /* t is the theoretically required length, but we use twice that
491 * to avoid descritisation errors in our circle approximation.
493 pa
= RectPoly (pin
->X
- t
* 2, pin
->X
+ t
* 2, pin
->Y
- w
, pin
->Y
+ w
);
494 poly_Boolean_free (m
, pa
, &arc
, PBO_SUB
);
495 pa
= RectPoly (pin
->X
- w
, pin
->X
+ w
, pin
->Y
- t
* 2, pin
->Y
+ t
* 2);
499 /* t is the theoretically required length, but we use twice that
500 * to avoid descritisation errors in our circle approximation.
502 pa
= diag_line (pin
->X
, pin
->Y
, t
* 2, w
, true);
503 poly_Boolean_free (m
, pa
, &arc
, PBO_SUB
);
504 pa
= diag_line (pin
->X
, pin
->Y
, t
* 2, w
, false);
506 poly_Boolean_free (arc
, pa
, &m
, PBO_SUB
);
514 a
.Height
= a
.Width
= pin
->Thickness
/ 2 + pin
->Clearance
/ 4;
516 a
.Clearance
= pin
->Clearance
/ 2;
517 a
.Flags
= NoFlags ();
520 (a
.Clearance
* (1. + 2. * pcb
->ThermScale
) * 180) / (M_PI
* a
.Width
);
521 a
.StartAngle
= 90 - a
.Delta
/ 2 + (style
== 4 ? 0 : 45);
522 pa
= ArcPoly (&a
, a
.Clearance
, NULL
);
526 arc
= ArcPoly (&a
, a
.Clearance
, NULL
);
532 arc
= ArcPoly (&a
, a
.Clearance
, NULL
);
538 arc
= ArcPoly (&a
, a
.Clearance
, NULL
);