pcb 4.1.1
An interactive printed circuit board layout editor.

find.c

Go to the documentation of this file.
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 }