pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00076 #ifdef HAVE_CONFIG_H 00077 #include "config.h" 00078 #endif 00079 00080 #include <setjmp.h> 00081 #include <assert.h> 00082 00083 #include "global.h" 00084 00085 #include "data.h" 00086 #include "draw.h" 00087 #include "error.h" 00088 #include "find.h" 00089 #include "misc.h" 00090 #include "rtree.h" 00091 #include "polygon.h" 00092 #include "pcb-printf.h" 00093 #include "search.h" 00094 #include "set.h" 00095 #include "undo.h" 00096 #include "rats.h" 00097 00098 #ifdef HAVE_LIBDMALLOC 00099 #include <dmalloc.h> 00100 #endif 00101 00102 #undef DEBUG 00103 00104 /* --------------------------------------------------------------------------- 00105 * some local macros 00106 */ 00107 00108 #define SEPARATE(FP) \ 00109 { \ 00110 int i; \ 00111 fputc('#', (FP)); \ 00112 for (i = Settings.CharPerLine; i; i--) \ 00113 fputc('=', (FP)); \ 00114 fputc('\n', (FP)); \ 00115 } 00116 00117 #define LIST_ENTRY(list,I) (((AnyObjectType **)list->Data)[(I)]) 00118 #define PADLIST_ENTRY(L,I) (((PadType **)PadList[(L)].Data)[(I)]) 00119 #define LINELIST_ENTRY(L,I) (((LineType **)LineList[(L)].Data)[(I)]) 00120 #define ARCLIST_ENTRY(L,I) (((ArcType **)ArcList[(L)].Data)[(I)]) 00121 #define RATLIST_ENTRY(I) (((RatType **)RatList.Data)[(I)]) 00122 #define POLYGONLIST_ENTRY(L,I) (((PolygonType **)PolygonList[(L)].Data)[(I)]) 00123 #define PVLIST_ENTRY(I) (((PinType **)PVList.Data)[(I)]) 00124 00125 #define IS_PV_ON_RAT(PV, Rat) \ 00126 (IsPointOnLineEnd((PV)->X,(PV)->Y, (Rat))) 00127 00128 #define IS_PV_ON_ARC(PV, Arc) \ 00129 (TEST_FLAG(SQUAREFLAG, (PV)) ? \ 00130 IsArcInRectangle( \ 00131 (PV)->X -MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y -MAX(((PV)->Thickness+1)/2 +Bloat,0), \ 00132 (PV)->X +MAX(((PV)->Thickness+1)/2 +Bloat,0), (PV)->Y +MAX(((PV)->Thickness+1)/2 +Bloat,0), \ 00133 (Arc)) : \ 00134 IsPointOnArc((PV)->X,(PV)->Y,MAX((PV)->Thickness/2.0 + Bloat,0.0), (Arc))) 00135 00136 #define IS_PV_ON_PAD(PV,Pad) \ 00137 ( IsPointInPad((PV)->X, (PV)->Y, MAX((PV)->Thickness/2 +Bloat,0), (Pad))) 00138 00139 00140 static DrcViolationType 00141 *pcb_drc_violation_new (const char *title, 00142 const char *explanation, 00143 Coord x, Coord y, 00144 Angle angle, 00145 bool have_measured, 00146 Coord measured_value, 00147 Coord required_value, 00148 int object_count, 00149 long int *object_id_list, 00150 int *object_type_list) 00151 { 00152 DrcViolationType *violation = (DrcViolationType *)malloc (sizeof (DrcViolationType)); 00153 00154 violation->title = strdup (title); 00155 violation->explanation = strdup (explanation); 00156 violation->x = x; 00157 violation->y = y; 00158 violation->angle = angle; 00159 violation->have_measured = have_measured; 00160 violation->measured_value = measured_value; 00161 violation->required_value = required_value; 00162 violation->object_count = object_count; 00163 violation->object_id_list = object_id_list; 00164 violation->object_type_list = object_type_list; 00165 00166 return violation; 00167 } 00168 00169 static void 00170 pcb_drc_violation_free (DrcViolationType *violation) 00171 { 00172 free (violation->title); 00173 free (violation->explanation); 00174 free (violation); 00175 } 00176 00177 static GString *drc_dialog_message; 00178 static void 00179 reset_drc_dialog_message(void) 00180 { 00181 if (drc_dialog_message) 00182 g_string_free (drc_dialog_message, FALSE); 00183 drc_dialog_message = g_string_new (""); 00184 if (gui->drc_gui != NULL) 00185 { 00186 gui->drc_gui->reset_drc_dialog_message (); 00187 } 00188 } 00189 static void 00190 append_drc_dialog_message(const char *fmt, ...) 00191 { 00192 gchar *new_str; 00193 va_list ap; 00194 va_start (ap, fmt); 00195 new_str = pcb_vprintf (fmt, ap); 00196 g_string_append (drc_dialog_message, new_str); 00197 va_end (ap); 00198 g_free (new_str); 00199 } 00200 00201 static void GotoError (void); 00202 00203 static void 00204 append_drc_violation (DrcViolationType *violation) 00205 { 00206 if (gui->drc_gui != NULL) 00207 { 00208 gui->drc_gui->append_drc_violation (violation); 00209 } 00210 else 00211 { 00212 /* Fallback to formatting the violation message as text */ 00213 append_drc_dialog_message ("%s\n", violation->title); 00214 append_drc_dialog_message (_("%m+near %$mD\n"), 00215 Settings.grid_unit->allow, 00216 violation->x, violation->y); 00217 GotoError (); 00218 } 00219 00220 if (gui->drc_gui == NULL || gui->drc_gui->log_drc_violations ) 00221 { 00222 Message (_("WARNING! Design Rule error - %s\n"), violation->title); 00223 Message (_("%m+near location %$mD\n"), 00224 Settings.grid_unit->allow, 00225 violation->x, violation->y); 00226 } 00227 } 00228 00229 #define DRC_CONTINUE _("Press Next to continue DRC checking") 00230 #define DRC_NEXT _("Next") 00231 #define DRC_CANCEL _("Cancel") 00232 00237 static int 00238 throw_drc_dialog(void) 00239 { 00240 int r; 00241 00242 if (gui->drc_gui != NULL) 00243 { 00244 r = gui->drc_gui->throw_drc_dialog (); 00245 } 00246 else 00247 { 00248 /* Fallback to formatting the violation message as text */ 00249 append_drc_dialog_message (DRC_CONTINUE); 00250 r = gui->confirm_dialog (drc_dialog_message->str, DRC_CANCEL, DRC_NEXT); 00251 reset_drc_dialog_message(); 00252 } 00253 return r; 00254 } 00255 00262 typedef struct 00263 { 00264 void **Data; 00265 Cardinal Location, 00266 DrawLocation, Number, 00267 Size; 00268 } ListType; 00269 00270 /* --------------------------------------------------------------------------- 00271 * some local identifiers 00272 */ 00273 static Coord Bloat = 0; 00274 static void *thing_ptr1, *thing_ptr2, *thing_ptr3; 00275 static int thing_type; 00276 static bool User = false; 00277 static bool drc = false; 00278 static Cardinal drcerr_count; 00279 static Cardinal TotalP, TotalV; 00280 static ListType LineList[MAX_LAYER], 00281 PolygonList[MAX_LAYER], ArcList[MAX_LAYER], PadList[2], RatList, PVList; 00282 00283 /* --------------------------------------------------------------------------- 00284 * some local prototypes 00285 */ 00286 static bool LookupLOConnectionsToLine (LineType *, Cardinal, int, bool, bool); 00287 static bool LookupLOConnectionsToPad (PadType *, Cardinal, int, bool); 00288 static bool LookupLOConnectionsToPolygon (PolygonType *, Cardinal, int, bool); 00289 static bool LookupLOConnectionsToArc (ArcType *, Cardinal, int, bool); 00290 static bool LookupLOConnectionsToRatEnd (PointType *, Cardinal, int); 00291 static bool IsRatPointOnLineEnd (PointType *, LineType *); 00292 static bool ArcArcIntersect (ArcType *, ArcType *); 00293 static bool PrepareNextLoop (FILE *); 00294 static void DrawNewConnections (void); 00295 static void DumpList (void); 00296 static void LocateError (Coord *, Coord *); 00297 static void BuildObjectList (int *, long int **, int **); 00298 static bool SetThing (int, void *, void *, void *); 00299 static bool IsArcInPolygon (ArcType *, PolygonType *); 00300 static bool IsLineInPolygon (LineType *, PolygonType *); 00301 static bool IsPadInPolygon (PadType *, PolygonType *); 00302 static bool IsPolygonInPolygon (PolygonType *, PolygonType *); 00303 00310 bool 00311 LinePadIntersect (LineType *Line, PadType *Pad) 00312 { 00313 return LineLineIntersect ((Line), (LineType *)Pad); 00314 } 00315 00316 bool 00317 ArcPadIntersect (ArcType *Arc, PadType *Pad) 00318 { 00319 return LineArcIntersect ((LineType *) (Pad), (Arc)); 00320 } 00321 00322 static bool 00323 add_object_to_list (ListType *list, int type, void *ptr1, void *ptr2, void *ptr3, int flag) 00324 { 00325 AnyObjectType *object = (AnyObjectType *)ptr2; 00326 00327 if (User) 00328 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3); 00329 00330 SET_FLAG (flag, object); 00331 LIST_ENTRY (list, list->Number) = object; 00332 list->Number++; 00333 00334 #ifdef DEBUG 00335 if (list->Number > list->Size) 00336 printf ("add_object_to_list overflow! type=%i num=%d size=%d\n", type, list->Number, list->Size); 00337 #endif 00338 00339 if (drc && !TEST_FLAG (SELECTEDFLAG, object)) 00340 return (SetThing (type, ptr1, ptr2, ptr3)); 00341 return false; 00342 } 00343 00344 static bool 00345 ADD_PV_TO_LIST (PinType *Pin, int flag) 00346 { 00347 return add_object_to_list (&PVList, Pin->Element ? PIN_TYPE : VIA_TYPE, 00348 Pin->Element ? Pin->Element : Pin, Pin, Pin, flag); 00349 } 00350 00351 static bool 00352 ADD_PAD_TO_LIST (Cardinal L, PadType *Pad, int flag) 00353 { 00354 return add_object_to_list (&PadList[L], PAD_TYPE, Pad->Element, Pad, Pad, flag); 00355 } 00356 00357 static bool 00358 ADD_LINE_TO_LIST (Cardinal L, LineType *Ptr, int flag) 00359 { 00360 return add_object_to_list (&LineList[L], LINE_TYPE, LAYER_PTR (L), Ptr, Ptr, flag); 00361 } 00362 00363 static bool 00364 ADD_ARC_TO_LIST (Cardinal L, ArcType *Ptr, int flag) 00365 { 00366 return add_object_to_list (&ArcList[L], ARC_TYPE, LAYER_PTR (L), Ptr, Ptr, flag); 00367 } 00368 00369 static bool 00370 ADD_RAT_TO_LIST (RatType *Ptr, int flag) 00371 { 00372 return add_object_to_list (&RatList, RATLINE_TYPE, Ptr, Ptr, Ptr, flag); 00373 } 00374 00375 static bool 00376 ADD_POLYGON_TO_LIST (Cardinal L, PolygonType *Ptr, int flag) 00377 { 00378 return add_object_to_list (&PolygonList[L], POLYGON_TYPE, LAYER_PTR (L), Ptr, Ptr, flag); 00379 } 00380 00381 static BoxType 00382 expand_bounds (BoxType *box_in) 00383 { 00384 BoxType box_out = *box_in; 00385 00386 if (Bloat > 0) 00387 { 00388 box_out.X1 -= Bloat; 00389 box_out.X2 += Bloat; 00390 box_out.Y1 -= Bloat; 00391 box_out.Y2 += Bloat; 00392 } 00393 00394 return box_out; 00395 } 00396 00397 bool 00398 PinLineIntersect (PinType *PV, LineType *Line) 00399 { 00400 /* IsLineInRectangle already has Bloat factor */ 00401 return TEST_FLAG (SQUAREFLAG, 00402 PV) ? IsLineInRectangle (PV->X - (PIN_SIZE (PV) + 1) / 2, 00403 PV->Y - (PIN_SIZE (PV) + 1) / 2, 00404 PV->X + (PIN_SIZE (PV) + 1) / 2, 00405 PV->Y + (PIN_SIZE (PV) + 1) / 2, 00406 Line) : IsPointInPad (PV->X, 00407 PV->Y, 00408 MAX (PIN_SIZE (PV) 00409 / 00410 2.0 + 00411 Bloat, 00412 0.0), 00413 (PadType *)Line); 00414 } 00415 00416 00417 bool 00418 SetThing (int type, void *ptr1, void *ptr2, void *ptr3) 00419 { 00420 thing_ptr1 = ptr1; 00421 thing_ptr2 = ptr2; 00422 thing_ptr3 = ptr3; 00423 thing_type = type; 00424 return true; 00425 } 00426 00427 bool 00428 BoxBoxIntersection (BoxType *b1, BoxType *b2) 00429 { 00430 if (b2->X2 < b1->X1 || b2->X1 > b1->X2) 00431 return false; 00432 if (b2->Y2 < b1->Y1 || b2->Y1 > b1->Y2) 00433 return false; 00434 return true; 00435 } 00436 00437 static bool 00438 PadPadIntersect (PadType *p1, PadType *p2) 00439 { 00440 return LinePadIntersect ((LineType *) p1, p2); 00441 } 00442 00443 static inline bool 00444 PV_TOUCH_PV (PinType *PV1, PinType *PV2) 00445 { 00446 double t1, t2; 00447 BoxType b1, b2; 00448 00449 t1 = MAX (PV1->Thickness / 2.0 + Bloat, 0); 00450 t2 = MAX (PV2->Thickness / 2.0 + Bloat, 0); 00451 if (IsPointOnPin (PV1->X, PV1->Y, t1, PV2) 00452 || IsPointOnPin (PV2->X, PV2->Y, t2, PV1)) 00453 return true; 00454 if (!TEST_FLAG (SQUAREFLAG, PV1) || !TEST_FLAG (SQUAREFLAG, PV2)) 00455 return false; 00456 /* check for square/square overlap */ 00457 b1.X1 = PV1->X - t1; 00458 b1.X2 = PV1->X + t1; 00459 b1.Y1 = PV1->Y - t1; 00460 b1.Y2 = PV1->Y + t1; 00461 t2 = PV2->Thickness / 2.0; 00462 b2.X1 = PV2->X - t2; 00463 b2.X2 = PV2->X + t2; 00464 b2.Y1 = PV2->Y - t2; 00465 b2.Y2 = PV2->Y + t2; 00466 return BoxBoxIntersection (&b1, &b2); 00467 } 00468 00472 static void 00473 FreeLayoutLookupMemory (void) 00474 { 00475 Cardinal i; 00476 00477 for (i = 0; i < max_copper_layer; i++) 00478 { 00479 free (LineList[i].Data); 00480 LineList[i].Data = NULL; 00481 free (ArcList[i].Data); 00482 ArcList[i].Data = NULL; 00483 free (PolygonList[i].Data); 00484 PolygonList[i].Data = NULL; 00485 } 00486 free (PVList.Data); 00487 PVList.Data = NULL; 00488 free (RatList.Data); 00489 RatList.Data = NULL; 00490 } 00491 00492 static void 00493 FreeComponentLookupMemory (void) 00494 { 00495 free (PadList[0].Data); 00496 PadList[0].Data = NULL; 00497 free (PadList[1].Data); 00498 PadList[1].Data = NULL; 00499 } 00500 00506 static void 00507 InitComponentLookup (void) 00508 { 00509 Cardinal NumberOfPads[2]; 00510 Cardinal i; 00511 00512 /* initialize pad data; start by counting the total number 00513 * on each of the two possible layers 00514 */ 00515 NumberOfPads[TOP_SIDE] = NumberOfPads[BOTTOM_SIDE] = 0; 00516 ALLPAD_LOOP (PCB->Data); 00517 { 00518 if (TEST_FLAG (ONSOLDERFLAG, pad)) 00519 NumberOfPads[BOTTOM_SIDE]++; 00520 else 00521 NumberOfPads[TOP_SIDE]++; 00522 } 00523 ENDALL_LOOP; 00524 for (i = 0; i < 2; i++) 00525 { 00526 /* allocate memory for working list */ 00527 PadList[i].Data = (void **)calloc (NumberOfPads[i], sizeof (PadType *)); 00528 00529 /* clear some struct members */ 00530 PadList[i].Location = 0; 00531 PadList[i].DrawLocation = 0; 00532 PadList[i].Number = 0; 00533 PadList[i].Size = NumberOfPads[i]; 00534 } 00535 } 00536 00542 static void 00543 InitLayoutLookup (void) 00544 { 00545 Cardinal i; 00546 00547 /* initialize line arc and polygon data */ 00548 for (i = 0; i < max_copper_layer; i++) 00549 { 00550 LayerType *layer = LAYER_PTR (i); 00551 00552 if (layer->LineN) 00553 { 00554 /* allocate memory for line pointer lists */ 00555 LineList[i].Data = (void **)calloc (layer->LineN, sizeof (LineType *)); 00556 LineList[i].Size = layer->LineN; 00557 } 00558 if (layer->ArcN) 00559 { 00560 ArcList[i].Data = (void **)calloc (layer->ArcN, sizeof (ArcType *)); 00561 ArcList[i].Size = layer->ArcN; 00562 } 00563 00564 00565 /* allocate memory for polygon list */ 00566 if (layer->PolygonN) 00567 { 00568 PolygonList[i].Data = (void **)calloc (layer->PolygonN, sizeof (PolygonType *)); 00569 PolygonList[i].Size = layer->PolygonN; 00570 } 00571 00572 /* clear some struct members */ 00573 LineList[i].Location = 0; 00574 LineList[i].DrawLocation = 0; 00575 LineList[i].Number = 0; 00576 ArcList[i].Location = 0; 00577 ArcList[i].DrawLocation = 0; 00578 ArcList[i].Number = 0; 00579 PolygonList[i].Location = 0; 00580 PolygonList[i].DrawLocation = 0; 00581 PolygonList[i].Number = 0; 00582 } 00583 00584 if (PCB->Data->pin_tree) 00585 TotalP = PCB->Data->pin_tree->size; 00586 else 00587 TotalP = 0; 00588 if (PCB->Data->via_tree) 00589 TotalV = PCB->Data->via_tree->size; 00590 else 00591 TotalV = 0; 00592 /* allocate memory for 'new PV to check' list and clear struct */ 00593 PVList.Data = (void **)calloc (TotalP + TotalV, sizeof (PinType *)); 00594 PVList.Size = TotalP + TotalV; 00595 PVList.Location = 0; 00596 PVList.DrawLocation = 0; 00597 PVList.Number = 0; 00598 /* Initialize ratline data */ 00599 RatList.Data = (void **)calloc (PCB->Data->RatN, sizeof (RatType *)); 00600 RatList.Size = PCB->Data->RatN; 00601 RatList.Location = 0; 00602 RatList.DrawLocation = 0; 00603 RatList.Number = 0; 00604 } 00605 00606 struct pv_info 00607 { 00608 Cardinal layer; 00609 PinType *pv; 00610 int flag; 00611 jmp_buf env; 00612 }; 00613 00614 static int 00615 LOCtoPVline_callback (const BoxType * b, void *cl) 00616 { 00617 LineType *line = (LineType *) b; 00618 struct pv_info *i = (struct pv_info *) cl; 00619 00620 if (!ViaIsOnLayerGroup (i->pv, GetLayerGroupNumberByNumber (i->layer))) 00621 return 0; 00622 00623 if (!TEST_FLAG (i->flag, line) && PinLineIntersect (i->pv, line) && 00624 !TEST_FLAG (HOLEFLAG, i->pv)) 00625 { 00626 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 00627 longjmp (i->env, 1); 00628 } 00629 return 0; 00630 } 00631 00632 static int 00633 LOCtoPVarc_callback (const BoxType * b, void *cl) 00634 { 00635 ArcType *arc = (ArcType *) b; 00636 struct pv_info *i = (struct pv_info *) cl; 00637 00638 if (!ViaIsOnLayerGroup (i->pv, GetLayerGroupNumberByNumber (i->layer))) 00639 return 0; 00640 00641 if (!TEST_FLAG (i->flag, arc) && IS_PV_ON_ARC (i->pv, arc) && 00642 !TEST_FLAG (HOLEFLAG, i->pv)) 00643 { 00644 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag)) 00645 longjmp (i->env, 1); 00646 } 00647 return 0; 00648 } 00649 00650 static int 00651 LOCtoPVpad_callback (const BoxType * b, void *cl) 00652 { 00653 PadType *pad = (PadType *) b; 00654 struct pv_info *i = (struct pv_info *) cl; 00655 00656 if (!ViaIsOnLayerGroup (i->pv, GetLayerGroupNumberBySide (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE))) 00657 return 0; 00658 00659 if (!TEST_FLAG (i->flag, pad) && IS_PV_ON_PAD (i->pv, pad) && 00660 !TEST_FLAG (HOLEFLAG, i->pv) && 00661 ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : 00662 TOP_SIDE, pad, i->flag)) 00663 longjmp (i->env, 1); 00664 return 0; 00665 } 00666 00667 static int 00668 LOCtoPVrat_callback (const BoxType * b, void *cl) 00669 { 00670 RatType *rat = (RatType *) b; 00671 struct pv_info *i = (struct pv_info *) cl; 00672 00673 if (!TEST_FLAG (i->flag, rat) && IS_PV_ON_RAT (i->pv, rat) && 00674 ADD_RAT_TO_LIST (rat, i->flag)) 00675 longjmp (i->env, 1); 00676 return 0; 00677 } 00678 00679 static int 00680 LOCtoPVpoly_callback (const BoxType * b, void *cl) 00681 { 00682 PolygonType *polygon = (PolygonType *) b; 00683 struct pv_info *i = (struct pv_info *) cl; 00684 00685 if (!ViaIsOnLayerGroup (i->pv, GetLayerGroupNumberByNumber (i->layer))) 00686 return 0; 00687 00688 /* if the pin doesn't have a therm and polygon is clearing 00689 * then it can't touch due to clearance, so skip the expensive 00690 * test. If it does have a therm, you still need to test 00691 * because it might not be inside the polygon, or it could 00692 * be on an edge such that it doesn't actually touch. 00693 */ 00694 if (!TEST_FLAG (i->flag, polygon) && !TEST_FLAG (HOLEFLAG, i->pv) && 00695 (TEST_THERM (i->layer, i->pv) || 00696 !TEST_FLAG (CLEARPOLYFLAG, 00697 polygon) 00698 || !i->pv->Clearance)) 00699 { 00700 double wide = MAX (0.5 * i->pv->Thickness + Bloat, 0); 00701 if (TEST_FLAG (SQUAREFLAG, i->pv)) 00702 { 00703 Coord x1 = i->pv->X - (i->pv->Thickness + 1 + Bloat) / 2; 00704 Coord x2 = i->pv->X + (i->pv->Thickness + 1 + Bloat) / 2; 00705 Coord y1 = i->pv->Y - (i->pv->Thickness + 1 + Bloat) / 2; 00706 Coord y2 = i->pv->Y + (i->pv->Thickness + 1 + Bloat) / 2; 00707 if (IsRectangleInPolygon (x1, y1, x2, y2, polygon) 00708 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag)) 00709 longjmp (i->env, 1); 00710 } 00711 else if (TEST_FLAG (OCTAGONFLAG, i->pv)) 00712 { 00713 POLYAREA *oct = OctagonPoly (i->pv->X, i->pv->Y, i->pv->Thickness / 2); 00714 if (isects (oct, polygon, true) 00715 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag)) 00716 longjmp (i->env, 1); 00717 } 00718 else if (IsPointInPolygon (i->pv->X, i->pv->Y, wide, 00719 polygon) 00720 && ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag)) 00721 longjmp (i->env, 1); 00722 } 00723 return 0; 00724 } 00725 00730 static bool 00731 LookupLOConnectionsToPVList (int flag, bool AndRats) 00732 { 00733 Cardinal layer_no; 00734 struct pv_info info; 00735 00736 info.flag = flag; 00737 00738 /* loop over all PVs currently on list */ 00739 while (PVList.Location < PVList.Number) 00740 { 00741 BoxType search_box; 00742 00743 /* get pointer to data */ 00744 info.pv = PVLIST_ENTRY (PVList.Location); 00745 search_box = expand_bounds (&info.pv->BoundingBox); 00746 00747 /* check pads */ 00748 if (setjmp (info.env) == 0) 00749 r_search (PCB->Data->pad_tree, &search_box, NULL, 00750 LOCtoPVpad_callback, &info); 00751 else 00752 return true; 00753 00754 /* now all lines, arcs and polygons of the several layers */ 00755 for (layer_no = 0; layer_no < max_copper_layer; layer_no++) 00756 { 00757 LayerType *layer = LAYER_PTR (layer_no); 00758 00759 if (layer->no_drc) 00760 continue; 00761 00762 info.layer = layer_no; 00763 00764 /* add touching lines */ 00765 if (setjmp (info.env) == 0) 00766 r_search (layer->line_tree, &search_box, 00767 NULL, LOCtoPVline_callback, &info); 00768 else 00769 return true; 00770 /* add touching arcs */ 00771 if (setjmp (info.env) == 0) 00772 r_search (layer->arc_tree, &search_box, 00773 NULL, LOCtoPVarc_callback, &info); 00774 else 00775 return true; 00776 /* check all polygons */ 00777 if (setjmp (info.env) == 0) 00778 r_search (layer->polygon_tree, &search_box, 00779 NULL, LOCtoPVpoly_callback, &info); 00780 else 00781 return true; 00782 } 00783 /* Check for rat-lines that may intersect the PV */ 00784 if (AndRats) 00785 { 00786 if (setjmp (info.env) == 0) 00787 r_search (PCB->Data->rat_tree, &search_box, NULL, 00788 LOCtoPVrat_callback, &info); 00789 else 00790 return true; 00791 } 00792 PVList.Location++; 00793 } 00794 return false; 00795 } 00796 00801 static bool 00802 LookupLOConnectionsToLOList (int flag, bool AndRats) 00803 { 00804 bool done; 00805 Cardinal i, group, layer, ratposition, 00806 lineposition[MAX_LAYER], 00807 polyposition[MAX_LAYER], arcposition[MAX_LAYER], padposition[2]; 00808 00809 /* copy the current LO list positions; the original data is changed 00810 * by 'LookupPVConnectionsToLOList()' which has to check the same 00811 * list entries plus the new ones 00812 */ 00813 for (i = 0; i < max_copper_layer; i++) 00814 { 00815 lineposition[i] = LineList[i].Location; 00816 polyposition[i] = PolygonList[i].Location; 00817 arcposition[i] = ArcList[i].Location; 00818 } 00819 for (i = 0; i < 2; i++) 00820 padposition[i] = PadList[i].Location; 00821 ratposition = RatList.Location; 00822 00823 /* loop over all new LOs in the list; recurse until no 00824 * more new connections in the layergroup were found 00825 */ 00826 do 00827 { 00828 Cardinal *position; 00829 00830 if (AndRats) 00831 { 00832 position = &ratposition; 00833 for (; *position < RatList.Number; (*position)++) 00834 { 00835 group = RATLIST_ENTRY (*position)->group1; 00836 if (LookupLOConnectionsToRatEnd 00837 (&(RATLIST_ENTRY (*position)->Point1), group, flag)) 00838 return (true); 00839 group = RATLIST_ENTRY (*position)->group2; 00840 if (LookupLOConnectionsToRatEnd 00841 (&(RATLIST_ENTRY (*position)->Point2), group, flag)) 00842 return (true); 00843 } 00844 } 00845 /* loop over all layergroups */ 00846 for (group = 0; group < max_group; group++) 00847 { 00848 Cardinal entry; 00849 00850 for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) 00851 { 00852 layer = PCB->LayerGroups.Entries[group][entry]; 00853 00854 /* be aware that the layer number equal max_copper_layer 00855 * and max_copper_layer+1 have a special meaning for pads 00856 */ 00857 if (layer < max_copper_layer) 00858 { 00859 /* try all new lines */ 00860 position = &lineposition[layer]; 00861 for (; *position < LineList[layer].Number; (*position)++) 00862 if (LookupLOConnectionsToLine 00863 (LINELIST_ENTRY (layer, *position), group, flag, true, AndRats)) 00864 return (true); 00865 00866 /* try all new arcs */ 00867 position = &arcposition[layer]; 00868 for (; *position < ArcList[layer].Number; (*position)++) 00869 if (LookupLOConnectionsToArc 00870 (ARCLIST_ENTRY (layer, *position), group, flag, AndRats)) 00871 return (true); 00872 00873 /* try all new polygons */ 00874 position = &polyposition[layer]; 00875 for (; *position < PolygonList[layer].Number; (*position)++) 00876 if (LookupLOConnectionsToPolygon 00877 (POLYGONLIST_ENTRY (layer, *position), group, flag, AndRats)) 00878 return (true); 00879 } 00880 else 00881 { 00882 /* try all new pads */ 00883 layer -= max_copper_layer; 00884 if (layer > 1) 00885 { 00886 Message (_("bad layer number %d max_copper_layer=%d in find.c\n"), 00887 layer, max_copper_layer); 00888 return false; 00889 } 00890 position = &padposition[layer]; 00891 for (; *position < PadList[layer].Number; (*position)++) 00892 if (LookupLOConnectionsToPad 00893 (PADLIST_ENTRY (layer, *position), group, flag, AndRats)) 00894 return (true); 00895 } 00896 } 00897 } 00898 00899 /* check if all lists are done; Later for-loops 00900 * may have changed the prior lists 00901 */ 00902 done = !AndRats || ratposition >= RatList.Number; 00903 done = done && padposition[0] >= PadList[0].Number && 00904 padposition[1] >= PadList[1].Number; 00905 for (layer = 0; layer < max_copper_layer; layer++) 00906 done = done && 00907 lineposition[layer] >= LineList[layer].Number && 00908 arcposition[layer] >= ArcList[layer].Number && 00909 polyposition[layer] >= PolygonList[layer].Number; 00910 } 00911 while (!done); 00912 return (false); 00913 } 00914 00915 static int 00916 pv_pv_callback (const BoxType * b, void *cl) 00917 { 00918 PinType *pin = (PinType *) b; 00919 struct pv_info *i = (struct pv_info *) cl; 00920 bool pv_overlap = false; 00921 Cardinal l; 00922 00923 if (VIA_IS_BURIED (pin) && VIA_IS_BURIED (i->pv)) 00924 { 00925 for (l = pin->BuriedFrom ; l <= pin->BuriedTo; l++) 00926 { 00927 if (ViaIsOnLayerGroup (i->pv, GetLayerGroupNumberByNumber (l))) 00928 { 00929 pv_overlap = true; 00930 break; 00931 } 00932 } 00933 if (!pv_overlap) 00934 return 0; 00935 } 00936 00937 if (!TEST_FLAG (i->flag, pin) && PV_TOUCH_PV (i->pv, pin)) 00938 { 00939 if (TEST_FLAG (HOLEFLAG, pin) || TEST_FLAG (HOLEFLAG, i->pv)) 00940 { 00941 SET_FLAG (WARNFLAG, pin); 00942 Settings.RatWarn = true; 00943 if (pin->Element) 00944 Message (_("WARNING: Hole too close to pin.\n")); 00945 else 00946 Message (_("WARNING: Hole too close to via.\n")); 00947 } 00948 else if (ADD_PV_TO_LIST (pin, i->flag)) 00949 longjmp (i->env, 1); 00950 } 00951 return 0; 00952 } 00953 00957 static bool 00958 LookupPVConnectionsToPVList (int flag) 00959 { 00960 Cardinal save_place; 00961 struct pv_info info; 00962 00963 info.flag = flag; 00964 00965 /* loop over all PVs on list */ 00966 save_place = PVList.Location; 00967 while (PVList.Location < PVList.Number) 00968 { 00969 BoxType search_box; 00970 00971 /* get pointer to data */ 00972 info.pv = PVLIST_ENTRY (PVList.Location); 00973 search_box = expand_bounds ((BoxType *)info.pv); 00974 00975 if (setjmp (info.env) == 0) 00976 r_search (PCB->Data->via_tree, &search_box, NULL, 00977 pv_pv_callback, &info); 00978 else 00979 return true; 00980 if (setjmp (info.env) == 0) 00981 r_search (PCB->Data->pin_tree, &search_box, NULL, 00982 pv_pv_callback, &info); 00983 else 00984 return true; 00985 PVList.Location++; 00986 } 00987 PVList.Location = save_place; 00988 return (false); 00989 } 00990 00991 struct lo_info 00992 { 00993 Cardinal layer; 00994 LineType *line; 00995 PadType *pad; 00996 ArcType *arc; 00997 PolygonType *polygon; 00998 RatType *rat; 00999 int flag; 01000 jmp_buf env; 01001 }; 01002 01003 static int 01004 pv_line_callback (const BoxType * b, void *cl) 01005 { 01006 PinType *pv = (PinType *) b; 01007 struct lo_info *i = (struct lo_info *) cl; 01008 01009 if (!ViaIsOnLayerGroup (pv, GetLayerGroupNumberByNumber (i->layer))) 01010 return 0; 01011 01012 if (!TEST_FLAG (i->flag, pv) && PinLineIntersect (pv, i->line)) 01013 { 01014 if (TEST_FLAG (HOLEFLAG, pv)) 01015 { 01016 SET_FLAG (WARNFLAG, pv); 01017 Settings.RatWarn = true; 01018 Message (_("WARNING: Hole too close to line.\n")); 01019 } 01020 else if (ADD_PV_TO_LIST (pv, i->flag)) 01021 longjmp (i->env, 1); 01022 } 01023 return 0; 01024 } 01025 01026 static int 01027 pv_pad_callback (const BoxType * b, void *cl) 01028 { 01029 PinType *pv = (PinType *) b; 01030 struct lo_info *i = (struct lo_info *) cl; 01031 01032 if (!ViaIsOnLayerGroup (pv, GetLayerGroupNumberBySide (i->layer))) 01033 return 0; 01034 01035 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_PAD (pv, i->pad)) 01036 { 01037 if (TEST_FLAG (HOLEFLAG, pv)) 01038 { 01039 SET_FLAG (WARNFLAG, pv); 01040 Settings.RatWarn = true; 01041 Message (_("WARNING: Hole too close to pad.\n")); 01042 } 01043 else if (ADD_PV_TO_LIST (pv, i->flag)) 01044 longjmp (i->env, 1); 01045 } 01046 return 0; 01047 } 01048 01049 static int 01050 pv_arc_callback (const BoxType * b, void *cl) 01051 { 01052 PinType *pv = (PinType *) b; 01053 struct lo_info *i = (struct lo_info *) cl; 01054 01055 if (!ViaIsOnLayerGroup (pv, GetLayerGroupNumberByNumber (i->layer))) 01056 return 0; 01057 01058 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_ARC (pv, i->arc)) 01059 { 01060 if (TEST_FLAG (HOLEFLAG, pv)) 01061 { 01062 SET_FLAG (WARNFLAG, pv); 01063 Settings.RatWarn = true; 01064 Message (_("WARNING: Hole touches arc.\n")); 01065 } 01066 else if (ADD_PV_TO_LIST (pv, i->flag)) 01067 longjmp (i->env, 1); 01068 } 01069 return 0; 01070 } 01071 01072 static int 01073 pv_poly_callback (const BoxType * b, void *cl) 01074 { 01075 PinType *pv = (PinType *) b; 01076 struct lo_info *i = (struct lo_info *) cl; 01077 01078 if (!ViaIsOnLayerGroup (pv, GetLayerGroupNumberByNumber (i->layer))) 01079 return 0; 01080 01081 /* note that holes in polygons are ok, so they don't generate warnings. */ 01082 if (!TEST_FLAG (i->flag, pv) && !TEST_FLAG (HOLEFLAG, pv) && 01083 (TEST_THERM (i->layer, pv) || 01084 !TEST_FLAG (CLEARPOLYFLAG, i->polygon) || 01085 !pv->Clearance)) 01086 { 01087 if (TEST_FLAG (SQUAREFLAG, pv)) 01088 { 01089 Coord x1, x2, y1, y2; 01090 x1 = pv->X - (PIN_SIZE (pv) + 1 + Bloat) / 2; 01091 x2 = pv->X + (PIN_SIZE (pv) + 1 + Bloat) / 2; 01092 y1 = pv->Y - (PIN_SIZE (pv) + 1 + Bloat) / 2; 01093 y2 = pv->Y + (PIN_SIZE (pv) + 1 + Bloat) / 2; 01094 if (IsRectangleInPolygon (x1, y1, x2, y2, i->polygon) 01095 && ADD_PV_TO_LIST (pv, i->flag)) 01096 longjmp (i->env, 1); 01097 } 01098 else if (TEST_FLAG (OCTAGONFLAG, pv)) 01099 { 01100 POLYAREA *oct = OctagonPoly (pv->X, pv->Y, PIN_SIZE (pv) / 2); 01101 if (isects (oct, i->polygon, true) && ADD_PV_TO_LIST (pv, i->flag)) 01102 longjmp (i->env, 1); 01103 } 01104 else 01105 { 01106 if (IsPointInPolygon 01107 (pv->X, pv->Y, PIN_SIZE (pv) * 0.5 + Bloat, i->polygon) 01108 && ADD_PV_TO_LIST (pv, i->flag)) 01109 longjmp (i->env, 1); 01110 } 01111 } 01112 return 0; 01113 } 01114 01115 static int 01116 pv_rat_callback (const BoxType * b, void *cl) 01117 { 01118 PinType *pv = (PinType *) b; 01119 struct lo_info *i = (struct lo_info *) cl; 01120 01121 /* rats can't cause DRC so there is no early exit */ 01122 if (!TEST_FLAG (i->flag, pv) && IS_PV_ON_RAT (pv, i->rat)) 01123 ADD_PV_TO_LIST (pv, i->flag); 01124 return 0; 01125 } 01126 01132 static bool 01133 LookupPVConnectionsToLOList (int flag, bool AndRats) 01134 { 01135 Cardinal layer_no; 01136 struct lo_info info; 01137 01138 info.flag = flag; 01139 01140 /* loop over all layers */ 01141 for (layer_no = 0; layer_no < max_copper_layer; layer_no++) 01142 { 01143 LayerType *layer = LAYER_PTR (layer_no); 01144 01145 if (layer->no_drc) 01146 continue; 01147 /* do nothing if there are no PV's */ 01148 if (TotalP + TotalV == 0) 01149 { 01150 LineList[layer_no].Location = LineList[layer_no].Number; 01151 ArcList[layer_no].Location = ArcList[layer_no].Number; 01152 PolygonList[layer_no].Location = PolygonList[layer_no].Number; 01153 continue; 01154 } 01155 01156 info.layer = layer_no; 01157 /* check all lines */ 01158 while (LineList[layer_no].Location < LineList[layer_no].Number) 01159 { 01160 BoxType search_box; 01161 01162 info.line = LINELIST_ENTRY (layer_no, LineList[layer_no].Location); 01163 search_box = expand_bounds ((BoxType *)info.line); 01164 01165 if (setjmp (info.env) == 0) 01166 r_search (PCB->Data->via_tree, &search_box, NULL, 01167 pv_line_callback, &info); 01168 else 01169 return true; 01170 if (setjmp (info.env) == 0) 01171 r_search (PCB->Data->pin_tree, &search_box, NULL, 01172 pv_line_callback, &info); 01173 else 01174 return true; 01175 LineList[layer_no].Location++; 01176 } 01177 01178 /* check all arcs */ 01179 while (ArcList[layer_no].Location < ArcList[layer_no].Number) 01180 { 01181 BoxType search_box; 01182 01183 info.arc = ARCLIST_ENTRY (layer_no, ArcList[layer_no].Location); 01184 search_box = expand_bounds ((BoxType *)info.arc); 01185 01186 if (setjmp (info.env) == 0) 01187 r_search (PCB->Data->via_tree, &search_box, NULL, 01188 pv_arc_callback, &info); 01189 else 01190 return true; 01191 if (setjmp (info.env) == 0) 01192 r_search (PCB->Data->pin_tree, &search_box, NULL, 01193 pv_arc_callback, &info); 01194 else 01195 return true; 01196 ArcList[layer_no].Location++; 01197 } 01198 01199 /* now all polygons */ 01200 info.layer = layer_no; 01201 while (PolygonList[layer_no].Location < PolygonList[layer_no].Number) 01202 { 01203 BoxType search_box; 01204 01205 info.polygon = POLYGONLIST_ENTRY (layer_no, PolygonList[layer_no].Location); 01206 search_box = expand_bounds ((BoxType *)info.polygon); 01207 01208 if (setjmp (info.env) == 0) 01209 r_search (PCB->Data->via_tree, &search_box, NULL, 01210 pv_poly_callback, &info); 01211 else 01212 return true; 01213 if (setjmp (info.env) == 0) 01214 r_search (PCB->Data->pin_tree, &search_box, NULL, 01215 pv_poly_callback, &info); 01216 else 01217 return true; 01218 PolygonList[layer_no].Location++; 01219 } 01220 } 01221 01222 /* loop over all pad-layers */ 01223 for (layer_no = 0; layer_no < 2; layer_no++) 01224 { 01225 /* do nothing if there are no PV's */ 01226 if (TotalP + TotalV == 0) 01227 { 01228 PadList[layer_no].Location = PadList[layer_no].Number; 01229 continue; 01230 } 01231 01232 /* check all pads; for a detailed description see 01233 * the handling of lines in this subroutine 01234 */ 01235 while (PadList[layer_no].Location < PadList[layer_no].Number) 01236 { 01237 BoxType search_box; 01238 01239 info.layer = layer_no; 01240 info.pad = PADLIST_ENTRY (layer_no, PadList[layer_no].Location); 01241 search_box = expand_bounds ((BoxType *)info.pad); 01242 01243 if (setjmp (info.env) == 0) 01244 r_search (PCB->Data->via_tree, &search_box, NULL, 01245 pv_pad_callback, &info); 01246 else 01247 return true; 01248 if (setjmp (info.env) == 0) 01249 r_search (PCB->Data->pin_tree, &search_box, NULL, 01250 pv_pad_callback, &info); 01251 else 01252 return true; 01253 PadList[layer_no].Location++; 01254 } 01255 } 01256 01257 /* do nothing if there are no PV's */ 01258 if (TotalP + TotalV == 0) 01259 RatList.Location = RatList.Number; 01260 01261 /* check all rat-lines */ 01262 if (AndRats) 01263 { 01264 while (RatList.Location < RatList.Number) 01265 { 01266 info.rat = RATLIST_ENTRY (RatList.Location); 01267 r_search_pt (PCB->Data->via_tree, & info.rat->Point1, 1, NULL, 01268 pv_rat_callback, &info); 01269 r_search_pt (PCB->Data->via_tree, & info.rat->Point2, 1, NULL, 01270 pv_rat_callback, &info); 01271 r_search_pt (PCB->Data->pin_tree, & info.rat->Point1, 1, NULL, 01272 pv_rat_callback, &info); 01273 r_search_pt (PCB->Data->pin_tree, & info.rat->Point2, 1, NULL, 01274 pv_rat_callback, &info); 01275 01276 RatList.Location++; 01277 } 01278 } 01279 return (false); 01280 } 01281 01285 static void 01286 normalize_angles (Angle *sa, Angle *d) 01287 { 01288 if (*d < 0) 01289 { 01290 *sa += *d; 01291 *d = - *d; 01292 } 01293 if (*d > 360) /* full circle */ 01294 *d = 360; 01295 *sa = NormalizeAngle (*sa); 01296 } 01297 01298 static int 01299 radius_crosses_arc (double x, double y, ArcType *arc) 01300 { 01301 double alpha = atan2 (y - arc->Y, -x + arc->X) * RAD_TO_DEG; 01302 Angle sa = arc->StartAngle, d = arc->Delta; 01303 01304 normalize_angles (&sa, &d); 01305 if (alpha < 0) 01306 alpha += 360; 01307 if (sa <= alpha) 01308 return (sa + d) >= alpha; 01309 return (sa + d - 360) >= alpha; 01310 } 01311 01312 static void 01313 get_arc_ends (Coord *box, ArcType *arc) 01314 { 01315 box[0] = arc->X - arc->Width * cos (M180 * arc->StartAngle); 01316 box[1] = arc->Y + arc->Height * sin (M180 * arc->StartAngle); 01317 box[2] = arc->X - arc->Width * cos (M180 * (arc->StartAngle + arc->Delta)); 01318 box[3] = arc->Y + arc->Height * sin (M180 * (arc->StartAngle + arc->Delta)); 01319 } 01320 01346 static bool 01347 ArcArcIntersect (ArcType *Arc1, ArcType *Arc2) 01348 { 01349 double x, y, dx, dy, r1, r2, a, d, l, t, t1, t2, dl; 01350 Coord pdx, pdy; 01351 Coord box[8]; 01352 01353 t = 0.5 * Arc1->Thickness + Bloat; 01354 t2 = 0.5 * Arc2->Thickness; 01355 t1 = t2 + Bloat; 01356 01357 /* too thin arc */ 01358 if (t < 0 || t1 < 0) 01359 return false; 01360 01361 /* try the end points first */ 01362 get_arc_ends (&box[0], Arc1); 01363 get_arc_ends (&box[4], Arc2); 01364 if (IsPointOnArc (box[0], box[1], t, Arc2) 01365 || IsPointOnArc (box[2], box[3], t, Arc2) 01366 || IsPointOnArc (box[4], box[5], t, Arc1) 01367 || IsPointOnArc (box[6], box[7], t, Arc1)) 01368 return true; 01369 01370 pdx = Arc2->X - Arc1->X; 01371 pdy = Arc2->Y - Arc1->Y; 01372 dl = Distance (Arc1->X, Arc1->Y, Arc2->X, Arc2->Y); 01373 /* concentric arcs, simpler intersection conditions */ 01374 if (dl < 0.5) 01375 { 01376 if ((Arc1->Width - t >= Arc2->Width - t2 01377 && Arc1->Width - t <= Arc2->Width + t2) 01378 || (Arc1->Width + t >= Arc2->Width - t2 01379 && Arc1->Width + t <= Arc2->Width + t2)) 01380 { 01381 Angle sa1 = Arc1->StartAngle, d1 = Arc1->Delta; 01382 Angle sa2 = Arc2->StartAngle, d2 = Arc2->Delta; 01383 /* NB the endpoints have already been checked, 01384 so we just compare the angles */ 01385 01386 normalize_angles (&sa1, &d1); 01387 normalize_angles (&sa2, &d2); 01388 /* sa1 == sa2 was caught when checking endpoints */ 01389 if (sa1 > sa2) 01390 if (sa1 < sa2 + d2 || sa1 + d1 - 360 > sa2) 01391 return true; 01392 if (sa2 > sa1) 01393 if (sa2 < sa1 + d1 || sa2 + d2 - 360 > sa1) 01394 return true; 01395 } 01396 return false; 01397 } 01398 r1 = Arc1->Width; 01399 r2 = Arc2->Width; 01400 /* arcs centerlines are too far or too near */ 01401 if (dl > r1 + r2 || dl + r1 < r2 || dl + r2 < r1) 01402 { 01403 /* check the nearest to the other arc's center point */ 01404 dx = pdx * r1 / dl; 01405 dy = pdy * r1 / dl; 01406 if (dl + r1 < r2) /* Arc1 inside Arc2 */ 01407 { 01408 dx = - dx; 01409 dy = - dy; 01410 } 01411 01412 if (radius_crosses_arc (Arc1->X + dx, Arc1->Y + dy, Arc1) 01413 && IsPointOnArc (Arc1->X + dx, Arc1->Y + dy, t, Arc2)) 01414 return true; 01415 01416 dx = - pdx * r2 / dl; 01417 dy = - pdy * r2 / dl; 01418 if (dl + r2 < r1) /* Arc2 inside Arc1 */ 01419 { 01420 dx = - dx; 01421 dy = - dy; 01422 } 01423 01424 if (radius_crosses_arc (Arc2->X + dx, Arc2->Y + dy, Arc2) 01425 && IsPointOnArc (Arc2->X + dx, Arc2->Y + dy, t1, Arc1)) 01426 return true; 01427 return false; 01428 } 01429 01430 l = dl * dl; 01431 r1 *= r1; 01432 r2 *= r2; 01433 a = 0.5 * (r1 - r2 + l) / l; 01434 r1 = r1 / l; 01435 d = r1 - a * a; 01436 /* the circles are too far apart to touch or probably just touch: 01437 check the nearest point */ 01438 if (d < 0) 01439 d = 0; 01440 else 01441 d = sqrt (d); 01442 x = Arc1->X + a * pdx; 01443 y = Arc1->Y + a * pdy; 01444 dx = d * pdx; 01445 dy = d * pdy; 01446 if (radius_crosses_arc (x + dy, y - dx, Arc1) 01447 && IsPointOnArc (x + dy, y - dx, t, Arc2)) 01448 return true; 01449 if (radius_crosses_arc (x + dy, y - dx, Arc2) 01450 && IsPointOnArc (x + dy, y - dx, t1, Arc1)) 01451 return true; 01452 01453 if (radius_crosses_arc (x - dy, y + dx, Arc1) 01454 && IsPointOnArc (x - dy, y + dx, t, Arc2)) 01455 return true; 01456 if (radius_crosses_arc (x - dy, y + dx, Arc2) 01457 && IsPointOnArc (x - dy, y + dx, t1, Arc1)) 01458 return true; 01459 return false; 01460 } 01461 01465 static bool 01466 IsRatPointOnLineEnd (PointType *Point, LineType *Line) 01467 { 01468 if ((Point->X == Line->Point1.X 01469 && Point->Y == Line->Point1.Y) 01470 || (Point->X == Line->Point2.X && Point->Y == Line->Point2.Y)) 01471 return (true); 01472 return (false); 01473 } 01474 01478 static void 01479 form_slanted_rectangle (PointType p[4], LineType *l) 01480 { 01481 double dwx = 0, dwy = 0; 01482 if (l->Point1.Y == l->Point2.Y) 01483 dwx = l->Thickness / 2.0; 01484 else if (l->Point1.X == l->Point2.X) 01485 dwy = l->Thickness / 2.0; 01486 else 01487 { 01488 Coord dX = l->Point2.X - l->Point1.X; 01489 Coord dY = l->Point2.Y - l->Point1.Y; 01490 double r = Distance (l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y); 01491 dwx = l->Thickness / 2.0 / r * dX; 01492 dwy = l->Thickness / 2.0 / r * dY; 01493 } 01494 p[0].X = l->Point1.X - dwx + dwy; p[0].Y = l->Point1.Y - dwy - dwx; 01495 p[1].X = l->Point1.X - dwx - dwy; p[1].Y = l->Point1.Y - dwy + dwx; 01496 p[2].X = l->Point2.X + dwx - dwy; p[2].Y = l->Point2.Y + dwy + dwx; 01497 p[3].X = l->Point2.X + dwx + dwy; p[3].Y = l->Point2.Y + dwy - dwx; 01498 } 01499 01563 bool 01564 LineLineIntersect (LineType *Line1, LineType *Line2) 01565 { 01566 double s, r; 01567 double line1_dx, line1_dy, line2_dx, line2_dy, 01568 point1_dx, point1_dy; 01569 if (TEST_FLAG (SQUAREFLAG, Line1))/* pretty reckless recursion */ 01570 { 01571 PointType p[4]; 01572 form_slanted_rectangle (p, Line1); 01573 return IsLineInQuadrangle (p, Line2); 01574 } 01575 /* here come only round Line1 because IsLineInQuadrangle() 01576 calls LineLineIntersect() with first argument rounded*/ 01577 if (TEST_FLAG (SQUAREFLAG, Line2)) 01578 { 01579 PointType p[4]; 01580 form_slanted_rectangle (p, Line2); 01581 return IsLineInQuadrangle (p, Line1); 01582 } 01583 /* now all lines are round */ 01584 01585 /* Check endpoints: this provides a quick exit, catches 01586 * cases where the "real" lines don't intersect but the 01587 * thick lines touch, and ensures that the dx/dy business 01588 * below does not cause a divide-by-zero. */ 01589 if (IsPointInPad (Line2->Point1.X, Line2->Point1.Y, 01590 MAX (Line2->Thickness / 2 + Bloat, 0), 01591 (PadType *) Line1) 01592 || IsPointInPad (Line2->Point2.X, Line2->Point2.Y, 01593 MAX (Line2->Thickness / 2 + Bloat, 0), 01594 (PadType *) Line1) 01595 || IsPointInPad (Line1->Point1.X, Line1->Point1.Y, 01596 MAX (Line1->Thickness / 2 + Bloat, 0), 01597 (PadType *) Line2) 01598 || IsPointInPad (Line1->Point2.X, Line1->Point2.Y, 01599 MAX (Line1->Thickness / 2 + Bloat, 0), 01600 (PadType *) Line2)) 01601 return true; 01602 01603 /* setup some constants */ 01604 line1_dx = Line1->Point2.X - Line1->Point1.X; 01605 line1_dy = Line1->Point2.Y - Line1->Point1.Y; 01606 line2_dx = Line2->Point2.X - Line2->Point1.X; 01607 line2_dy = Line2->Point2.Y - Line2->Point1.Y; 01608 point1_dx = Line1->Point1.X - Line2->Point1.X; 01609 point1_dy = Line1->Point1.Y - Line2->Point1.Y; 01610 01611 /* If either line is a point, we have failed already, since the 01612 * endpoint check above will have caught an "intersection". */ 01613 if ((line1_dx == 0 && line1_dy == 0) 01614 || (line2_dx == 0 && line2_dy == 0)) 01615 return false; 01616 01617 /* set s to cross product of Line1 and the line 01618 * Line1.Point1--Line2.Point1 (as vectors) */ 01619 s = point1_dy * line1_dx - point1_dx * line1_dy; 01620 01621 /* set r to cross product of both lines (as vectors) */ 01622 r = line1_dx * line2_dy - line1_dy * line2_dx; 01623 01624 /* No cross product means parallel lines, or maybe Line2 is 01625 * zero-length. In either case, since we did a bounding-box 01626 * check before getting here, the above IsPointInPad() checks 01627 * will have caught any intersections. */ 01628 if (r == 0.0) 01629 return false; 01630 01631 s /= r; 01632 r = (point1_dy * line2_dx - point1_dx * line2_dy) / r; 01633 01634 /* intersection is at least on AB */ 01635 if (r >= 0.0 && r <= 1.0) 01636 return (s >= 0.0 && s <= 1.0); 01637 01638 /* intersection is at least on CD */ 01639 /* [removed this case since it always returns false --asp] */ 01640 return false; 01641 } 01642 01673 bool 01674 LineArcIntersect (LineType *Line, ArcType *Arc) 01675 { 01676 double dx, dy, dx1, dy1, l, d, r, r2, Radius; 01677 BoxType *box; 01678 01679 dx = Line->Point2.X - Line->Point1.X; 01680 dy = Line->Point2.Y - Line->Point1.Y; 01681 dx1 = Line->Point1.X - Arc->X; 01682 dy1 = Line->Point1.Y - Arc->Y; 01683 l = dx * dx + dy * dy; 01684 d = dx * dy1 - dy * dx1; 01685 d *= d; 01686 01687 /* use the larger diameter circle first */ 01688 Radius = 01689 Arc->Width + MAX (0.5 * (Arc->Thickness + Line->Thickness) + Bloat, 0.0); 01690 Radius *= Radius; 01691 r2 = Radius * l - d; 01692 /* projection doesn't even intersect circle when r2 < 0 */ 01693 if (r2 < 0) 01694 return (false); 01695 /* check the ends of the line in case the projected point */ 01696 /* of intersection is beyond the line end */ 01697 if (IsPointOnArc 01698 (Line->Point1.X, Line->Point1.Y, 01699 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc)) 01700 return (true); 01701 if (IsPointOnArc 01702 (Line->Point2.X, Line->Point2.Y, 01703 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc)) 01704 return (true); 01705 if (l == 0.0) 01706 return (false); 01707 r2 = sqrt (r2); 01708 Radius = -(dx * dx1 + dy * dy1); 01709 r = (Radius + r2) / l; 01710 if (r >= 0 && r <= 1 01711 && IsPointOnArc (Line->Point1.X + r * dx, 01712 Line->Point1.Y + r * dy, 01713 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc)) 01714 return (true); 01715 r = (Radius - r2) / l; 01716 if (r >= 0 && r <= 1 01717 && IsPointOnArc (Line->Point1.X + r * dx, 01718 Line->Point1.Y + r * dy, 01719 MAX (0.5 * Line->Thickness + Bloat, 0.0), Arc)) 01720 return (true); 01721 /* check arc end points */ 01722 box = GetArcEnds (Arc); 01723 if (IsPointInPad (box->X1, box->Y1, Arc->Thickness * 0.5 + Bloat, (PadType *)Line)) 01724 return true; 01725 if (IsPointInPad (box->X2, box->Y2, Arc->Thickness * 0.5 + Bloat, (PadType *)Line)) 01726 return true; 01727 return false; 01728 } 01729 01730 static int 01731 LOCtoArcLine_callback (const BoxType * b, void *cl) 01732 { 01733 LineType *line = (LineType *) b; 01734 struct lo_info *i = (struct lo_info *) cl; 01735 01736 if (!TEST_FLAG (i->flag, line) && LineArcIntersect (line, i->arc)) 01737 { 01738 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 01739 longjmp (i->env, 1); 01740 } 01741 return 0; 01742 } 01743 01744 static int 01745 LOCtoArcArc_callback (const BoxType * b, void *cl) 01746 { 01747 ArcType *arc = (ArcType *) b; 01748 struct lo_info *i = (struct lo_info *) cl; 01749 01750 if (!arc->Thickness) 01751 return 0; 01752 if (!TEST_FLAG (i->flag, arc) && ArcArcIntersect (i->arc, arc)) 01753 { 01754 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag)) 01755 longjmp (i->env, 1); 01756 } 01757 return 0; 01758 } 01759 01760 static int 01761 LOCtoArcPad_callback (const BoxType * b, void *cl) 01762 { 01763 PadType *pad = (PadType *) b; 01764 struct lo_info *i = (struct lo_info *) cl; 01765 01766 if (!TEST_FLAG (i->flag, pad) && i->layer == 01767 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) 01768 && ArcPadIntersect (i->arc, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag)) 01769 longjmp (i->env, 1); 01770 return 0; 01771 } 01772 01782 static bool 01783 LookupLOConnectionsToArc (ArcType *Arc, Cardinal LayerGroup, int flag, bool AndRats) 01784 { 01785 Cardinal entry; 01786 struct lo_info info; 01787 BoxType search_box; 01788 01789 info.flag = flag; 01790 info.arc = Arc; 01791 search_box = expand_bounds ((BoxType *)info.arc); 01792 01793 /* loop over all layers of the group */ 01794 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) 01795 { 01796 Cardinal layer_no; 01797 LayerType *layer; 01798 GList *i; 01799 01800 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry]; 01801 layer = LAYER_PTR (layer_no); 01802 01803 /* handle normal layers */ 01804 if (layer_no < max_copper_layer) 01805 { 01806 info.layer = layer_no; 01807 /* add arcs */ 01808 if (setjmp (info.env) == 0) 01809 r_search (layer->line_tree, &search_box, 01810 NULL, LOCtoArcLine_callback, &info); 01811 else 01812 return true; 01813 01814 if (setjmp (info.env) == 0) 01815 r_search (layer->arc_tree, &search_box, 01816 NULL, LOCtoArcArc_callback, &info); 01817 else 01818 return true; 01819 01820 /* now check all polygons */ 01821 for (i = layer->Polygon; i != NULL; i = g_list_next (i)) 01822 { 01823 PolygonType *polygon = i->data; 01824 if (!TEST_FLAG (flag, polygon) && IsArcInPolygon (Arc, polygon) 01825 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag)) 01826 return true; 01827 } 01828 } 01829 else 01830 { 01831 info.layer = layer_no - max_copper_layer; 01832 if (setjmp (info.env) == 0) 01833 r_search (PCB->Data->pad_tree, &search_box, NULL, 01834 LOCtoArcPad_callback, &info); 01835 else 01836 return true; 01837 } 01838 } 01839 return (false); 01840 } 01841 01842 static int 01843 LOCtoLineLine_callback (const BoxType * b, void *cl) 01844 { 01845 LineType *line = (LineType *) b; 01846 struct lo_info *i = (struct lo_info *) cl; 01847 01848 if (!TEST_FLAG (i->flag, line) && LineLineIntersect (i->line, line)) 01849 { 01850 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 01851 longjmp (i->env, 1); 01852 } 01853 return 0; 01854 } 01855 01856 static int 01857 LOCtoLineArc_callback (const BoxType * b, void *cl) 01858 { 01859 ArcType *arc = (ArcType *) b; 01860 struct lo_info *i = (struct lo_info *) cl; 01861 01862 if (!arc->Thickness) 01863 return 0; 01864 if (!TEST_FLAG (i->flag, arc) && LineArcIntersect (i->line, arc)) 01865 { 01866 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag)) 01867 longjmp (i->env, 1); 01868 } 01869 return 0; 01870 } 01871 01872 static int 01873 LOCtoLineRat_callback (const BoxType * b, void *cl) 01874 { 01875 RatType *rat = (RatType *) b; 01876 struct lo_info *i = (struct lo_info *) cl; 01877 01878 if (!TEST_FLAG (i->flag, rat)) 01879 { 01880 if ((rat->group1 == i->layer) 01881 && IsRatPointOnLineEnd (&rat->Point1, i->line)) 01882 { 01883 if (ADD_RAT_TO_LIST (rat, i->flag)) 01884 longjmp (i->env, 1); 01885 } 01886 else if ((rat->group2 == i->layer) 01887 && IsRatPointOnLineEnd (&rat->Point2, i->line)) 01888 { 01889 if (ADD_RAT_TO_LIST (rat, i->flag)) 01890 longjmp (i->env, 1); 01891 } 01892 } 01893 return 0; 01894 } 01895 01896 static int 01897 LOCtoLinePad_callback (const BoxType * b, void *cl) 01898 { 01899 PadType *pad = (PadType *) b; 01900 struct lo_info *i = (struct lo_info *) cl; 01901 01902 if (!TEST_FLAG (i->flag, pad) && i->layer == 01903 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) 01904 && LinePadIntersect (i->line, pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag)) 01905 longjmp (i->env, 1); 01906 return 0; 01907 } 01908 01918 static bool 01919 LookupLOConnectionsToLine (LineType *Line, Cardinal LayerGroup, 01920 int flag, bool PolysTo, bool AndRats) 01921 { 01922 Cardinal entry; 01923 struct lo_info info; 01924 BoxType search_box; 01925 01926 info.flag = flag; 01927 info.layer = LayerGroup; 01928 info.line = Line; 01929 search_box = expand_bounds ((BoxType *)info.line); 01930 01931 if (AndRats) 01932 { 01933 /* add the new rat lines */ 01934 if (setjmp (info.env) == 0) 01935 r_search (PCB->Data->rat_tree, &search_box, NULL, 01936 LOCtoLineRat_callback, &info); 01937 else 01938 return true; 01939 } 01940 01941 /* loop over all layers of the group */ 01942 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) 01943 { 01944 Cardinal layer_no; 01945 LayerType *layer; 01946 01947 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry]; 01948 layer = LAYER_PTR (layer_no); 01949 01950 /* handle normal layers */ 01951 if (layer_no < max_copper_layer) 01952 { 01953 info.layer = layer_no; 01954 /* add lines */ 01955 if (setjmp (info.env) == 0) 01956 r_search (layer->line_tree, &search_box, 01957 NULL, LOCtoLineLine_callback, &info); 01958 else 01959 return true; 01960 /* add arcs */ 01961 if (setjmp (info.env) == 0) 01962 r_search (layer->arc_tree, &search_box, 01963 NULL, LOCtoLineArc_callback, &info); 01964 else 01965 return true; 01966 /* now check all polygons */ 01967 if (PolysTo) 01968 { 01969 GList *i; 01970 for (i = layer->Polygon; i != NULL; i = g_list_next (i)) 01971 { 01972 PolygonType *polygon = i->data; 01973 if (!TEST_FLAG (flag, polygon) && IsLineInPolygon (Line, polygon) 01974 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag)) 01975 return true; 01976 } 01977 } 01978 } 01979 else 01980 { 01981 /* handle special 'pad' layers */ 01982 info.layer = layer_no - max_copper_layer; 01983 if (setjmp (info.env) == 0) 01984 r_search (PCB->Data->pad_tree, &search_box, NULL, 01985 LOCtoLinePad_callback, &info); 01986 else 01987 return true; 01988 } 01989 } 01990 return (false); 01991 } 01992 01993 struct rat_info 01994 { 01995 Cardinal layer; 01996 PointType *Point; 01997 int flag; 01998 jmp_buf env; 01999 }; 02000 02001 static int 02002 LOCtoRat_callback (const BoxType * b, void *cl) 02003 { 02004 LineType *line = (LineType *) b; 02005 struct rat_info *i = (struct rat_info *) cl; 02006 02007 if (!TEST_FLAG (i->flag, line) && 02008 ((line->Point1.X == i->Point->X && 02009 line->Point1.Y == i->Point->Y) || 02010 (line->Point2.X == i->Point->X && line->Point2.Y == i->Point->Y))) 02011 { 02012 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 02013 longjmp (i->env, 1); 02014 } 02015 return 0; 02016 } 02017 static int 02018 PolygonToRat_callback (const BoxType * b, void *cl) 02019 { 02020 PolygonType *polygon = (PolygonType *) b; 02021 struct rat_info *i = (struct rat_info *) cl; 02022 02023 if (!TEST_FLAG (i->flag, polygon) && polygon->Clipped && 02024 (i->Point->X == polygon->Clipped->contours->head.point[0]) && 02025 (i->Point->Y == polygon->Clipped->contours->head.point[1])) 02026 { 02027 if (ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag)) 02028 longjmp (i->env, 1); 02029 } 02030 return 0; 02031 } 02032 02033 static int 02034 LOCtoPad_callback (const BoxType * b, void *cl) 02035 { 02036 PadType *pad = (PadType *) b; 02037 struct rat_info *i = (struct rat_info *) cl; 02038 02039 if (!TEST_FLAG (i->flag, pad) && i->layer == 02040 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) && 02041 ((pad->Point1.X == i->Point->X && pad->Point1.Y == i->Point->Y) || 02042 (pad->Point2.X == i->Point->X && pad->Point2.Y == i->Point->Y) || 02043 ((pad->Point1.X + pad->Point2.X) / 2 == i->Point->X && 02044 (pad->Point1.Y + pad->Point2.Y) / 2 == i->Point->Y)) && 02045 ADD_PAD_TO_LIST (i->layer, pad, i->flag)) 02046 longjmp (i->env, 1); 02047 return 0; 02048 } 02049 02059 static bool 02060 LookupLOConnectionsToRatEnd (PointType *Point, Cardinal LayerGroup, int flag) 02061 { 02062 Cardinal entry; 02063 struct rat_info info; 02064 02065 info.flag = flag; 02066 info.Point = Point; 02067 /* loop over all layers of this group */ 02068 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) 02069 { 02070 Cardinal layer_no; 02071 LayerType *layer; 02072 02073 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry]; 02074 layer = LAYER_PTR (layer_no); 02075 /* handle normal layers 02076 rats don't ever touch 02077 arcs by definition 02078 */ 02079 02080 if (layer_no < max_copper_layer) 02081 { 02082 info.layer = layer_no; 02083 if (setjmp (info.env) == 0) 02084 r_search_pt (layer->line_tree, Point, 1, NULL, 02085 LOCtoRat_callback, &info); 02086 else 02087 return true; 02088 if (setjmp (info.env) == 0) 02089 r_search_pt (layer->polygon_tree, Point, 1, 02090 NULL, PolygonToRat_callback, &info); 02091 } 02092 else 02093 { 02094 /* handle special 'pad' layers */ 02095 info.layer = layer_no - max_copper_layer; 02096 if (setjmp (info.env) == 0) 02097 r_search_pt (PCB->Data->pad_tree, Point, 1, NULL, 02098 LOCtoPad_callback, &info); 02099 else 02100 return true; 02101 } 02102 } 02103 return (false); 02104 } 02105 02106 static int 02107 LOCtoPadLine_callback (const BoxType * b, void *cl) 02108 { 02109 LineType *line = (LineType *) b; 02110 struct lo_info *i = (struct lo_info *) cl; 02111 02112 if (!TEST_FLAG (i->flag, line) && LinePadIntersect (line, i->pad)) 02113 { 02114 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 02115 longjmp (i->env, 1); 02116 } 02117 return 0; 02118 } 02119 02120 static int 02121 LOCtoPadArc_callback (const BoxType * b, void *cl) 02122 { 02123 ArcType *arc = (ArcType *) b; 02124 struct lo_info *i = (struct lo_info *) cl; 02125 02126 if (!arc->Thickness) 02127 return 0; 02128 if (!TEST_FLAG (i->flag, arc) && ArcPadIntersect (arc, i->pad)) 02129 { 02130 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag)) 02131 longjmp (i->env, 1); 02132 } 02133 return 0; 02134 } 02135 02136 static int 02137 LOCtoPadPoly_callback (const BoxType * b, void *cl) 02138 { 02139 PolygonType *polygon = (PolygonType *) b; 02140 struct lo_info *i = (struct lo_info *) cl; 02141 02142 02143 if (!TEST_FLAG (i->flag, polygon) && 02144 (!TEST_FLAG (CLEARPOLYFLAG, polygon) || !i->pad->Clearance)) 02145 { 02146 if (IsPadInPolygon (i->pad, polygon) && 02147 ADD_POLYGON_TO_LIST (i->layer, polygon, i->flag)) 02148 longjmp (i->env, 1); 02149 } 02150 return 0; 02151 } 02152 02153 static int 02154 LOCtoPadRat_callback (const BoxType * b, void *cl) 02155 { 02156 RatType *rat = (RatType *) b; 02157 struct lo_info *i = (struct lo_info *) cl; 02158 02159 if (!TEST_FLAG (i->flag, rat)) 02160 { 02161 if (rat->group1 == i->layer && 02162 ((rat->Point1.X == i->pad->Point1.X && rat->Point1.Y == i->pad->Point1.Y) || 02163 (rat->Point1.X == i->pad->Point2.X && rat->Point1.Y == i->pad->Point2.Y) || 02164 (rat->Point1.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 && 02165 rat->Point1.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2))) 02166 { 02167 if (ADD_RAT_TO_LIST (rat, i->flag)) 02168 longjmp (i->env, 1); 02169 } 02170 else if (rat->group2 == i->layer && 02171 ((rat->Point2.X == i->pad->Point1.X && rat->Point2.Y == i->pad->Point1.Y) || 02172 (rat->Point2.X == i->pad->Point2.X && rat->Point2.Y == i->pad->Point2.Y) || 02173 (rat->Point2.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 && 02174 rat->Point2.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2))) 02175 { 02176 if (ADD_RAT_TO_LIST (rat, i->flag)) 02177 longjmp (i->env, 1); 02178 } 02179 } 02180 return 0; 02181 } 02182 02183 static int 02184 LOCtoPadPad_callback (const BoxType * b, void *cl) 02185 { 02186 PadType *pad = (PadType *) b; 02187 struct lo_info *i = (struct lo_info *) cl; 02188 02189 if (!TEST_FLAG (i->flag, pad) && i->layer == 02190 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) 02191 && PadPadIntersect (pad, i->pad) && ADD_PAD_TO_LIST (i->layer, pad, i->flag)) 02192 longjmp (i->env, 1); 02193 return 0; 02194 } 02195 02202 static bool 02203 LookupLOConnectionsToPad (PadType *Pad, Cardinal LayerGroup, int flag, bool AndRats) 02204 { 02205 Cardinal entry; 02206 struct lo_info info; 02207 BoxType search_box; 02208 02209 if (!TEST_FLAG (SQUAREFLAG, Pad)) 02210 return (LookupLOConnectionsToLine ((LineType *) Pad, LayerGroup, flag, false, AndRats)); 02211 02212 info.flag = flag; 02213 info.pad = Pad; 02214 search_box = expand_bounds ((BoxType *)info.pad); 02215 02216 /* add the new rat lines */ 02217 info.layer = LayerGroup; 02218 02219 if (AndRats) 02220 { 02221 if (setjmp (info.env) == 0) 02222 r_search (PCB->Data->rat_tree, &search_box, NULL, 02223 LOCtoPadRat_callback, &info); 02224 else 02225 return true; 02226 } 02227 02228 /* loop over all layers of the group */ 02229 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) 02230 { 02231 Cardinal layer_no; 02232 LayerType *layer; 02233 02234 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry]; 02235 layer = LAYER_PTR (layer_no); 02236 /* handle normal layers */ 02237 if (layer_no < max_copper_layer) 02238 { 02239 info.layer = layer_no; 02240 /* add lines */ 02241 if (setjmp (info.env) == 0) 02242 r_search (layer->line_tree, &search_box, 02243 NULL, LOCtoPadLine_callback, &info); 02244 else 02245 return true; 02246 /* add arcs */ 02247 if (setjmp (info.env) == 0) 02248 r_search (layer->arc_tree, &search_box, 02249 NULL, LOCtoPadArc_callback, &info); 02250 else 02251 return true; 02252 /* add polygons */ 02253 if (setjmp (info.env) == 0) 02254 r_search (layer->polygon_tree, &search_box, 02255 NULL, LOCtoPadPoly_callback, &info); 02256 else 02257 return true; 02258 } 02259 else 02260 { 02261 /* handle special 'pad' layers */ 02262 info.layer = layer_no - max_copper_layer; 02263 if (setjmp (info.env) == 0) 02264 r_search (PCB->Data->pad_tree, &search_box, NULL, 02265 LOCtoPadPad_callback, &info); 02266 else 02267 return true; 02268 } 02269 02270 } 02271 return (false); 02272 } 02273 02274 static int 02275 LOCtoPolyLine_callback (const BoxType * b, void *cl) 02276 { 02277 LineType *line = (LineType *) b; 02278 struct lo_info *i = (struct lo_info *) cl; 02279 02280 if (!TEST_FLAG (i->flag, line) && IsLineInPolygon (line, i->polygon)) 02281 { 02282 if (ADD_LINE_TO_LIST (i->layer, line, i->flag)) 02283 longjmp (i->env, 1); 02284 } 02285 return 0; 02286 } 02287 02288 static int 02289 LOCtoPolyArc_callback (const BoxType * b, void *cl) 02290 { 02291 ArcType *arc = (ArcType *) b; 02292 struct lo_info *i = (struct lo_info *) cl; 02293 02294 if (!arc->Thickness) 02295 return 0; 02296 if (!TEST_FLAG (i->flag, arc) && IsArcInPolygon (arc, i->polygon)) 02297 { 02298 if (ADD_ARC_TO_LIST (i->layer, arc, i->flag)) 02299 longjmp (i->env, 1); 02300 } 02301 return 0; 02302 } 02303 02304 static int 02305 LOCtoPolyPad_callback (const BoxType * b, void *cl) 02306 { 02307 PadType *pad = (PadType *) b; 02308 struct lo_info *i = (struct lo_info *) cl; 02309 02310 if (!TEST_FLAG (i->flag, pad) && i->layer == 02311 (TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE) 02312 && IsPadInPolygon (pad, i->polygon)) 02313 { 02314 if (ADD_PAD_TO_LIST (i->layer, pad, i->flag)) 02315 longjmp (i->env, 1); 02316 } 02317 return 0; 02318 } 02319 02320 static int 02321 LOCtoPolyRat_callback (const BoxType * b, void *cl) 02322 { 02323 RatType *rat = (RatType *) b; 02324 struct lo_info *i = (struct lo_info *) cl; 02325 02326 if (!TEST_FLAG (i->flag, rat)) 02327 { 02328 if ((rat->Point1.X == (i->polygon->Clipped->contours->head.point[0]) && 02329 rat->Point1.Y == (i->polygon->Clipped->contours->head.point[1]) && 02330 rat->group1 == i->layer) || 02331 (rat->Point2.X == (i->polygon->Clipped->contours->head.point[0]) && 02332 rat->Point2.Y == (i->polygon->Clipped->contours->head.point[1]) && 02333 rat->group2 == i->layer)) 02334 if (ADD_RAT_TO_LIST (rat, i->flag)) 02335 longjmp (i->env, 1); 02336 } 02337 return 0; 02338 } 02339 02340 02347 static bool 02348 LookupLOConnectionsToPolygon (PolygonType *Polygon, Cardinal LayerGroup, int flag, bool AndRats) 02349 { 02350 Cardinal entry; 02351 struct lo_info info; 02352 BoxType search_box; 02353 02354 if (!Polygon->Clipped) 02355 return false; 02356 02357 info.flag = flag; 02358 info.polygon = Polygon; 02359 search_box = expand_bounds ((BoxType *)info.polygon); 02360 02361 info.layer = LayerGroup; 02362 02363 /* check rats */ 02364 if (AndRats) 02365 { 02366 if (setjmp (info.env) == 0) 02367 r_search (PCB->Data->rat_tree, &search_box, NULL, 02368 LOCtoPolyRat_callback, &info); 02369 else 02370 return true; 02371 } 02372 02373 /* loop over all layers of the group */ 02374 for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++) 02375 { 02376 Cardinal layer_no; 02377 LayerType *layer; 02378 02379 layer_no = PCB->LayerGroups.Entries[LayerGroup][entry]; 02380 layer = LAYER_PTR (layer_no); 02381 02382 /* handle normal layers */ 02383 if (layer_no < max_copper_layer) 02384 { 02385 GList *i; 02386 02387 /* check all polygons */ 02388 for (i = layer->Polygon; i != NULL; i = g_list_next (i)) 02389 { 02390 PolygonType *polygon = i->data; 02391 if (!TEST_FLAG (flag, polygon) 02392 && IsPolygonInPolygon (polygon, Polygon) 02393 && ADD_POLYGON_TO_LIST (layer_no, polygon, flag)) 02394 return true; 02395 } 02396 02397 info.layer = layer_no; 02398 /* check all lines */ 02399 if (setjmp (info.env) == 0) 02400 r_search (layer->line_tree, &search_box, 02401 NULL, LOCtoPolyLine_callback, &info); 02402 else 02403 return true; 02404 /* check all arcs */ 02405 if (setjmp (info.env) == 0) 02406 r_search (layer->arc_tree, &search_box, 02407 NULL, LOCtoPolyArc_callback, &info); 02408 else 02409 return true; 02410 } 02411 else 02412 { 02413 info.layer = layer_no - max_copper_layer; 02414 if (setjmp (info.env) == 0) 02415 r_search (PCB->Data->pad_tree, &search_box, 02416 NULL, LOCtoPolyPad_callback, &info); 02417 else 02418 return true; 02419 } 02420 } 02421 return (false); 02422 } 02423 02432 static bool 02433 IsArcInPolygon (ArcType *Arc, PolygonType *Polygon) 02434 { 02435 BoxType *Box = (BoxType *) Arc; 02436 02437 /* arcs with clearance never touch polys */ 02438 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Arc)) 02439 return false; 02440 if (!Polygon->Clipped) 02441 return false; 02442 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat 02443 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat 02444 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat 02445 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat) 02446 { 02447 POLYAREA *ap; 02448 02449 if (!(ap = ArcPoly (Arc, Arc->Thickness + Bloat))) 02450 return false; /* error */ 02451 return isects (ap, Polygon, true); 02452 } 02453 return false; 02454 } 02455 02464 static bool 02465 IsLineInPolygon (LineType *Line, PolygonType *Polygon) 02466 { 02467 BoxType *Box = (BoxType *) Line; 02468 POLYAREA *lp; 02469 02470 /* lines with clearance never touch polygons */ 02471 if (TEST_FLAG (CLEARPOLYFLAG, Polygon) && TEST_FLAG (CLEARLINEFLAG, Line)) 02472 return false; 02473 if (!Polygon->Clipped) 02474 return false; 02475 if (TEST_FLAG(SQUAREFLAG,Line)&&(Line->Point1.X==Line->Point2.X||Line->Point1.Y==Line->Point2.Y)) 02476 { 02477 Coord wid = (Line->Thickness + Bloat + 1) / 2; 02478 Coord x1, x2, y1, y2; 02479 02480 x1 = MIN (Line->Point1.X, Line->Point2.X) - wid; 02481 y1 = MIN (Line->Point1.Y, Line->Point2.Y) - wid; 02482 x2 = MAX (Line->Point1.X, Line->Point2.X) + wid; 02483 y2 = MAX (Line->Point1.Y, Line->Point2.Y) + wid; 02484 return IsRectangleInPolygon (x1, y1, x2, y2, Polygon); 02485 } 02486 if (Box->X1 <= Polygon->Clipped->contours->xmax + Bloat 02487 && Box->X2 >= Polygon->Clipped->contours->xmin - Bloat 02488 && Box->Y1 <= Polygon->Clipped->contours->ymax + Bloat 02489 && Box->Y2 >= Polygon->Clipped->contours->ymin - Bloat) 02490 { 02491 if (!(lp = LinePoly (Line, Line->Thickness + Bloat))) 02492 return FALSE; /* error */ 02493 return isects (lp, Polygon, true); 02494 } 02495 return false; 02496 } 02497 02503 static bool 02504 IsPadInPolygon (PadType *pad, PolygonType *polygon) 02505 { 02506 return IsLineInPolygon ((LineType *) pad, polygon); 02507 } 02508 02515 static bool 02516 IsPolygonInPolygon (PolygonType *P1, PolygonType *P2) 02517 { 02518 if (!P1->Clipped || !P2->Clipped) 02519 return false; 02520 assert (P1->Clipped->contours); 02521 assert (P2->Clipped->contours); 02522 02523 /* first check if both bounding boxes intersect. If not, return quickly */ 02524 if (P1->Clipped->contours->xmin - Bloat > P2->Clipped->contours->xmax || 02525 P1->Clipped->contours->xmax + Bloat < P2->Clipped->contours->xmin || 02526 P1->Clipped->contours->ymin - Bloat > P2->Clipped->contours->ymax || 02527 P1->Clipped->contours->ymax + Bloat < P2->Clipped->contours->ymin) 02528 return false; 02529 02530 /* first check un-bloated case */ 02531 if (isects (P1->Clipped, P2, false)) 02532 return TRUE; 02533 02534 /* now the difficult case of bloated */ 02535 if (Bloat > 0) 02536 { 02537 PLINE *c; 02538 for (c = P1->Clipped->contours; c; c = c->next) 02539 { 02540 LineType line; 02541 VNODE *v = &c->head; 02542 if (c->xmin - Bloat <= P2->Clipped->contours->xmax && 02543 c->xmax + Bloat >= P2->Clipped->contours->xmin && 02544 c->ymin - Bloat <= P2->Clipped->contours->ymax && 02545 c->ymax + Bloat >= P2->Clipped->contours->ymin) 02546 { 02547 02548 line.Point1.X = v->point[0]; 02549 line.Point1.Y = v->point[1]; 02550 line.Thickness = Bloat; 02551 /* Another Bloat is added by IsLineInPolygon, making the correct 02552 * 2x Bloat. Perhaps we should change it there, but doing so 02553 * breaks some other DRC checks which rely on the behaviour 02554 * in IsLineInPolygon. 02555 */ 02556 line.Clearance = 0; 02557 line.Flags = NoFlags (); 02558 for (v = v->next; v != &c->head; v = v->next) 02559 { 02560 line.Point2.X = v->point[0]; 02561 line.Point2.Y = v->point[1]; 02562 SetLineBoundingBox (&line); 02563 if (IsLineInPolygon (&line, P2)) 02564 return (true); 02565 line.Point1.X = line.Point2.X; 02566 line.Point1.Y = line.Point2.Y; 02567 } 02568 } 02569 } 02570 } 02571 02572 return (false); 02573 } 02574 02578 static void 02579 PrintElementNameList (ElementType *Element, FILE * FP) 02580 { 02581 static DynamicStringType cname, pname, vname; 02582 02583 CreateQuotedString (&cname, (char *)EMPTY (DESCRIPTION_NAME (Element))); 02584 CreateQuotedString (&pname, (char *)EMPTY (NAMEONPCB_NAME (Element))); 02585 CreateQuotedString (&vname, (char *)EMPTY (VALUE_NAME (Element))); 02586 fprintf (FP, "(%s %s %s)\n", cname.Data, pname.Data, vname.Data); 02587 } 02588 02592 static void 02593 PrintConnectionElementName (ElementType *Element, FILE * FP) 02594 { 02595 fputs ("Element", FP); 02596 PrintElementNameList (Element, FP); 02597 fputs ("{\n", FP); 02598 } 02599 02603 static void 02604 PrintConnectionListEntry (char *ObjName, ElementType *Element, 02605 bool FirstOne, FILE * FP) 02606 { 02607 static DynamicStringType oname; 02608 02609 CreateQuotedString (&oname, ObjName); 02610 if (FirstOne) 02611 fprintf (FP, "\t%s\n\t{\n", oname.Data); 02612 else 02613 { 02614 fprintf (FP, "\t\t%s ", oname.Data); 02615 if (Element) 02616 PrintElementNameList (Element, FP); 02617 else 02618 fputs ("(__VIA__)\n", FP); 02619 } 02620 } 02621 02626 static void 02627 PrintPadConnections (Cardinal Layer, FILE * FP, bool IsFirst) 02628 { 02629 Cardinal i; 02630 PadType *ptr; 02631 02632 if (!PadList[Layer].Number) 02633 return; 02634 02635 /* the starting pad */ 02636 if (IsFirst) 02637 { 02638 ptr = PADLIST_ENTRY (Layer, 0); 02639 if (ptr != NULL) 02640 PrintConnectionListEntry ((char *)UNKNOWN (ptr->Name), NULL, true, FP); 02641 else 02642 printf ("Skipping NULL ptr in 1st part of PrintPadConnections\n"); 02643 } 02644 02645 /* we maybe have to start with i=1 if we are handling the 02646 * starting-pad itself 02647 */ 02648 for (i = IsFirst ? 1 : 0; i < PadList[Layer].Number; i++) 02649 { 02650 ptr = PADLIST_ENTRY (Layer, i); 02651 if (ptr != NULL) 02652 PrintConnectionListEntry ((char *)EMPTY (ptr->Name), (ElementType *)ptr->Element, false, FP); 02653 else 02654 printf ("Skipping NULL ptr in 2nd part of PrintPadConnections\n"); 02655 } 02656 } 02657 02662 static void 02663 PrintPinConnections (FILE * FP, bool IsFirst) 02664 { 02665 Cardinal i; 02666 PinType *pv; 02667 02668 if (!PVList.Number) 02669 return; 02670 02671 if (IsFirst) 02672 { 02673 /* the starting pin */ 02674 pv = PVLIST_ENTRY (0); 02675 PrintConnectionListEntry ((char *)EMPTY (pv->Name), NULL, true, FP); 02676 } 02677 02678 /* we maybe have to start with i=1 if we are handling the 02679 * starting-pin itself 02680 */ 02681 for (i = IsFirst ? 1 : 0; i < PVList.Number; i++) 02682 { 02683 /* get the elements name or assume that its a via */ 02684 pv = PVLIST_ENTRY (i); 02685 PrintConnectionListEntry ((char *)EMPTY (pv->Name), (ElementType *)pv->Element, false, FP); 02686 } 02687 } 02688 02692 static bool 02693 ListsEmpty (bool AndRats) 02694 { 02695 bool empty; 02696 int i; 02697 02698 empty = (PVList.Location >= PVList.Number); 02699 if (AndRats) 02700 empty = empty && (RatList.Location >= RatList.Number); 02701 for (i = 0; i < max_copper_layer && empty; i++) 02702 if (!LAYER_PTR (i)->no_drc) 02703 empty = empty && LineList[i].Location >= LineList[i].Number 02704 && ArcList[i].Location >= ArcList[i].Number 02705 && PolygonList[i].Location >= PolygonList[i].Number; 02706 return (empty); 02707 } 02708 02709 static void 02710 reassign_no_drc_flags (void) 02711 { 02712 int layer; 02713 02714 for (layer = 0; layer < max_copper_layer; layer++) 02715 { 02716 LayerType *l = LAYER_PTR (layer); 02717 l->no_drc = AttributeGet (l, "PCB::skip-drc") != NULL; 02718 } 02719 } 02720 02721 02722 02723 02727 static bool 02728 DoIt (int flag, bool AndRats, bool AndDraw) 02729 { 02730 bool newone = false; 02731 reassign_no_drc_flags (); 02732 do 02733 { 02734 /* lookup connections; these are the steps (2) to (4) 02735 * from the description 02736 */ 02737 newone = LookupPVConnectionsToPVList (flag) || 02738 LookupLOConnectionsToPVList (flag, AndRats) || 02739 LookupLOConnectionsToLOList (flag, AndRats) || 02740 LookupPVConnectionsToLOList (flag, AndRats); 02741 if (AndDraw) 02742 DrawNewConnections (); 02743 } 02744 while (!newone && !ListsEmpty (AndRats)); 02745 if (AndDraw) 02746 Draw (); 02747 return (newone); 02748 } 02749 02753 static bool 02754 PrintAndSelectUnusedPinsAndPadsOfElement (ElementType *Element, FILE * FP, int flag) 02755 { 02756 bool first = true; 02757 Cardinal number; 02758 static DynamicStringType oname; 02759 02760 /* check all pins in element */ 02761 02762 PIN_LOOP (Element); 02763 { 02764 if (!TEST_FLAG (HOLEFLAG, pin)) 02765 { 02766 /* pin might have bee checked before, add to list if not */ 02767 if (!TEST_FLAG (flag, pin) && FP) 02768 { 02769 int i; 02770 if (ADD_PV_TO_LIST (pin, flag)) 02771 return true; 02772 DoIt (flag, true, true); 02773 number = PadList[TOP_SIDE].Number 02774 + PadList[BOTTOM_SIDE].Number + PVList.Number; 02775 /* the pin has no connection if it's the only 02776 * list entry; don't count vias 02777 */ 02778 for (i = 0; i < PVList.Number; i++) 02779 if (!PVLIST_ENTRY (i)->Element) 02780 number--; 02781 if (number == 1) 02782 { 02783 /* output of element name if not already done */ 02784 if (first) 02785 { 02786 PrintConnectionElementName (Element, FP); 02787 first = false; 02788 } 02789 02790 /* write name to list and draw selected object */ 02791 CreateQuotedString (&oname, (char *)EMPTY (pin->Name)); 02792 fprintf (FP, "\t%s\n", oname.Data); 02793 SET_FLAG (SELECTEDFLAG, pin); 02794 DrawPin (pin); 02795 } 02796 02797 /* reset found objects for the next pin */ 02798 if (PrepareNextLoop (FP)) 02799 return (true); 02800 } 02801 } 02802 } 02803 END_LOOP; 02804 02805 /* check all pads in element */ 02806 PAD_LOOP (Element); 02807 { 02808 /* lookup pad in list */ 02809 /* pad might has bee checked before, add to list if not */ 02810 if (!TEST_FLAG (flag, pad) && FP) 02811 { 02812 int i; 02813 if (ADD_PAD_TO_LIST (TEST_FLAG (ONSOLDERFLAG, pad) 02814 ? BOTTOM_SIDE : TOP_SIDE, pad, flag)) 02815 return true; 02816 DoIt (flag, true, true); 02817 number = PadList[TOP_SIDE].Number 02818 + PadList[BOTTOM_SIDE].Number + PVList.Number; 02819 /* the pin has no connection if it's the only 02820 * list entry; don't count vias 02821 */ 02822 for (i = 0; i < PVList.Number; i++) 02823 if (!PVLIST_ENTRY (i)->Element) 02824 number--; 02825 if (number == 1) 02826 { 02827 /* output of element name if not already done */ 02828 if (first) 02829 { 02830 PrintConnectionElementName (Element, FP); 02831 first = false; 02832 } 02833 02834 /* write name to list and draw selected object */ 02835 CreateQuotedString (&oname, (char *)EMPTY (pad->Name)); 02836 fprintf (FP, "\t%s\n", oname.Data); 02837 SET_FLAG (SELECTEDFLAG, pad); 02838 DrawPad (pad); 02839 } 02840 02841 /* reset found objects for the next pin */ 02842 if (PrepareNextLoop (FP)) 02843 return (true); 02844 } 02845 } 02846 END_LOOP; 02847 02848 /* print separator if element has unused pins or pads */ 02849 if (!first) 02850 { 02851 fputs ("}\n\n", FP); 02852 SEPARATE (FP); 02853 } 02854 return (false); 02855 } 02856 02860 static bool 02861 PrepareNextLoop (FILE * FP) 02862 { 02863 Cardinal layer; 02864 02865 /* reset found LOs for the next pin */ 02866 for (layer = 0; layer < max_copper_layer; layer++) 02867 { 02868 LineList[layer].Location = LineList[layer].Number = 0; 02869 ArcList[layer].Location = ArcList[layer].Number = 0; 02870 PolygonList[layer].Location = PolygonList[layer].Number = 0; 02871 } 02872 02873 /* reset found pads */ 02874 for (layer = 0; layer < 2; layer++) 02875 PadList[layer].Location = PadList[layer].Number = 0; 02876 02877 /* reset PVs */ 02878 PVList.Number = PVList.Location = 0; 02879 RatList.Number = RatList.Location = 0; 02880 02881 return (false); 02882 } 02883 02891 static bool 02892 PrintElementConnections (ElementType *Element, FILE * FP, int flag, bool AndDraw) 02893 { 02894 PrintConnectionElementName (Element, FP); 02895 02896 /* check all pins in element */ 02897 PIN_LOOP (Element); 02898 { 02899 /* pin might have been checked before, add to list if not */ 02900 if (TEST_FLAG (flag, pin)) 02901 { 02902 PrintConnectionListEntry ((char *)EMPTY (pin->Name), NULL, true, FP); 02903 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP); 02904 continue; 02905 } 02906 if (ADD_PV_TO_LIST (pin, flag)) 02907 return true; 02908 DoIt (flag, true, AndDraw); 02909 /* printout all found connections */ 02910 PrintPinConnections (FP, true); 02911 PrintPadConnections (TOP_SIDE, FP, false); 02912 PrintPadConnections (BOTTOM_SIDE, FP, false); 02913 fputs ("\t}\n", FP); 02914 if (PrepareNextLoop (FP)) 02915 return (true); 02916 } 02917 END_LOOP; 02918 02919 /* check all pads in element */ 02920 PAD_LOOP (Element); 02921 { 02922 Cardinal layer; 02923 /* pad might have been checked before, add to list if not */ 02924 if (TEST_FLAG (flag, pad)) 02925 { 02926 PrintConnectionListEntry ((char *)EMPTY (pad->Name), NULL, true, FP); 02927 fputs ("\t\t__CHECKED_BEFORE__\n\t}\n", FP); 02928 continue; 02929 } 02930 layer = TEST_FLAG (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE; 02931 if (ADD_PAD_TO_LIST (layer, pad, flag)) 02932 return true; 02933 DoIt (flag, true, AndDraw); 02934 /* print all found connections */ 02935 PrintPadConnections (layer, FP, true); 02936 PrintPadConnections (layer == 02937 (TOP_SIDE ? BOTTOM_SIDE : TOP_SIDE), 02938 FP, false); 02939 PrintPinConnections (FP, false); 02940 fputs ("\t}\n", FP); 02941 if (PrepareNextLoop (FP)) 02942 return (true); 02943 } 02944 END_LOOP; 02945 fputs ("}\n\n", FP); 02946 return (false); 02947 } 02948 02953 static void 02954 DrawNewConnections (void) 02955 { 02956 int i; 02957 Cardinal position; 02958 02959 /* decrement 'i' to keep layerstack order */ 02960 for (i = max_copper_layer - 1; i != -1; i--) 02961 { 02962 Cardinal layer = LayerStack[i]; 02963 02964 if (PCB->Data->Layer[layer].On) 02965 { 02966 /* draw all new lines */ 02967 position = LineList[layer].DrawLocation; 02968 for (; position < LineList[layer].Number; position++) 02969 DrawLine (LAYER_PTR (layer), LINELIST_ENTRY (layer, position)); 02970 LineList[layer].DrawLocation = LineList[layer].Number; 02971 02972 /* draw all new arcs */ 02973 position = ArcList[layer].DrawLocation; 02974 for (; position < ArcList[layer].Number; position++) 02975 DrawArc (LAYER_PTR (layer), ARCLIST_ENTRY (layer, position)); 02976 ArcList[layer].DrawLocation = ArcList[layer].Number; 02977 02978 /* draw all new polygons */ 02979 position = PolygonList[layer].DrawLocation; 02980 for (; position < PolygonList[layer].Number; position++) 02981 DrawPolygon (LAYER_PTR (layer), POLYGONLIST_ENTRY (layer, position)); 02982 PolygonList[layer].DrawLocation = PolygonList[layer].Number; 02983 } 02984 } 02985 02986 /* draw all new pads */ 02987 if (PCB->PinOn) 02988 for (i = 0; i < 2; i++) 02989 { 02990 position = PadList[i].DrawLocation; 02991 02992 for (; position < PadList[i].Number; position++) 02993 DrawPad (PADLIST_ENTRY (i, position)); 02994 PadList[i].DrawLocation = PadList[i].Number; 02995 } 02996 02997 /* draw all new PVs; 'PVList' holds a list of pointers to the 02998 * sorted array pointers to PV data 02999 */ 03000 while (PVList.DrawLocation < PVList.Number) 03001 { 03002 PinType *pv = PVLIST_ENTRY (PVList.DrawLocation); 03003 03004 if (TEST_FLAG (PINFLAG, pv)) 03005 { 03006 if (PCB->PinOn) 03007 DrawPin (pv); 03008 } 03009 else if (PCB->ViaOn) 03010 DrawVia (pv); 03011 PVList.DrawLocation++; 03012 } 03013 /* draw the new rat-lines */ 03014 if (PCB->RatOn) 03015 { 03016 position = RatList.DrawLocation; 03017 for (; position < RatList.Number; position++) 03018 DrawRat (RATLIST_ENTRY (position)); 03019 RatList.DrawLocation = RatList.Number; 03020 } 03021 } 03022 03026 void 03027 LookupElementConnections (ElementType *Element, FILE * FP) 03028 { 03029 /* reset all currently marked connections */ 03030 User = true; 03031 ClearFlagOnAllObjects (true, FOUNDFLAG); 03032 InitConnectionLookup (); 03033 PrintElementConnections (Element, FP, FOUNDFLAG, true); 03034 SetChangedFlag (true); 03035 if (Settings.RingBellWhenFinished) 03036 gui->beep (); 03037 FreeConnectionLookupMemory (); 03038 IncrementUndoSerialNumber (); 03039 User = false; 03040 Draw (); 03041 } 03042 03046 void 03047 LookupConnectionsToAllElements (FILE * FP) 03048 { 03049 /* reset all currently marked connections */ 03050 User = false; 03051 ClearFlagOnAllObjects (false, FOUNDFLAG); 03052 InitConnectionLookup (); 03053 03054 ELEMENT_LOOP (PCB->Data); 03055 { 03056 /* break if abort dialog returned true */ 03057 if (PrintElementConnections (element, FP, FOUNDFLAG, false)) 03058 break; 03059 SEPARATE (FP); 03060 if (Settings.ResetAfterElement && n != 1) 03061 ClearFlagOnAllObjects (false, FOUNDFLAG); 03062 } 03063 END_LOOP; 03064 if (Settings.RingBellWhenFinished) 03065 gui->beep (); 03066 ClearFlagOnAllObjects (false, FOUNDFLAG); 03067 FreeConnectionLookupMemory (); 03068 Redraw (); 03069 } 03070 03074 static bool 03075 ListStart (int type, void *ptr1, void *ptr2, void *ptr3, int flag) 03076 { 03077 DumpList (); 03078 switch (type) 03079 { 03080 case PIN_TYPE: 03081 case VIA_TYPE: 03082 { 03083 if (ADD_PV_TO_LIST ((PinType *) ptr2, flag)) 03084 return true; 03085 break; 03086 } 03087 03088 case RATLINE_TYPE: 03089 { 03090 if (ADD_RAT_TO_LIST ((RatType *) ptr1, flag)) 03091 return true; 03092 break; 03093 } 03094 03095 case LINE_TYPE: 03096 { 03097 int layer = GetLayerNumber (PCB->Data, 03098 (LayerType *) ptr1); 03099 03100 if (ADD_LINE_TO_LIST (layer, (LineType *) ptr2, flag)) 03101 return true; 03102 break; 03103 } 03104 03105 case ARC_TYPE: 03106 { 03107 int layer = GetLayerNumber (PCB->Data, 03108 (LayerType *) ptr1); 03109 03110 if (ADD_ARC_TO_LIST (layer, (ArcType *) ptr2, flag)) 03111 return true; 03112 break; 03113 } 03114 03115 case POLYGON_TYPE: 03116 { 03117 int layer = GetLayerNumber (PCB->Data, 03118 (LayerType *) ptr1); 03119 03120 if (ADD_POLYGON_TO_LIST (layer, (PolygonType *) ptr2, flag)) 03121 return true; 03122 break; 03123 } 03124 03125 case PAD_TYPE: 03126 { 03127 PadType *pad = (PadType *) ptr2; 03128 if (ADD_PAD_TO_LIST 03129 (TEST_FLAG 03130 (ONSOLDERFLAG, pad) ? BOTTOM_SIDE : TOP_SIDE, pad, flag)) 03131 return true; 03132 break; 03133 } 03134 } 03135 return (false); 03136 } 03137 03138 03147 void 03148 LookupConnection (Coord X, Coord Y, bool AndDraw, Coord Range, int flag, 03149 bool AndRats) 03150 { 03151 void *ptr1, *ptr2, *ptr3; 03152 char *name; 03153 int type; 03154 03155 /* check if there are any pins or pads at that position */ 03156 03157 reassign_no_drc_flags (); 03158 03159 type 03160 = SearchObjectByLocation (LOOKUP_FIRST, &ptr1, &ptr2, &ptr3, X, Y, Range); 03161 if (type == NO_TYPE) 03162 { 03163 type = SearchObjectByLocation ( 03164 LOOKUP_MORE & ~(AndRats ? 0 : RATLINE_TYPE), 03165 &ptr1, &ptr2, &ptr3, X, Y, Range); 03166 if (type == NO_TYPE) 03167 return; 03168 if (type & SILK_TYPE) 03169 { 03170 int laynum = GetLayerNumber (PCB->Data, 03171 (LayerType *) ptr1); 03172 03173 /* don't mess with non-conducting objects! */ 03174 if (laynum >= max_copper_layer || ((LayerType *)ptr1)->no_drc) 03175 return; 03176 } 03177 } 03178 03179 name = ConnectionName (type, ptr1, ptr2); 03180 hid_actionl ("NetlistShow", name, NULL); 03181 03182 User = AndDraw; 03183 InitConnectionLookup (); 03184 03185 /* now add the object to the appropriate list and start scanning 03186 * This is step (1) from the description 03187 */ 03188 ListStart (type, ptr1, ptr2, ptr3, flag); 03189 DoIt (flag, AndRats, AndDraw); 03190 if (User) 03191 IncrementUndoSerialNumber (); 03192 User = false; 03193 03194 /* we are done */ 03195 if (AndDraw) 03196 Draw (); 03197 if (AndDraw && Settings.RingBellWhenFinished) 03198 gui->beep (); 03199 FreeConnectionLookupMemory (); 03200 } 03201 03202 void 03203 LookupConnectionByPin (int type, void *ptr1) 03204 { 03205 /* int TheFlag = FOUNDFLAG; */ 03206 03207 User = 0; 03208 InitConnectionLookup (); 03209 ListStart (type, NULL, ptr1, NULL, FOUNDFLAG); 03210 03211 DoIt (FOUNDFLAG, true, false); 03212 03213 FreeConnectionLookupMemory (); 03214 } 03215 03221 void 03222 RatFindHook (int type, void *ptr1, void *ptr2, void *ptr3, 03223 bool undo, int flag, bool AndRats) 03224 { 03225 User = undo; 03226 DumpList (); 03227 ListStart (type, ptr1, ptr2, ptr3, flag); 03228 DoIt (flag, AndRats, false); 03229 User = false; 03230 } 03231 03235 void 03236 LookupUnusedPins (FILE * FP) 03237 { 03238 /* reset all currently marked connections */ 03239 User = true; 03240 ClearFlagOnAllObjects (true, FOUNDFLAG); 03241 InitConnectionLookup (); 03242 03243 ELEMENT_LOOP (PCB->Data); 03244 { 03245 /* break if abort dialog returned true; 03246 * passing NULL as filedescriptor discards the normal output 03247 */ 03248 if (PrintAndSelectUnusedPinsAndPadsOfElement (element, FP, FOUNDFLAG)) 03249 break; 03250 } 03251 END_LOOP; 03252 03253 if (Settings.RingBellWhenFinished) 03254 gui->beep (); 03255 FreeConnectionLookupMemory (); 03256 IncrementUndoSerialNumber (); 03257 User = false; 03258 Draw (); 03259 } 03260 03264 bool 03265 ClearFlagOnPinsViasAndPads (bool AndDraw, int flag) 03266 { 03267 bool change = false; 03268 03269 VIA_LOOP (PCB->Data); 03270 { 03271 if (TEST_FLAG (flag, via)) 03272 { 03273 if (AndDraw) 03274 AddObjectToFlagUndoList (VIA_TYPE, via, via, via); 03275 CLEAR_FLAG (flag, via); 03276 if (AndDraw) 03277 DrawVia (via); 03278 change = true; 03279 } 03280 } 03281 END_LOOP; 03282 ELEMENT_LOOP (PCB->Data); 03283 { 03284 PIN_LOOP (element); 03285 { 03286 if (TEST_FLAG (flag, pin)) 03287 { 03288 if (AndDraw) 03289 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin); 03290 CLEAR_FLAG (flag, pin); 03291 if (AndDraw) 03292 DrawPin (pin); 03293 change = true; 03294 } 03295 } 03296 END_LOOP; 03297 PAD_LOOP (element); 03298 { 03299 if (TEST_FLAG (flag, pad)) 03300 { 03301 if (AndDraw) 03302 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad); 03303 CLEAR_FLAG (flag, pad); 03304 if (AndDraw) 03305 DrawPad (pad); 03306 change = true; 03307 } 03308 } 03309 END_LOOP; 03310 } 03311 END_LOOP; 03312 if (change) 03313 SetChangedFlag (true); 03314 return change; 03315 } 03316 03320 bool 03321 ClearFlagOnLinesAndPolygons (bool AndDraw, int flag) 03322 { 03323 bool change = false; 03324 03325 RAT_LOOP (PCB->Data); 03326 { 03327 if (TEST_FLAG (flag, line)) 03328 { 03329 if (AndDraw) 03330 AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line); 03331 CLEAR_FLAG (flag, line); 03332 if (AndDraw) 03333 DrawRat (line); 03334 change = true; 03335 } 03336 } 03337 END_LOOP; 03338 COPPERLINE_LOOP (PCB->Data); 03339 { 03340 if (TEST_FLAG (flag, line)) 03341 { 03342 if (AndDraw) 03343 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line); 03344 CLEAR_FLAG (flag, line); 03345 if (AndDraw) 03346 DrawLine (layer, line); 03347 change = true; 03348 } 03349 } 03350 ENDALL_LOOP; 03351 COPPERARC_LOOP (PCB->Data); 03352 { 03353 if (TEST_FLAG (flag, arc)) 03354 { 03355 if (AndDraw) 03356 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc); 03357 CLEAR_FLAG (flag, arc); 03358 if (AndDraw) 03359 DrawArc (layer, arc); 03360 change = true; 03361 } 03362 } 03363 ENDALL_LOOP; 03364 COPPERPOLYGON_LOOP (PCB->Data); 03365 { 03366 if (TEST_FLAG (flag, polygon)) 03367 { 03368 if (AndDraw) 03369 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon); 03370 CLEAR_FLAG (flag, polygon); 03371 if (AndDraw) 03372 DrawPolygon (layer, polygon); 03373 change = true; 03374 } 03375 } 03376 ENDALL_LOOP; 03377 if (change) 03378 SetChangedFlag (true); 03379 return change; 03380 } 03381 03385 bool 03386 ClearFlagOnAllObjects (bool AndDraw, int flag) 03387 { 03388 bool change = false; 03389 03390 change = ClearFlagOnPinsViasAndPads (AndDraw, flag) || change; 03391 change = ClearFlagOnLinesAndPolygons (AndDraw, flag) || change; 03392 03393 return change; 03394 } 03395 03399 static void 03400 DumpList (void) 03401 { 03402 Cardinal i; 03403 03404 for (i = 0; i < 2; i++) 03405 { 03406 PadList[i].Number = 0; 03407 PadList[i].Location = 0; 03408 PadList[i].DrawLocation = 0; 03409 } 03410 03411 PVList.Number = 0; 03412 PVList.Location = 0; 03413 03414 for (i = 0; i < max_copper_layer; i++) 03415 { 03416 LineList[i].Location = 0; 03417 LineList[i].DrawLocation = 0; 03418 LineList[i].Number = 0; 03419 ArcList[i].Location = 0; 03420 ArcList[i].DrawLocation = 0; 03421 ArcList[i].Number = 0; 03422 PolygonList[i].Location = 0; 03423 PolygonList[i].DrawLocation = 0; 03424 PolygonList[i].Number = 0; 03425 } 03426 RatList.Number = 0; 03427 RatList.Location = 0; 03428 RatList.DrawLocation = 0; 03429 } 03430 03431 struct drc_info 03432 { 03433 int flag; 03434 }; 03435 03443 static bool 03444 DRCFind (int What, void *ptr1, void *ptr2, void *ptr3) 03445 { 03446 Coord x, y; 03447 int object_count; 03448 long int *object_id_list; 03449 int *object_type_list; 03450 DrcViolationType *violation; 03451 int flag; 03452 03453 if (PCB->Shrink != 0) 03454 { 03455 Bloat = -PCB->Shrink; 03456 ListStart (What, ptr1, ptr2, ptr3, DRCFLAG | SELECTEDFLAG); 03457 DoIt (DRCFLAG | SELECTEDFLAG, true, false); 03458 /* ok now the shrunk net has the SELECTEDFLAG set */ 03459 DumpList (); 03460 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG); 03461 Bloat = 0; 03462 drc = true; /* abort the search if we find anything not already found */ 03463 if (DoIt (FOUNDFLAG, true, false)) 03464 { 03465 DumpList (); 03466 /* make the flag changes undoable */ 03467 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG); 03468 User = true; 03469 drc = false; 03470 Bloat = -PCB->Shrink; 03471 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG); 03472 DoIt (SELECTEDFLAG, true, true); 03473 DumpList (); 03474 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG); 03475 Bloat = 0; 03476 drc = true; 03477 DoIt (FOUNDFLAG, true, true); 03478 DumpList (); 03479 User = false; 03480 drc = false; 03481 drcerr_count++; 03482 LocateError (&x, &y); 03483 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03484 violation = pcb_drc_violation_new (_("Potential for broken trace"), 03485 _("Insufficient overlap between objects can lead to broken tracks\n" 03486 "due to registration errors with old wheel style photo-plotters."), 03487 x, y, 03488 0, /* ANGLE OF ERROR UNKNOWN */ 03489 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */ 03490 0, /* MAGNITUDE OF ERROR UNKNOWN */ 03491 PCB->Shrink, 03492 object_count, 03493 object_id_list, 03494 object_type_list); 03495 append_drc_violation (violation); 03496 pcb_drc_violation_free (violation); 03497 free (object_id_list); 03498 free (object_type_list); 03499 03500 if (!throw_drc_dialog()) 03501 return (true); 03502 IncrementUndoSerialNumber (); 03503 Undo (true); 03504 } 03505 DumpList (); 03506 } 03507 /* now check the bloated condition */ 03508 drc = false; 03509 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG); 03510 Bloat = 0; 03511 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG); 03512 DoIt (SELECTEDFLAG, true, false); 03513 DumpList (); 03514 flag = FOUNDFLAG; 03515 ListStart (What, ptr1, ptr2, ptr3, flag); 03516 Bloat = PCB->Bloat; 03517 drc = true; 03518 while (DoIt (flag, true, false)) 03519 { 03520 DumpList (); 03521 /* make the flag changes undoable */ 03522 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG); 03523 User = true; 03524 drc = false; 03525 Bloat = 0; 03526 ListStart (What, ptr1, ptr2, ptr3, SELECTEDFLAG); 03527 DoIt (SELECTEDFLAG, true, true); 03528 DumpList (); 03529 ListStart (What, ptr1, ptr2, ptr3, FOUNDFLAG); 03530 Bloat = PCB->Bloat; 03531 drc = true; 03532 DoIt (FOUNDFLAG, true, true); 03533 DumpList (); 03534 drcerr_count++; 03535 LocateError (&x, &y); 03536 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03537 violation = pcb_drc_violation_new (_("Copper areas too close"), 03538 _("Circuits that are too close may bridge during imaging, etching,\n" 03539 "plating, or soldering processes resulting in a direct short."), 03540 x, y, 03541 0, /* ANGLE OF ERROR UNKNOWN */ 03542 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */ 03543 0, /* MAGNITUDE OF ERROR UNKNOWN */ 03544 PCB->Bloat, 03545 object_count, 03546 object_id_list, 03547 object_type_list); 03548 append_drc_violation (violation); 03549 pcb_drc_violation_free (violation); 03550 free (object_id_list); 03551 free (object_type_list); 03552 User = false; 03553 drc = false; 03554 if (!throw_drc_dialog()) 03555 return (true); 03556 IncrementUndoSerialNumber (); 03557 Undo (true); 03558 /* highlight the rest of the encroaching net so it's not reported again */ 03559 flag = FOUNDFLAG | SELECTEDFLAG; 03560 Bloat = 0; 03561 ListStart (thing_type, thing_ptr1, thing_ptr2, thing_ptr3, flag); 03562 DoIt (flag, true, true); 03563 DumpList (); 03564 drc = true; 03565 Bloat = PCB->Bloat; 03566 ListStart (What, ptr1, ptr2, ptr3, flag); 03567 } 03568 drc = false; 03569 DumpList (); 03570 ClearFlagOnAllObjects (false, FOUNDFLAG | SELECTEDFLAG); 03571 return (false); 03572 } 03573 03577 static int 03578 drc_callback (DataType *data, LayerType *layer, PolygonType *polygon, 03579 int type, void *ptr1, void *ptr2, void *userdata) 03580 { 03581 struct drc_info *i = (struct drc_info *) userdata; 03582 char *message; 03583 Coord x, y; 03584 int object_count; 03585 long int *object_id_list; 03586 int *object_type_list; 03587 DrcViolationType *violation; 03588 03589 LineType *line = (LineType *) ptr2; 03590 ArcType *arc = (ArcType *) ptr2; 03591 PinType *pin = (PinType *) ptr2; 03592 PadType *pad = (PadType *) ptr2; 03593 03594 SetThing (type, ptr1, ptr2, ptr2); 03595 03596 switch (type) 03597 { 03598 case LINE_TYPE: 03599 if (line->Clearance < 2 * PCB->Bloat) 03600 { 03601 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2); 03602 SET_FLAG (i->flag, line); 03603 message = _("Line with insufficient clearance inside polygon\n"); 03604 goto doIsBad; 03605 } 03606 break; 03607 case ARC_TYPE: 03608 if (arc->Clearance < 2 * PCB->Bloat) 03609 { 03610 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2); 03611 SET_FLAG (i->flag, arc); 03612 message = _("Arc with insufficient clearance inside polygon\n"); 03613 goto doIsBad; 03614 } 03615 break; 03616 case PAD_TYPE: 03617 if (pad->Clearance && pad->Clearance < 2 * PCB->Bloat) 03618 if (IsPadInPolygon(pad,polygon)) 03619 { 03620 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2); 03621 SET_FLAG (i->flag, pad); 03622 message = _("Pad with insufficient clearance inside polygon\n"); 03623 goto doIsBad; 03624 } 03625 break; 03626 case PIN_TYPE: 03627 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat) 03628 { 03629 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2); 03630 SET_FLAG (i->flag, pin); 03631 message = _("Pin with insufficient clearance inside polygon\n"); 03632 goto doIsBad; 03633 } 03634 break; 03635 case VIA_TYPE: 03636 if (pin->Clearance && pin->Clearance < 2 * PCB->Bloat) 03637 { 03638 AddObjectToFlagUndoList (type, ptr1, ptr2, ptr2); 03639 SET_FLAG (i->flag, pin); 03640 message = _("Via with insufficient clearance inside polygon\n"); 03641 goto doIsBad; 03642 } 03643 break; 03644 default: 03645 Message ("hace: Bad Plow object in callback\n"); 03646 } 03647 return 0; 03648 03649 doIsBad: 03650 AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon); 03651 SET_FLAG (FOUNDFLAG, polygon); 03652 DrawPolygon (layer, polygon); 03653 DrawObject (type, ptr1, ptr2); 03654 drcerr_count++; 03655 LocateError (&x, &y); 03656 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03657 violation = pcb_drc_violation_new (message, 03658 _("Circuits that are too close may bridge during imaging, etching,\n" 03659 "plating, or soldering processes resulting in a direct short."), 03660 x, y, 03661 0, /* ANGLE OF ERROR UNKNOWN */ 03662 FALSE, /* MEASUREMENT OF ERROR UNKNOWN */ 03663 0, /* MAGNITUDE OF ERROR UNKNOWN */ 03664 PCB->Bloat, 03665 object_count, 03666 object_id_list, 03667 object_type_list); 03668 append_drc_violation (violation); 03669 pcb_drc_violation_free (violation); 03670 free (object_id_list); 03671 free (object_type_list); 03672 03673 if (!throw_drc_dialog()) 03674 return 1; 03675 03676 IncrementUndoSerialNumber (); 03677 Undo (true); 03678 return 0; 03679 } 03680 03686 int 03687 DRCAll (void) 03688 { 03689 Coord x, y; 03690 int object_count; 03691 long int *object_id_list; 03692 int *object_type_list; 03693 DrcViolationType *violation; 03694 int tmpcnt; 03695 int nopastecnt = 0; 03696 bool IsBad; 03697 struct drc_info info; 03698 03699 reset_drc_dialog_message(); 03700 03701 /* This phony violation informs user about what DRC does NOT catch. */ 03702 violation 03703 = pcb_drc_violation_new ( 03704 _("WARNING: DRC doesn't catch everything"), 03705 _("Detection of outright shorts, missing connections, etc.\n" 03706 "is handled via rat's nest addition. To catch these problems,\n" 03707 "display the message log using Window->Message Log, then use\n" 03708 "Connects->Optimize rats nest (O hotkey) and watch for messages.\n"), 03709 /* All remaining arguments are not relevant to this application. */ 03710 0, 0, 0, TRUE, 0, 0, 0, NULL, NULL); 03711 append_drc_violation (violation); 03712 pcb_drc_violation_free (violation); 03713 if (!throw_drc_dialog()) 03714 return (true); 03715 03716 IsBad = false; 03717 drcerr_count = 0; 03718 SaveStackAndVisibility (); 03719 ResetStackAndVisibility (); 03720 hid_action ("LayersChanged"); 03721 InitConnectionLookup (); 03722 03723 if (ClearFlagOnAllObjects (true, FOUNDFLAG | DRCFLAG | SELECTEDFLAG)) 03724 { 03725 IncrementUndoSerialNumber (); 03726 Draw (); 03727 } 03728 03729 User = false; 03730 03731 ELEMENT_LOOP (PCB->Data); 03732 { 03733 PIN_LOOP (element); 03734 { 03735 if (!TEST_FLAG (DRCFLAG, pin) 03736 && DRCFind (PIN_TYPE, (void *) element, (void *) pin, (void *) pin)) 03737 { 03738 IsBad = true; 03739 break; 03740 } 03741 } 03742 END_LOOP; 03743 if (IsBad) 03744 break; 03745 PAD_LOOP (element); 03746 { 03747 03748 /* count up how many pads have no solderpaste openings */ 03749 if (TEST_FLAG (NOPASTEFLAG, pad)) 03750 nopastecnt++; 03751 03752 if (!TEST_FLAG (DRCFLAG, pad) 03753 && DRCFind (PAD_TYPE, (void *) element, (void *) pad, (void *) pad)) 03754 { 03755 IsBad = true; 03756 break; 03757 } 03758 } 03759 END_LOOP; 03760 if (IsBad) 03761 break; 03762 } 03763 END_LOOP; 03764 if (!IsBad) 03765 VIA_LOOP (PCB->Data); 03766 { 03767 if (!TEST_FLAG (DRCFLAG, via) 03768 && DRCFind (VIA_TYPE, (void *) via, (void *) via, (void *) via)) 03769 { 03770 IsBad = true; 03771 break; 03772 } 03773 } 03774 END_LOOP; 03775 03776 ClearFlagOnAllObjects (false, IsBad ? DRCFLAG : (FOUNDFLAG | DRCFLAG | SELECTEDFLAG)); 03777 info.flag = SELECTEDFLAG; 03778 /* check minimum widths and polygon clearances */ 03779 if (!IsBad) 03780 { 03781 COPPERLINE_LOOP (PCB->Data); 03782 { 03783 /* check line clearances in polygons */ 03784 if (PlowsPolygon (PCB->Data, LINE_TYPE, layer, line, drc_callback, &info)) 03785 { 03786 IsBad = true; 03787 break; 03788 } 03789 if (line->Thickness < PCB->minWid) 03790 { 03791 AddObjectToFlagUndoList (LINE_TYPE, layer, line, line); 03792 SET_FLAG (SELECTEDFLAG, line); 03793 DrawLine (layer, line); 03794 drcerr_count++; 03795 SetThing (LINE_TYPE, layer, line, line); 03796 LocateError (&x, &y); 03797 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03798 violation = pcb_drc_violation_new (_("Line width is too thin"), 03799 _("Process specifications dictate a minimum feature-width\n" 03800 "that can reliably be reproduced"), 03801 x, y, 03802 0, /* ANGLE OF ERROR UNKNOWN */ 03803 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 03804 line->Thickness, 03805 PCB->minWid, 03806 object_count, 03807 object_id_list, 03808 object_type_list); 03809 append_drc_violation (violation); 03810 pcb_drc_violation_free (violation); 03811 free (object_id_list); 03812 free (object_type_list); 03813 if (!throw_drc_dialog()) 03814 { 03815 IsBad = true; 03816 break; 03817 } 03818 IncrementUndoSerialNumber (); 03819 Undo (false); 03820 } 03821 } 03822 ENDALL_LOOP; 03823 } 03824 if (!IsBad) 03825 { 03826 COPPERARC_LOOP (PCB->Data); 03827 { 03828 if (PlowsPolygon (PCB->Data, ARC_TYPE, layer, arc, drc_callback, &info)) 03829 { 03830 IsBad = true; 03831 break; 03832 } 03833 if (arc->Thickness < PCB->minWid) 03834 { 03835 AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc); 03836 SET_FLAG (SELECTEDFLAG, arc); 03837 DrawArc (layer, arc); 03838 drcerr_count++; 03839 SetThing (ARC_TYPE, layer, arc, arc); 03840 LocateError (&x, &y); 03841 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03842 violation = pcb_drc_violation_new (_("Arc width is too thin"), 03843 _("Process specifications dictate a minimum feature-width\n" 03844 "that can reliably be reproduced"), 03845 x, y, 03846 0, /* ANGLE OF ERROR UNKNOWN */ 03847 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 03848 arc->Thickness, 03849 PCB->minWid, 03850 object_count, 03851 object_id_list, 03852 object_type_list); 03853 append_drc_violation (violation); 03854 pcb_drc_violation_free (violation); 03855 free (object_id_list); 03856 free (object_type_list); 03857 if (!throw_drc_dialog()) 03858 { 03859 IsBad = true; 03860 break; 03861 } 03862 IncrementUndoSerialNumber (); 03863 Undo (false); 03864 } 03865 } 03866 ENDALL_LOOP; 03867 } 03868 if (!IsBad) 03869 { 03870 ALLPIN_LOOP (PCB->Data); 03871 { 03872 if (PlowsPolygon (PCB->Data, PIN_TYPE, element, pin, drc_callback, &info)) 03873 { 03874 IsBad = true; 03875 break; 03876 } 03877 if (!TEST_FLAG (HOLEFLAG, pin) && 03878 pin->Thickness - pin->DrillingHole < 2 * PCB->minRing) 03879 { 03880 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin); 03881 SET_FLAG (SELECTEDFLAG, pin); 03882 DrawPin (pin); 03883 drcerr_count++; 03884 SetThing (PIN_TYPE, element, pin, pin); 03885 LocateError (&x, &y); 03886 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03887 violation = pcb_drc_violation_new (_("Pin annular ring too small"), 03888 _("Annular rings that are too small may erode during etching,\n" 03889 "resulting in a broken connection"), 03890 x, y, 03891 0, /* ANGLE OF ERROR UNKNOWN */ 03892 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 03893 (pin->Thickness - pin->DrillingHole) / 2, 03894 PCB->minRing, 03895 object_count, 03896 object_id_list, 03897 object_type_list); 03898 append_drc_violation (violation); 03899 pcb_drc_violation_free (violation); 03900 free (object_id_list); 03901 free (object_type_list); 03902 if (!throw_drc_dialog()) 03903 { 03904 IsBad = true; 03905 break; 03906 } 03907 IncrementUndoSerialNumber (); 03908 Undo (false); 03909 } 03910 if (pin->DrillingHole < PCB->minDrill) 03911 { 03912 AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin); 03913 SET_FLAG (SELECTEDFLAG, pin); 03914 DrawPin (pin); 03915 drcerr_count++; 03916 SetThing (PIN_TYPE, element, pin, pin); 03917 LocateError (&x, &y); 03918 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03919 violation = pcb_drc_violation_new (_("Pin drill size is too small"), 03920 _("Process rules dictate the minimum drill size which can be used"), 03921 x, y, 03922 0, /* ANGLE OF ERROR UNKNOWN */ 03923 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 03924 pin->DrillingHole, 03925 PCB->minDrill, 03926 object_count, 03927 object_id_list, 03928 object_type_list); 03929 append_drc_violation (violation); 03930 pcb_drc_violation_free (violation); 03931 free (object_id_list); 03932 free (object_type_list); 03933 if (!throw_drc_dialog()) 03934 { 03935 IsBad = true; 03936 break; 03937 } 03938 IncrementUndoSerialNumber (); 03939 Undo (false); 03940 } 03941 } 03942 ENDALL_LOOP; 03943 } 03944 if (!IsBad) 03945 { 03946 ALLPAD_LOOP (PCB->Data); 03947 { 03948 if (PlowsPolygon (PCB->Data, PAD_TYPE, element, pad, drc_callback, &info)) 03949 { 03950 IsBad = true; 03951 break; 03952 } 03953 if (pad->Thickness < PCB->minWid) 03954 { 03955 AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad); 03956 SET_FLAG (SELECTEDFLAG, pad); 03957 DrawPad (pad); 03958 drcerr_count++; 03959 SetThing (PAD_TYPE, element, pad, pad); 03960 LocateError (&x, &y); 03961 BuildObjectList (&object_count, &object_id_list, &object_type_list); 03962 violation = pcb_drc_violation_new (_("Pad is too thin"), 03963 _("Pads which are too thin may erode during etching,\n" 03964 "resulting in a broken or unreliable connection"), 03965 x, y, 03966 0, /* ANGLE OF ERROR UNKNOWN */ 03967 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 03968 pad->Thickness, 03969 PCB->minWid, 03970 object_count, 03971 object_id_list, 03972 object_type_list); 03973 append_drc_violation (violation); 03974 pcb_drc_violation_free (violation); 03975 free (object_id_list); 03976 free (object_type_list); 03977 if (!throw_drc_dialog()) 03978 { 03979 IsBad = true; 03980 break; 03981 } 03982 IncrementUndoSerialNumber (); 03983 Undo (false); 03984 } 03985 } 03986 ENDALL_LOOP; 03987 } 03988 if (!IsBad) 03989 { 03990 VIA_LOOP (PCB->Data); 03991 { 03992 if (PlowsPolygon (PCB->Data, VIA_TYPE, via, via, drc_callback, &info)) 03993 { 03994 IsBad = true; 03995 break; 03996 } 03997 if (!TEST_FLAG (HOLEFLAG, via) && 03998 via->Thickness - via->DrillingHole < 2 * PCB->minRing) 03999 { 04000 AddObjectToFlagUndoList (VIA_TYPE, via, via, via); 04001 SET_FLAG (SELECTEDFLAG, via); 04002 DrawVia (via); 04003 drcerr_count++; 04004 SetThing (VIA_TYPE, via, via, via); 04005 LocateError (&x, &y); 04006 BuildObjectList (&object_count, &object_id_list, &object_type_list); 04007 violation = pcb_drc_violation_new (_("Via annular ring too small"), 04008 _("Annular rings that are too small may erode during etching,\n" 04009 "resulting in a broken connection"), 04010 x, y, 04011 0, /* ANGLE OF ERROR UNKNOWN */ 04012 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 04013 (via->Thickness - via->DrillingHole) / 2, 04014 PCB->minRing, 04015 object_count, 04016 object_id_list, 04017 object_type_list); 04018 append_drc_violation (violation); 04019 pcb_drc_violation_free (violation); 04020 free (object_id_list); 04021 free (object_type_list); 04022 if (!throw_drc_dialog()) 04023 { 04024 IsBad = true; 04025 break; 04026 } 04027 IncrementUndoSerialNumber (); 04028 Undo (false); 04029 } 04030 if (via->DrillingHole < PCB->minDrill) 04031 { 04032 AddObjectToFlagUndoList (VIA_TYPE, via, via, via); 04033 SET_FLAG (SELECTEDFLAG, via); 04034 DrawVia (via); 04035 drcerr_count++; 04036 SetThing (VIA_TYPE, via, via, via); 04037 LocateError (&x, &y); 04038 BuildObjectList (&object_count, &object_id_list, &object_type_list); 04039 violation = pcb_drc_violation_new (_("Via drill size is too small"), 04040 _("Process rules dictate the minimum drill size which can be used"), 04041 x, y, 04042 0, /* ANGLE OF ERROR UNKNOWN */ 04043 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 04044 via->DrillingHole, 04045 PCB->minDrill, 04046 object_count, 04047 object_id_list, 04048 object_type_list); 04049 append_drc_violation (violation); 04050 pcb_drc_violation_free (violation); 04051 free (object_id_list); 04052 free (object_type_list); 04053 if (!throw_drc_dialog()) 04054 { 04055 IsBad = true; 04056 break; 04057 } 04058 IncrementUndoSerialNumber (); 04059 Undo (false); 04060 } 04061 } 04062 END_LOOP; 04063 } 04064 04065 FreeConnectionLookupMemory (); 04066 Bloat = 0; 04067 04068 /* check silkscreen minimum widths outside of elements */ 04069 /* XXX - need to check text and polygons too! */ 04070 if (!IsBad) 04071 { 04072 SILKLINE_LOOP (PCB->Data); 04073 { 04074 if (line->Thickness < PCB->minSlk) 04075 { 04076 SET_FLAG (SELECTEDFLAG, line); 04077 DrawLine (layer, line); 04078 drcerr_count++; 04079 SetThing (LINE_TYPE, layer, line, line); 04080 LocateError (&x, &y); 04081 BuildObjectList (&object_count, &object_id_list, &object_type_list); 04082 violation = pcb_drc_violation_new (_("Silk line is too thin"), 04083 _("Process specifications dictate a minimum silkscreen\n" 04084 "feature-width that can reliably be reproduced"), 04085 x, y, 04086 0, /* ANGLE OF ERROR UNKNOWN */ 04087 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 04088 line->Thickness, 04089 PCB->minSlk, 04090 object_count, 04091 object_id_list, 04092 object_type_list); 04093 append_drc_violation (violation); 04094 pcb_drc_violation_free (violation); 04095 free (object_id_list); 04096 free (object_type_list); 04097 if (!throw_drc_dialog()) 04098 { 04099 IsBad = true; 04100 break; 04101 } 04102 } 04103 } 04104 ENDALL_LOOP; 04105 } 04106 04107 /* check silkscreen minimum widths inside of elements */ 04108 /* XXX - need to check text and polygons too! */ 04109 if (!IsBad) 04110 { 04111 ELEMENT_LOOP (PCB->Data); 04112 { 04113 tmpcnt = 0; 04114 ELEMENTLINE_LOOP (element); 04115 { 04116 if (line->Thickness < PCB->minSlk) 04117 tmpcnt++; 04118 } 04119 END_LOOP; 04120 if (tmpcnt > 0) 04121 { 04122 char *title; 04123 char *name; 04124 char *buffer; 04125 int buflen; 04126 04127 SET_FLAG (SELECTEDFLAG, element); 04128 DrawElement (element); 04129 drcerr_count++; 04130 SetThing (ELEMENT_TYPE, element, element, element); 04131 LocateError (&x, &y); 04132 BuildObjectList (&object_count, &object_id_list, &object_type_list); 04133 04134 title = _("Element %s has %i silk lines which are too thin"); 04135 name = (char *)UNKNOWN (NAMEONPCB_NAME (element)); 04136 04137 /* -4 is for the %s and %i place-holders */ 04138 /* +11 is the max printed length for a 32 bit integer */ 04139 /* +1 is for the \0 termination */ 04140 buflen = strlen (title) - 4 + strlen (name) + 11 + 1; 04141 buffer = (char *)malloc (buflen); 04142 snprintf (buffer, buflen, title, name, tmpcnt); 04143 04144 violation = pcb_drc_violation_new (buffer, 04145 _("Process specifications dictate a minimum silkscreen\n" 04146 "feature-width that can reliably be reproduced"), 04147 x, y, 04148 0, /* ANGLE OF ERROR UNKNOWN */ 04149 TRUE, /* MEASUREMENT OF ERROR KNOWN */ 04150 0, /* MINIMUM OFFENDING WIDTH UNKNOWN */ 04151 PCB->minSlk, 04152 object_count, 04153 object_id_list, 04154 object_type_list); 04155 free (buffer); 04156 append_drc_violation (violation); 04157 pcb_drc_violation_free (violation); 04158 free (object_id_list); 04159 free (object_type_list); 04160 if (!throw_drc_dialog()) 04161 { 04162 IsBad = true; 04163 break; 04164 } 04165 } 04166 } 04167 END_LOOP; 04168 } 04169 04170 04171 if (IsBad) 04172 { 04173 IncrementUndoSerialNumber (); 04174 } 04175 04176 04177 RestoreStackAndVisibility (); 04178 hid_action ("LayersChanged"); 04179 gui->invalidate_all (); 04180 04181 if (nopastecnt > 0) 04182 { 04183 Message (ngettext ("Warning: %d pad has the nopaste flag set.\n", 04184 "Warning: %d pads have the nopaste flag set.\n", 04185 nopastecnt), nopastecnt); 04186 } 04187 return IsBad ? -drcerr_count : drcerr_count; 04188 } 04189 04193 static void 04194 LocateError (Coord *x, Coord *y) 04195 { 04196 switch (thing_type) 04197 { 04198 case LINE_TYPE: 04199 { 04200 LineType *line = (LineType *) thing_ptr3; 04201 *x = (line->Point1.X + line->Point2.X) / 2; 04202 *y = (line->Point1.Y + line->Point2.Y) / 2; 04203 break; 04204 } 04205 case ARC_TYPE: 04206 { 04207 ArcType *arc = (ArcType *) thing_ptr3; 04208 *x = arc->X; 04209 *y = arc->Y; 04210 break; 04211 } 04212 case POLYGON_TYPE: 04213 { 04214 PolygonType *polygon = (PolygonType *) thing_ptr3; 04215 *x = 04216 (polygon->Clipped->contours->xmin + 04217 polygon->Clipped->contours->xmax) / 2; 04218 *y = 04219 (polygon->Clipped->contours->ymin + 04220 polygon->Clipped->contours->ymax) / 2; 04221 break; 04222 } 04223 case PIN_TYPE: 04224 case VIA_TYPE: 04225 { 04226 PinType *pin = (PinType *) thing_ptr3; 04227 *x = pin->X; 04228 *y = pin->Y; 04229 break; 04230 } 04231 case PAD_TYPE: 04232 { 04233 PadType *pad = (PadType *) thing_ptr3; 04234 *x = (pad->Point1.X + pad->Point2.X) / 2; 04235 *y = (pad->Point1.Y + pad->Point2.Y) / 2; 04236 break; 04237 } 04238 case ELEMENT_TYPE: 04239 { 04240 ElementType *element = (ElementType *) thing_ptr3; 04241 *x = element->MarkX; 04242 *y = element->MarkY; 04243 break; 04244 } 04245 default: 04246 return; 04247 } 04248 } 04249 04250 04256 static void 04257 BuildObjectList (int *object_count, long int **object_id_list, int **object_type_list) 04258 { 04259 *object_count = 0; 04260 *object_id_list = NULL; 04261 *object_type_list = NULL; 04262 04263 switch (thing_type) 04264 { 04265 case LINE_TYPE: 04266 case ARC_TYPE: 04267 case POLYGON_TYPE: 04268 case PIN_TYPE: 04269 case VIA_TYPE: 04270 case PAD_TYPE: 04271 case ELEMENT_TYPE: 04272 case RATLINE_TYPE: 04273 *object_count = 1; 04274 *object_id_list = (long int *)malloc (sizeof (long int)); 04275 *object_type_list = (int *)malloc (sizeof (int)); 04276 **object_id_list = ((AnyObjectType *)thing_ptr3)->ID; 04277 **object_type_list = thing_type; 04278 return; 04279 04280 default: 04281 fprintf (stderr, 04282 _("Internal error in BuildObjectList: unknown object type %i\n"), 04283 thing_type); 04284 } 04285 } 04286 04287 04291 static void 04292 GotoError (void) 04293 { 04294 Coord X, Y; 04295 04296 LocateError (&X, &Y); 04297 04298 switch (thing_type) 04299 { 04300 case LINE_TYPE: 04301 case ARC_TYPE: 04302 case POLYGON_TYPE: 04303 ChangeGroupVisibility ( 04304 GetLayerNumber (PCB->Data, (LayerType *) thing_ptr1), 04305 true, true); 04306 } 04307 CenterDisplay (X, Y, false); 04308 } 04309 04310 void 04311 InitConnectionLookup (void) 04312 { 04313 InitComponentLookup (); 04314 InitLayoutLookup (); 04315 } 04316 04317 void 04318 FreeConnectionLookupMemory (void) 04319 { 04320 FreeComponentLookupMemory (); 04321 FreeLayoutLookupMemory (); 04322 }