pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00035 #ifdef HAVE_CONFIG_H 00036 #include "config.h" 00037 #endif 00038 00039 #include <math.h> 00040 #include <setjmp.h> 00041 #include <stdlib.h> 00042 00043 00044 #include "global.h" 00045 #include "data.h" 00046 #include "crosshair.h" 00047 #include "find.h" 00048 #include "line.h" 00049 #include "misc.h" 00050 #include "rtree.h" 00051 00052 #ifdef HAVE_LIBDMALLOC 00053 #include <dmalloc.h> 00054 #endif 00055 00056 static double drc_lines (PointType *end, bool way); 00057 00061 void 00062 AdjustAttachedLine (void) 00063 { 00064 AttachedLineType *line = &Crosshair.AttachedLine; 00065 00066 /* I need at least one point */ 00067 if (line->State == STATE_FIRST) 00068 return; 00069 /* don't draw outline when ctrl key is pressed */ 00070 if (Settings.Mode == LINE_MODE && gui->control_is_pressed ()) 00071 { 00072 line->draw = false; 00073 return; 00074 } 00075 else 00076 line->draw = true; 00077 /* no 45 degree lines required */ 00078 if (PCB->RatDraw || TEST_FLAG (ALLDIRECTIONFLAG, PCB)) 00079 { 00080 line->Point2.X = Crosshair.X; 00081 line->Point2.Y = Crosshair.Y; 00082 return; 00083 } 00084 FortyFiveLine (line); 00085 } 00086 00099 void 00100 FortyFiveLine (AttachedLineType *Line) 00101 { 00102 Coord dx, dy, min, max; 00103 unsigned direction = 0; 00104 double m; 00105 00106 /* first calculate direction of line */ 00107 dx = Crosshair.X - Line->Point1.X; 00108 dy = Crosshair.Y - Line->Point1.Y; 00109 00110 /* zero length line, don't draw anything */ 00111 if (dx == 0 && dy == 0) 00112 return; 00113 00114 if (dx == 0) 00115 direction = dy > 0 ? 0 : 4; 00116 else 00117 { 00118 m = (double)dy / (double)dx; 00119 direction = 2; 00120 if (m > TAN_30_DEGREE) 00121 direction = m > TAN_60_DEGREE ? 0 : 1; 00122 else if (m < -TAN_30_DEGREE) 00123 direction = m < -TAN_60_DEGREE ? 4 : 3; 00124 } 00125 if (dx < 0) 00126 direction += 4; 00127 00128 dx = abs (dx); 00129 dy = abs (dy); 00130 min = MIN (dx, dy); 00131 max = MAX (dx, dy); 00132 00133 /* now set up the second pair of coordinates */ 00134 switch (direction) 00135 { 00136 case 0: 00137 Line->Point2.X = Line->Point1.X; 00138 Line->Point2.Y = Line->Point1.Y + max; 00139 break; 00140 00141 case 4: 00142 Line->Point2.X = Line->Point1.X; 00143 Line->Point2.Y = Line->Point1.Y - max; 00144 break; 00145 00146 case 2: 00147 Line->Point2.X = Line->Point1.X + max; 00148 Line->Point2.Y = Line->Point1.Y; 00149 break; 00150 00151 case 6: 00152 Line->Point2.X = Line->Point1.X - max; 00153 Line->Point2.Y = Line->Point1.Y; 00154 break; 00155 00156 case 1: 00157 Line->Point2.X = Line->Point1.X + min; 00158 Line->Point2.Y = Line->Point1.Y + min; 00159 break; 00160 00161 case 3: 00162 Line->Point2.X = Line->Point1.X + min; 00163 Line->Point2.Y = Line->Point1.Y - min; 00164 break; 00165 00166 case 5: 00167 Line->Point2.X = Line->Point1.X - min; 00168 Line->Point2.Y = Line->Point1.Y - min; 00169 break; 00170 00171 case 7: 00172 Line->Point2.X = Line->Point1.X - min; 00173 Line->Point2.Y = Line->Point1.Y + min; 00174 break; 00175 } 00176 } 00177 00181 void 00182 AdjustTwoLine (bool way) 00183 { 00184 Coord dx, dy; 00185 AttachedLineType *line = &Crosshair.AttachedLine; 00186 00187 if (Crosshair.AttachedLine.State == STATE_FIRST) 00188 return; 00189 /* don't draw outline when ctrl key is pressed */ 00190 if (gui->control_is_pressed ()) 00191 { 00192 line->draw = false; 00193 return; 00194 } 00195 else 00196 line->draw = true; 00197 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB)) 00198 { 00199 line->Point2.X = Crosshair.X; 00200 line->Point2.Y = Crosshair.Y; 00201 return; 00202 } 00203 /* swap the modes if shift is held down */ 00204 if (gui->shift_is_pressed ()) 00205 way = !way; 00206 dx = Crosshair.X - line->Point1.X; 00207 dy = Crosshair.Y - line->Point1.Y; 00208 if (!way) 00209 { 00210 if (abs (dx) > abs (dy)) 00211 { 00212 line->Point2.X = Crosshair.X - SGN (dx) * abs (dy); 00213 line->Point2.Y = line->Point1.Y; 00214 } 00215 else 00216 { 00217 line->Point2.X = line->Point1.X; 00218 line->Point2.Y = Crosshair.Y - SGN (dy) * abs (dx); 00219 } 00220 } 00221 else 00222 { 00223 if (abs (dx) > abs (dy)) 00224 { 00225 line->Point2.X = line->Point1.X + SGN (dx) * abs (dy); 00226 line->Point2.Y = Crosshair.Y; 00227 } 00228 else 00229 { 00230 line->Point2.X = Crosshair.X; 00231 line->Point2.Y = line->Point1.Y + SGN (dy) * abs (dx);; 00232 } 00233 } 00234 } 00235 00236 struct drc_info 00237 { 00238 LineType *line; 00239 bool bottom_side; 00240 bool top_side; 00241 jmp_buf env; 00242 }; 00243 00244 static int 00245 drcVia_callback (const BoxType * b, void *cl) 00246 { 00247 PinType *via = (PinType *) b; 00248 struct drc_info *i = (struct drc_info *) cl; 00249 00250 if (!TEST_FLAG (FOUNDFLAG, via) && PinLineIntersect (via, i->line)) 00251 longjmp (i->env, 1); 00252 return 1; 00253 } 00254 00255 static int 00256 drcPad_callback (const BoxType * b, void *cl) 00257 { 00258 PadType *pad = (PadType *) b; 00259 struct drc_info *i = (struct drc_info *) cl; 00260 00261 if (TEST_FLAG (ONSOLDERFLAG, pad) == i->bottom_side && 00262 !TEST_FLAG (FOUNDFLAG, pad) && LinePadIntersect (i->line, pad)) 00263 longjmp (i->env, 1); 00264 return 1; 00265 } 00266 00267 static int 00268 drcLine_callback (const BoxType * b, void *cl) 00269 { 00270 LineType *line = (LineType *) b; 00271 struct drc_info *i = (struct drc_info *) cl; 00272 00273 if (!TEST_FLAG (FOUNDFLAG, line) && LineLineIntersect (line, i->line)) 00274 longjmp (i->env, 1); 00275 return 1; 00276 } 00277 00278 static int 00279 drcArc_callback (const BoxType * b, void *cl) 00280 { 00281 ArcType *arc = (ArcType *) b; 00282 struct drc_info *i = (struct drc_info *) cl; 00283 00284 if (!TEST_FLAG (FOUNDFLAG, arc) && LineArcIntersect (i->line, arc)) 00285 longjmp (i->env, 1); 00286 return 1; 00287 } 00288 00300 static double 00301 drc_lines (PointType *end, bool way) 00302 { 00303 double f, s, f2, s2, len, best; 00304 Coord dx, dy, temp, last, length; 00305 Coord temp2, last2, length2; 00306 LineType line1, line2; 00307 Cardinal group; 00308 struct drc_info info; 00309 bool two_lines, x_is_long, blocker; 00310 PointType ans; 00311 00312 f = 1.0; 00313 s = 0.5; 00314 last = -1; 00315 line1.Flags = line2.Flags = NoFlags (); 00316 line1.Thickness = Settings.LineThickness + 2 * PCB->Bloat; 00317 line2.Thickness = line1.Thickness; 00318 line1.Clearance = line2.Clearance = 0; 00319 line1.Point1.X = Crosshair.AttachedLine.Point1.X; 00320 line1.Point1.Y = Crosshair.AttachedLine.Point1.Y; 00321 dy = end->Y - line1.Point1.Y; 00322 dx = end->X - line1.Point1.X; 00323 if (abs (dx) > abs (dy)) 00324 { 00325 x_is_long = true; 00326 length = abs (dx); 00327 } 00328 else 00329 { 00330 x_is_long = false; 00331 length = abs (dy); 00332 } 00333 00334 group = GetLayerGroupNumberByNumber (INDEXOFCURRENT); 00335 info.bottom_side = (GetLayerGroupNumberBySide (BOTTOM_SIDE) == group); 00336 info.top_side = (GetLayerGroupNumberBySide (TOP_SIDE) == group); 00337 00338 temp = length; 00339 /* assume the worst */ 00340 best = 0.0; 00341 ans.X = line1.Point1.X; 00342 ans.Y = line1.Point1.Y; 00343 while (length != last) 00344 { 00345 last = length; 00346 if (x_is_long) 00347 { 00348 dx = SGN (dx) * length; 00349 dy = end->Y - line1.Point1.Y; 00350 length2 = abs (dy); 00351 } 00352 else 00353 { 00354 dy = SGN (dy) * length; 00355 dx = end->X - line1.Point1.X; 00356 length2 = abs (dx); 00357 } 00358 temp2 = length2; 00359 f2 = 1.0; 00360 s2 = 0.5; 00361 last2 = -1; 00362 blocker = true; 00363 while (length2 != last2) 00364 { 00365 if (x_is_long) 00366 dy = SGN (dy) * length2; 00367 else 00368 dx = SGN (dx) * length2; 00369 two_lines = true; 00370 if (abs (dx) > abs (dy) && x_is_long) 00371 { 00372 line1.Point2.X = line1.Point1.X + 00373 (way ? SGN (dx) * abs (dy) : dx - SGN (dx) * abs (dy)); 00374 line1.Point2.Y = line1.Point1.Y + (way ? dy : 0); 00375 } 00376 else if (abs (dy) >= abs (dx) && !x_is_long) 00377 { 00378 line1.Point2.X = line1.Point1.X + (way ? dx : 0); 00379 line1.Point2.Y = line1.Point1.Y + 00380 (way ? SGN (dy) * abs (dx) : dy - SGN (dy) * abs (dx)); 00381 } 00382 else if (x_is_long) 00383 { 00384 /* we've changed which axis is long, so only do one line */ 00385 line1.Point2.X = line1.Point1.X + dx; 00386 line1.Point2.Y = 00387 line1.Point1.Y + (way ? SGN (dy) * abs (dx) : 0); 00388 two_lines = false; 00389 } 00390 else 00391 { 00392 /* we've changed which axis is long, so only do one line */ 00393 line1.Point2.Y = line1.Point1.Y + dy; 00394 line1.Point2.X = 00395 line1.Point1.X + (way ? SGN (dx) * abs (dy) : 0); 00396 two_lines = false; 00397 } 00398 line2.Point1.X = line1.Point2.X; 00399 line2.Point1.Y = line1.Point2.Y; 00400 if (!two_lines) 00401 { 00402 line2.Point2.Y = line1.Point2.Y; 00403 line2.Point2.X = line1.Point2.X; 00404 } 00405 else 00406 { 00407 line2.Point2.X = line1.Point1.X + dx; 00408 line2.Point2.Y = line1.Point1.Y + dy; 00409 } 00410 SetLineBoundingBox (&line1); 00411 SetLineBoundingBox (&line2); 00412 last2 = length2; 00413 if (setjmp (info.env) == 0) 00414 { 00415 info.line = &line1; 00416 r_search (PCB->Data->via_tree, &line1.BoundingBox, NULL, 00417 drcVia_callback, &info); 00418 r_search (PCB->Data->pin_tree, &line1.BoundingBox, NULL, 00419 drcVia_callback, &info); 00420 if (info.bottom_side || info.top_side) 00421 r_search (PCB->Data->pad_tree, &line1.BoundingBox, NULL, 00422 drcPad_callback, &info); 00423 if (two_lines) 00424 { 00425 info.line = &line2; 00426 r_search (PCB->Data->via_tree, &line2.BoundingBox, NULL, 00427 drcVia_callback, &info); 00428 r_search (PCB->Data->pin_tree, &line2.BoundingBox, NULL, 00429 drcVia_callback, &info); 00430 if (info.bottom_side || info.top_side) 00431 r_search (PCB->Data->pad_tree, &line2.BoundingBox, NULL, 00432 drcPad_callback, &info); 00433 } 00434 GROUP_LOOP (PCB->Data, group); 00435 { 00436 info.line = &line1; 00437 r_search (layer->line_tree, &line1.BoundingBox, NULL, 00438 drcLine_callback, &info); 00439 r_search (layer->arc_tree, &line1.BoundingBox, NULL, 00440 drcArc_callback, &info); 00441 if (two_lines) 00442 { 00443 info.line = &line2; 00444 r_search (layer->line_tree, &line2.BoundingBox, 00445 NULL, drcLine_callback, &info); 00446 r_search (layer->arc_tree, &line2.BoundingBox, 00447 NULL, drcArc_callback, &info); 00448 } 00449 } 00450 END_LOOP; 00451 /* no intersector! */ 00452 blocker = false; 00453 f2 += s2; 00454 len = (line2.Point2.X - line1.Point1.X); 00455 len *= len; 00456 len += (double) (line2.Point2.Y - line1.Point1.Y) * 00457 (line2.Point2.Y - line1.Point1.Y); 00458 if (len > best) 00459 { 00460 best = len; 00461 ans.X = line2.Point2.X; 00462 ans.Y = line2.Point2.Y; 00463 } 00464 #if 0 00465 if (f2 > 1.0) 00466 f2 = 0.5; 00467 #endif 00468 } 00469 else 00470 { 00471 /* bumped into something, back off */ 00472 f2 -= s2; 00473 } 00474 s2 *= 0.5; 00475 length2 = MIN (f2 * temp2, temp2); 00476 } 00477 if (!blocker && ((x_is_long && line2.Point2.X - line1.Point1.X == dx) 00478 || (!x_is_long 00479 && line2.Point2.Y - line1.Point1.Y == dy))) 00480 f += s; 00481 else 00482 f -= s; 00483 s *= 0.5; 00484 length = MIN (f * temp, temp); 00485 } 00486 00487 end->X = ans.X; 00488 end->Y = ans.Y; 00489 return best; 00490 } 00491 00492 void 00493 EnforceLineDRC (void) 00494 { 00495 PointType r45, rs; 00496 bool shift; 00497 double r1, r2; 00498 00499 /* Silence a bogus compiler warning by storing this in a variable */ 00500 int layer_idx = INDEXOFCURRENT; 00501 00502 if ( gui->mod1_is_pressed() || gui->control_is_pressed () || PCB->RatDraw 00503 || layer_idx >= max_copper_layer) 00504 return; 00505 00506 rs.X = r45.X = Crosshair.X; 00507 rs.Y = r45.Y = Crosshair.Y; 00508 /* first try starting straight */ 00509 r1 = drc_lines (&rs, false); 00510 /* then try starting at 45 */ 00511 r2 = drc_lines (&r45, true); 00512 shift = gui->shift_is_pressed (); 00513 if (XOR (r1 > r2, shift)) 00514 { 00515 if (PCB->Clipping) 00516 PCB->Clipping = shift ? 2 : 1; 00517 Crosshair.X = rs.X; 00518 Crosshair.Y = rs.Y; 00519 } 00520 else 00521 { 00522 if (PCB->Clipping) 00523 PCB->Clipping = shift ? 1 : 2; 00524 Crosshair.X = r45.X; 00525 Crosshair.Y = r45.Y; 00526 } 00527 }