pcb 4.1.1
An interactive printed circuit board layout editor.

thermal.c

Go to the documentation of this file.
00001 
00047 #ifdef HAVE_CONFIG_H
00048 #include "config.h"
00049 #endif
00050 
00051 #include <stdlib.h>
00052 #include <stdarg.h>
00053 #ifdef HAVE_STRING_H
00054 #include <string.h>
00055 #endif
00056 #include <assert.h>
00057 #include <memory.h>
00058 #include <ctype.h>
00059 #include <signal.h>
00060 #include <sys/param.h>
00061 #include <sys/stat.h>
00062 #include <sys/types.h>
00063 #include <math.h>
00064 #ifdef HAVE_UNISTD_H
00065 #include <unistd.h>
00066 #endif
00067 #ifdef HAVE_PWD_H
00068 #include <pwd.h>
00069 #endif
00070 
00071 #include "global.h"
00072 
00073 #include "create.h"
00074 #include "data.h"
00075 #include "draw.h"
00076 #include "error.h"
00077 #include "misc.h"
00078 #include "move.h"
00079 #include "polygon.h"
00080 #include "rtree.h"
00081 #include "thermal.h"
00082 #include "undo.h"
00083 
00084 #ifdef HAVE_LIBDMALLOC
00085 #include <dmalloc.h>
00086 #endif
00087 
00088 static PCBType *pcb;
00089 
00090 struct cent
00091 {
00092   Coord x, y;
00093   Coord s, c;
00094   char style;
00095   POLYAREA *p;
00096 };
00097 
00098 static POLYAREA *
00099 diag_line (Coord X, Coord Y, Coord l, Coord w, bool rt)
00100 {
00101   PLINE *c;
00102   Vector v;
00103   Coord x1, x2, y1, y2;
00104 
00105   if (rt)
00106     {
00107       x1 = (l - w) * M_SQRT1_2;
00108       x2 = (l + w) * M_SQRT1_2;
00109       y1 = x1;
00110       y2 = x2;
00111     }
00112   else
00113     {
00114       x2 = -(l - w) * M_SQRT1_2;
00115       x1 = -(l + w) * M_SQRT1_2;
00116       y1 = -x1;
00117       y2 = -x2;
00118     }
00119 
00120   v[0] = X + x1;
00121   v[1] = Y + y2;
00122   if ((c = poly_NewContour (v)) == NULL)
00123     return NULL;
00124   v[0] = X - x2;
00125   v[1] = Y - y1;
00126   poly_InclVertex (c->head.prev, poly_CreateNode (v));
00127   v[0] = X - x1;
00128   v[1] = Y - y2;
00129   poly_InclVertex (c->head.prev, poly_CreateNode (v));
00130   v[0] = X + x2;
00131   v[1] = Y + y1;
00132   poly_InclVertex (c->head.prev, poly_CreateNode (v));
00133   return ContourToPoly (c);
00134 }
00135 
00136 static POLYAREA *
00137 square_therm (PinType *pin, Cardinal style)
00138 {
00139   POLYAREA *p, *p2;
00140   PLINE *c;
00141   Vector v;
00142   Coord d, in, out;
00143 
00144   switch (style)
00145     {
00146     case 1:
00147       d = pcb->ThermScale * pin->Clearance * M_SQRT1_2;
00148       out = (pin->Thickness + pin->Clearance) / 2;
00149       in = pin->Thickness / 2;
00150       /* top (actually bottom since +y is down) */
00151       v[0] = pin->X - in + d;
00152       v[1] = pin->Y + in;
00153       if ((c = poly_NewContour (v)) == NULL)
00154         return NULL;
00155       v[0] = pin->X + in - d;
00156       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00157       v[0] = pin->X + out - d;
00158       v[1] = pin->Y + out;
00159       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00160       v[0] = pin->X - out + d;
00161       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00162       p = ContourToPoly (c);
00163       /* right */
00164       v[0] = pin->X + in;
00165       v[1] = pin->Y + in - d;
00166       if ((c = poly_NewContour (v)) == NULL)
00167         return NULL;
00168       v[1] = pin->Y - in + d;
00169       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00170       v[0] = pin->X + out;
00171       v[1] = pin->Y - out + d;
00172       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00173       v[1] = pin->Y + out - d;
00174       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00175       p2 = ContourToPoly (c);
00176       p->f = p2;
00177       p2->b = p;
00178       /* left */
00179       v[0] = pin->X - in;
00180       v[1] = pin->Y - in + d;
00181       if ((c = poly_NewContour (v)) == NULL)
00182         return NULL;
00183       v[1] = pin->Y + in - d;
00184       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00185       v[0] = pin->X - out;
00186       v[1] = pin->Y + out - d;
00187       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00188       v[1] = pin->Y - out + d;
00189       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00190       p2 = ContourToPoly (c);
00191       p->f->f = p2;
00192       p2->b = p->f;
00193       /* bottom (actually top since +y is down) */
00194       v[0] = pin->X + in - d;
00195       v[1] = pin->Y - in;
00196       if ((c = poly_NewContour (v)) == NULL)
00197         return NULL;
00198       v[0] = pin->X - in + d;
00199       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00200       v[0] = pin->X - out + d;
00201       v[1] = pin->Y - out;
00202       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00203       v[0] = pin->X + out - d;
00204       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00205       p2 = ContourToPoly (c);
00206       p->f->f->f = p2;
00207       p2->f = p;
00208       p2->b = p->f->f;
00209       p->b = p2;
00210       return p;
00211     case 4:
00212       {
00213         LineType l;
00214         l.Flags = NoFlags ();
00215         d = pin->Thickness / 2 - pcb->ThermScale * pin->Clearance;
00216         out = pin->Thickness / 2 + pin->Clearance / 4;
00217         in = pin->Clearance / 2;
00218         /* top */
00219         l.Point1.X = pin->X - d;
00220         l.Point2.Y = l.Point1.Y = pin->Y + out;
00221         l.Point2.X = pin->X + d;
00222         p = LinePoly (&l, in);
00223         /* right */
00224         l.Point1.X = l.Point2.X = pin->X + out;
00225         l.Point1.Y = pin->Y - d;
00226         l.Point2.Y = pin->Y + d;
00227         p2 = LinePoly (&l, in);
00228         p->f = p2;
00229         p2->b = p;
00230         /* bottom */
00231         l.Point1.X = pin->X - d;
00232         l.Point2.Y = l.Point1.Y = pin->Y - out;
00233         l.Point2.X = pin->X + d;
00234         p2 = LinePoly (&l, in);
00235         p->f->f = p2;
00236         p2->b = p->f;
00237         /* left */
00238         l.Point1.X = l.Point2.X = pin->X - out;
00239         l.Point1.Y = pin->Y - d;
00240         l.Point2.Y = pin->Y + d;
00241         p2 = LinePoly (&l, in);
00242         p->f->f->f = p2;
00243         p2->b = p->f->f;
00244         p->b = p2;
00245         p2->f = p;
00246         return p;
00247       }
00248     default:                   /* style 2 and 5 */
00249       d = 0.5 * pcb->ThermScale * pin->Clearance;
00250       if (style == 5)
00251         d += d;
00252       out = (pin->Thickness + pin->Clearance) / 2;
00253       in = pin->Thickness / 2;
00254       /* topright */
00255       v[0] = pin->X + in;
00256       v[1] = pin->Y + in;
00257       if ((c = poly_NewContour (v)) == NULL)
00258         return NULL;
00259       v[1] = pin->Y + d;
00260       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00261       if (style == 2)
00262         {
00263           v[0] = pin->X + out;
00264           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00265         }
00266       else
00267         frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
00268       v[1] = pin->Y + in;
00269       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00270       /* pivot 1/4 circle to next point */
00271       frac_circle (c, pin->X + in, pin->Y + in, v, 4);
00272       v[0] = pin->X + d;
00273       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00274       if (style == 2)
00275         {
00276           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00277           v[1] = pin->Y + in;
00278           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00279         }
00280       else
00281         frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
00282       p = ContourToPoly (c);
00283       /* bottom right */
00284       v[0] = pin->X + in;
00285       v[1] = pin->Y - d;
00286       if ((c = poly_NewContour (v)) == NULL)
00287         return NULL;
00288       v[1] = pin->Y - in;
00289       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00290       v[0] = pin->X + d;
00291       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00292       if (style == 2)
00293         {
00294           v[1] = pin->Y - out;
00295           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00296         }
00297       else
00298         frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2);
00299       v[0] = pin->X + in;
00300       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00301       /* pivot 1/4 circle to next point */
00302       frac_circle (c, pin->X + in, pin->Y - in, v, 4);
00303       v[1] = pin->Y - d;
00304       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00305       if (style == 5)
00306         frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
00307       p2 = ContourToPoly (c);
00308       p->f = p2;
00309       p2->b = p;
00310       /* bottom left */
00311       v[0] = pin->X - d;
00312       v[1] = pin->Y - in;
00313       if ((c = poly_NewContour (v)) == NULL)
00314         return NULL;
00315       v[0] = pin->X - in;
00316       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00317       v[1] = pin->Y - d;
00318       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00319       if (style == 2)
00320         {
00321           v[0] = pin->X - out;
00322           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00323         }
00324       else
00325         frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2);
00326       v[1] = pin->Y - in;
00327       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00328       /* pivot 1/4 circle to next point */
00329       frac_circle (c, pin->X - in, pin->Y - in, v, 4);
00330       v[0] = pin->X - d;
00331       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00332       if (style == 5)
00333         frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
00334       p2 = ContourToPoly (c);
00335       p->f->f = p2;
00336       p2->b = p->f;
00337       /* top left */
00338       v[0] = pin->X - d;
00339       v[1] = pin->Y + out;
00340       if ((c = poly_NewContour (v)) == NULL)
00341         return NULL;
00342       v[0] = pin->X - in;
00343       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00344       /* pivot 1/4 circle to next point (x-out, y+in) */
00345       frac_circle (c, pin->X - in, pin->Y + in, v, 4);
00346       v[1] = pin->Y + d;
00347       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00348       if (style == 2)
00349         {
00350           v[0] = pin->X - in;
00351           poly_InclVertex (c->head.prev, poly_CreateNode (v));
00352         }
00353       else
00354         frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2);
00355       v[1] = pin->Y + in;
00356       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00357       v[0] = pin->X - d;
00358       poly_InclVertex (c->head.prev, poly_CreateNode (v));
00359       if (style == 5)
00360         frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2);
00361       p2 = ContourToPoly (c);
00362       p->f->f->f = p2;
00363       p2->f = p;
00364       p2->b = p->f->f;
00365       p->b = p2;
00366       return p;
00367     }
00368 }
00369 
00370 static POLYAREA *
00371 oct_therm (PinType *pin, Cardinal style)
00372 {
00373   POLYAREA *p, *p2, *m;
00374   Coord t = 0.5 * pcb->ThermScale * pin->Clearance;
00375   Coord w = pin->Thickness + pin->Clearance;
00376 
00377   p = OctagonPoly (pin->X, pin->Y, w);
00378   p2 = OctagonPoly (pin->X, pin->Y, pin->Thickness);
00379   /* make full clearance ring */
00380   poly_Boolean_free (p, p2, &m, PBO_SUB);
00381   switch (style)
00382     {
00383     default:
00384     case 1:
00385       p = diag_line (pin->X, pin->Y, w, t, true);
00386       poly_Boolean_free (m, p, &p2, PBO_SUB);
00387       p = diag_line (pin->X, pin->Y, w, t, false);
00388       poly_Boolean_free (p2, p, &m, PBO_SUB);
00389       return m;
00390     case 2:
00391       p = RectPoly (pin->X - t, pin->X + t, pin->Y - w, pin->Y + w);
00392       poly_Boolean_free (m, p, &p2, PBO_SUB);
00393       p = RectPoly (pin->X - w, pin->X + w, pin->Y - t, pin->Y + t);
00394       poly_Boolean_free (p2, p, &m, PBO_SUB);
00395       return m;
00396       /* fix me add thermal style 4 */
00397     case 5:
00398       {
00399         Coord t = pin->Thickness / 2;
00400         POLYAREA *q;
00401         /* cheat by using the square therm's rounded parts */
00402         p = square_therm (pin, style);
00403         q = RectPoly (pin->X - t, pin->X + t, pin->Y - t, pin->Y + t);
00404         poly_Boolean_free (p, q, &p2, PBO_UNITE);
00405         poly_Boolean_free (m, p2, &p, PBO_ISECT);
00406         return p;
00407       }
00408     }
00409 }
00410 
00418 POLYAREA *
00419 ThermPoly (PCBType *p, PinType *pin, Cardinal laynum)
00420 {
00421   ArcType a;
00422   POLYAREA *pa, *arc;
00423   Cardinal style = GET_THERM (laynum, pin);
00424 
00425   if (style == 3)
00426     return NULL;                /* solid connection no clearance */
00427   pcb = p;
00428   if (TEST_FLAG (SQUAREFLAG, pin))
00429     return square_therm (pin, style);
00430   if (TEST_FLAG (OCTAGONFLAG, pin))
00431     return oct_therm (pin, style);
00432   /* must be circular */
00433   switch (style)
00434     {
00435     case 1:
00436     case 2:
00437       {
00438         POLYAREA *m;
00439         Coord t = (pin->Thickness + pin->Clearance) / 2;
00440         Coord w = 0.5 * pcb->ThermScale * pin->Clearance;
00441         pa = CirclePoly (pin->X, pin->Y, t);
00442         arc = CirclePoly (pin->X, pin->Y, pin->Thickness / 2);
00443         /* create a thin ring */
00444         poly_Boolean_free (pa, arc, &m, PBO_SUB);
00445         /* fix me needs error checking */
00446         if (style == 2)
00447           {
00448             /* t is the theoretically required length, but we use twice that
00449              * to avoid descritisation errors in our circle approximation.
00450              */
00451             pa = RectPoly (pin->X - t * 2, pin->X + t * 2, pin->Y - w, pin->Y + w);
00452             poly_Boolean_free (m, pa, &arc, PBO_SUB);
00453             pa = RectPoly (pin->X - w, pin->X + w, pin->Y - t * 2, pin->Y + t * 2);
00454           }
00455         else
00456           {
00457             /* t is the theoretically required length, but we use twice that
00458              * to avoid descritisation errors in our circle approximation.
00459              */
00460             pa = diag_line (pin->X, pin->Y, t * 2, w, true);
00461             poly_Boolean_free (m, pa, &arc, PBO_SUB);
00462             pa = diag_line (pin->X, pin->Y, t * 2, w, false);
00463           }
00464         poly_Boolean_free (arc, pa, &m, PBO_SUB);
00465         return m;
00466       }
00467 
00468 
00469     default:
00470       a.X = pin->X;
00471       a.Y = pin->Y;
00472       a.Height = a.Width = pin->Thickness / 2 + pin->Clearance / 4;
00473       a.Thickness = 1;
00474       a.Clearance = pin->Clearance / 2;
00475       a.Flags = NoFlags ();
00476       a.Delta =
00477         90 -
00478         (a.Clearance * (1. + 2. * pcb->ThermScale) * 180) / (M_PI * a.Width);
00479       a.StartAngle = 90 - a.Delta / 2 + (style == 4 ? 0 : 45);
00480       pa = ArcPoly (&a, a.Clearance);
00481       if (!pa)
00482         return NULL;
00483       a.StartAngle += 90;
00484       arc = ArcPoly (&a, a.Clearance);
00485       if (!arc)
00486         return NULL;
00487       pa->f = arc;
00488       arc->b = pa;
00489       a.StartAngle += 90;
00490       arc = ArcPoly (&a, a.Clearance);
00491       if (!arc)
00492         return NULL;
00493       pa->f->f = arc;
00494       arc->b = pa->f;
00495       a.StartAngle += 90;
00496       arc = ArcPoly (&a, a.Clearance);
00497       if (!arc)
00498         return NULL;
00499       pa->b = arc;
00500       pa->f->f->f = arc;
00501       arc->b = pa->f->f;
00502       arc->f = pa;
00503       pa->b = arc;
00504       return pa;
00505     }
00506 }