pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }