pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 00036 /* Change History: 00037 * Started 6/10/97 00038 * Added support for minimum length rat lines 6/13/97 00039 * rat lines to nearest line/via 8/29/98 00040 * support for netlist window 10/24/98 00041 */ 00042 00043 #ifdef HAVE_CONFIG_H 00044 #include "config.h" 00045 #endif 00046 00047 #include <math.h> 00048 #include <stdio.h> 00049 00050 #include "global.h" 00051 00052 #include "create.h" 00053 #include "data.h" 00054 #include "draw.h" 00055 #include "error.h" 00056 #include "file.h" 00057 #include "find.h" 00058 #include "misc.h" 00059 #include "mymem.h" 00060 #include "polygon.h" 00061 #include "rats.h" 00062 #include "search.h" 00063 #include "set.h" 00064 #include "undo.h" 00065 00066 #ifdef HAVE_LIBDMALLOC 00067 #include <dmalloc.h> 00068 #endif 00069 00070 #define TRIEDFIRST 0x1 00071 #define BESTFOUND 0x2 00072 00073 /* --------------------------------------------------------------------------- 00074 * some forward declarations 00075 */ 00076 static bool FindPad (char *, char *, ConnectionType *, bool); 00077 static bool ParseConnection (char *, char *, char *); 00078 static bool DrawShortestRats (NetListType *, void (*)(register ConnectionType *, register ConnectionType *, register RouteStyleType *)); 00079 static bool GatherSubnets (NetListType *, bool, bool); 00080 static bool CheckShorts (LibraryMenuType *); 00081 static void TransferNet (NetListType *, NetType *, NetType *); 00082 00083 /* --------------------------------------------------------------------------- 00084 * some local identifiers 00085 */ 00086 static bool badnet = false; 00087 static Cardinal top_group, bottom_group; /* layer group holding top/bottom side */ 00088 00098 static bool 00099 ParseConnection (char *InString, char *ElementName, char *PinNum) 00100 { 00101 int i, j; 00102 00103 /* copy element name portion */ 00104 for (j = 0; InString[j] != '\0' && InString[j] != '-'; j++) 00105 ElementName[j] = InString[j]; 00106 if (InString[j] == '-') 00107 { 00108 for (i = j; i > 0 && ElementName[i - 1] >= 'a'; i--); 00109 ElementName[i] = '\0'; 00110 for (i = 0, j++; InString[j] != '\0'; i++, j++) 00111 PinNum[i] = InString[j]; 00112 PinNum[i] = '\0'; 00113 return (false); 00114 } 00115 else 00116 { 00117 ElementName[j] = '\0'; 00118 Message (_("Bad net-list format encountered near: \"%s\"\n"), 00119 ElementName); 00120 return (true); 00121 } 00122 } 00123 00127 static bool 00128 FindPad (char *ElementName, char *PinNum, ConnectionType * conn, bool Same) 00129 { 00130 ElementType *element; 00131 GList *i; 00132 00133 if ((element = SearchElementByName (PCB->Data, ElementName)) == NULL) 00134 return false; 00135 00136 for (i = element->Pad; i != NULL; i = g_list_next (i)) 00137 { 00138 PadType *pad = i->data; 00139 00140 if (NSTRCMP (PinNum, pad->Number) == 0 && 00141 (!Same || !TEST_FLAG (DRCFLAG, pad))) 00142 { 00143 conn->type = PAD_TYPE; 00144 conn->ptr1 = element; 00145 conn->ptr2 = pad; 00146 conn->group = TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_group : top_group; 00147 00148 if (TEST_FLAG (EDGE2FLAG, pad)) 00149 { 00150 conn->X = pad->Point2.X; 00151 conn->Y = pad->Point2.Y; 00152 } 00153 else 00154 { 00155 conn->X = pad->Point1.X; 00156 conn->Y = pad->Point1.Y; 00157 } 00158 return true; 00159 } 00160 } 00161 00162 for (i = element->Pin; i != NULL; i = g_list_next (i)) 00163 { 00164 PinType *pin = i->data; 00165 00166 if (!TEST_FLAG (HOLEFLAG, pin) && 00167 pin->Number && NSTRCMP (PinNum, pin->Number) == 0 && 00168 (!Same || !TEST_FLAG (DRCFLAG, pin))) 00169 { 00170 conn->type = PIN_TYPE; 00171 conn->ptr1 = element; 00172 conn->ptr2 = pin; 00173 conn->group = bottom_group; /* any layer will do */ 00174 conn->X = pin->X; 00175 conn->Y = pin->Y; 00176 return true; 00177 } 00178 } 00179 00180 return false; 00181 } 00182 00188 bool 00189 SeekPad (LibraryEntryType * entry, ConnectionType * conn, bool Same) 00190 { 00191 int j; 00192 char ElementName[256]; 00193 char PinNum[256]; 00194 00195 if (ParseConnection (entry->ListEntry, ElementName, PinNum)) 00196 return (false); 00197 for (j = 0; PinNum[j] != '\0'; j++); 00198 if (j == 0) 00199 { 00200 Message (_("Error! Netlist file is missing pin!\n" 00201 "white space after \"%s-\"\n"), ElementName); 00202 badnet = true; 00203 } 00204 else 00205 { 00206 if (FindPad (ElementName, PinNum, conn, Same)) 00207 return (true); 00208 if (Same) 00209 return (false); 00210 if (PinNum[j - 1] < '0' || PinNum[j - 1] > '9') 00211 { 00212 Message ("WARNING! Pin number ending with '%c'" 00213 " encountered in netlist file\n" 00214 "Probably a bad netlist file format\n", PinNum[j - 1]); 00215 } 00216 } 00217 Message (_("Can't find %s pin %s called for in netlist.\n"), 00218 ElementName, PinNum); 00219 return (false); 00220 } 00221 00225 NetListType * 00226 ProcNetlist (LibraryType *net_menu) 00227 { 00228 ConnectionType *connection; 00229 ConnectionType LastPoint; 00230 NetType *net; 00231 static NetListType *Wantlist = NULL; 00232 00233 if (!net_menu->MenuN) 00234 return (NULL); 00235 FreeNetListMemory (Wantlist); 00236 free (Wantlist); 00237 badnet = false; 00238 00239 /* find layer groups of the component side and solder side */ 00240 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); 00241 top_group = GetLayerGroupNumberBySide (TOP_SIDE); 00242 00243 Wantlist = (NetListType *)calloc (1, sizeof (NetListType)); 00244 if (Wantlist) 00245 { 00246 ALLPIN_LOOP (PCB->Data); 00247 { 00248 pin->Spare = NULL; 00249 CLEAR_FLAG (DRCFLAG, pin); 00250 } 00251 ENDALL_LOOP; 00252 ALLPAD_LOOP (PCB->Data); 00253 { 00254 pad->Spare = NULL; 00255 CLEAR_FLAG (DRCFLAG, pad); 00256 } 00257 ENDALL_LOOP; 00258 MENU_LOOP (net_menu); 00259 { 00260 if (menu->Name[0] == '*' || menu->flag == 0) 00261 { 00262 badnet = true; 00263 continue; 00264 } 00265 net = GetNetMemory (Wantlist); 00266 if (menu->Style) 00267 { 00268 STYLE_LOOP (PCB); 00269 { 00270 if (style->Name && !NSTRCMP (style->Name, menu->Style)) 00271 { 00272 net->Style = style; 00273 break; 00274 } 00275 } 00276 END_LOOP; 00277 } 00278 else /* default to NULL if none found */ 00279 net->Style = NULL; 00280 ENTRY_LOOP (menu); 00281 { 00282 if (SeekPad (entry, &LastPoint, false)) 00283 { 00284 if (TEST_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2)) 00285 Message (_ 00286 ("Error! Element %s pin %s appears multiple times in the netlist file.\n"), 00287 NAMEONPCB_NAME ((ElementType *) LastPoint.ptr1), 00288 (LastPoint.type == 00289 PIN_TYPE) ? ((PinType *) LastPoint.ptr2)-> 00290 Number : ((PadType *) LastPoint.ptr2)->Number); 00291 else 00292 { 00293 connection = GetConnectionMemory (net); 00294 *connection = LastPoint; 00295 /* indicate expect net */ 00296 connection->menu = menu; 00297 /* mark as visited */ 00298 SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); 00299 if (LastPoint.type == PIN_TYPE) 00300 ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; 00301 else 00302 ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; 00303 } 00304 } 00305 else 00306 badnet = true; 00307 /* check for more pins with the same number */ 00308 for (; SeekPad (entry, &LastPoint, true);) 00309 { 00310 connection = GetConnectionMemory (net); 00311 *connection = LastPoint; 00312 /* indicate expect net */ 00313 connection->menu = menu; 00314 /* mark as visited */ 00315 SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); 00316 if (LastPoint.type == PIN_TYPE) 00317 ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; 00318 else 00319 ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; 00320 } 00321 } 00322 END_LOOP; 00323 } 00324 END_LOOP; 00325 } 00326 /* clear all visit marks */ 00327 ALLPIN_LOOP (PCB->Data); 00328 { 00329 CLEAR_FLAG (DRCFLAG, pin); 00330 } 00331 ENDALL_LOOP; 00332 ALLPAD_LOOP (PCB->Data); 00333 { 00334 CLEAR_FLAG (DRCFLAG, pad); 00335 } 00336 ENDALL_LOOP; 00337 return (Wantlist); 00338 } 00339 00344 static void 00345 TransferNet (NetListType *Netl, NetType *SourceNet, NetType *DestNet) 00346 { 00347 ConnectionType *conn; 00348 00349 /* It would be worth checking if SourceNet is NULL here to avoid a segfault. Seb James. */ 00350 CONNECTION_LOOP (SourceNet); 00351 { 00352 conn = GetConnectionMemory (DestNet); 00353 *conn = *connection; 00354 } 00355 END_LOOP; 00356 DestNet->Style = SourceNet->Style; 00357 /* free the connection memory */ 00358 FreeNetMemory (SourceNet); 00359 /* remove SourceNet from its netlist */ 00360 *SourceNet = Netl->Net[--(Netl->NetN)]; 00361 /* zero out old garbage */ 00362 memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType)); 00363 } 00364 00365 static bool 00366 CheckShorts (LibraryMenuType *theNet) 00367 { 00368 bool newone, warn = false; 00369 PointerListType *generic = (PointerListType *)calloc (1, sizeof (PointerListType)); 00370 /* the first connection was starting point so 00371 * the menu is always non-null 00372 */ 00373 void **menu = GetPointerMemory (generic); 00374 00375 *menu = theNet; 00376 ALLPIN_LOOP (PCB->Data); 00377 { 00378 if (TEST_FLAG (DRCFLAG, pin)) 00379 { 00380 warn = true; 00381 if (!pin->Spare) 00382 { 00383 Message (_("Warning! Net \"%s\" is shorted to %s pin %s\n"), 00384 &theNet->Name[2], 00385 UNKNOWN (NAMEONPCB_NAME (element)), 00386 UNKNOWN (pin->Number)); 00387 SET_FLAG (WARNFLAG, pin); 00388 continue; 00389 } 00390 newone = true; 00391 POINTER_LOOP (generic); 00392 { 00393 if (*ptr == pin->Spare) 00394 { 00395 newone = false; 00396 break; 00397 } 00398 } 00399 END_LOOP; 00400 if (newone) 00401 { 00402 menu = GetPointerMemory (generic); 00403 *menu = pin->Spare; 00404 Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"), 00405 &theNet->Name[2], 00406 &((LibraryMenuType *) (pin->Spare))->Name[2]); 00407 SET_FLAG (WARNFLAG, pin); 00408 } 00409 } 00410 } 00411 ENDALL_LOOP; 00412 ALLPAD_LOOP (PCB->Data); 00413 { 00414 if (TEST_FLAG (DRCFLAG, pad)) 00415 { 00416 warn = true; 00417 if (!pad->Spare) 00418 { 00419 Message (_("Warning! Net \"%s\" is shorted to %s pad %s\n"), 00420 &theNet->Name[2], 00421 UNKNOWN (NAMEONPCB_NAME (element)), 00422 UNKNOWN (pad->Number)); 00423 SET_FLAG (WARNFLAG, pad); 00424 continue; 00425 } 00426 newone = true; 00427 POINTER_LOOP (generic); 00428 { 00429 if (*ptr == pad->Spare) 00430 { 00431 newone = false; 00432 break; 00433 } 00434 } 00435 END_LOOP; 00436 if (newone) 00437 { 00438 menu = GetPointerMemory (generic); 00439 *menu = pad->Spare; 00440 Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"), 00441 &theNet->Name[2], 00442 &((LibraryMenuType *) (pad->Spare))->Name[2]); 00443 SET_FLAG (WARNFLAG, pad); 00444 } 00445 } 00446 } 00447 ENDALL_LOOP; 00448 FreePointerListMemory (generic); 00449 free (generic); 00450 return (warn); 00451 } 00452 00453 00462 static bool 00463 GatherSubnets (NetListType *Netl, bool NoWarn, bool AndRats) 00464 { 00465 NetType *a, *b; 00466 ConnectionType *conn; 00467 Cardinal m, n; 00468 bool Warned = false; 00469 00470 for (m = 0; Netl->NetN > 0 && m < Netl->NetN; m++) 00471 { 00472 a = &Netl->Net[m]; 00473 ClearFlagOnAllObjects (false, DRCFLAG); 00474 RatFindHook (a->Connection[0].type, a->Connection[0].ptr1, 00475 a->Connection[0].ptr2, a->Connection[0].ptr2, 00476 false, DRCFLAG, AndRats); 00477 /* now anybody connected to the first point has DRCFLAG set */ 00478 /* so move those to this subnet */ 00479 CLEAR_FLAG (DRCFLAG, (PinType *) a->Connection[0].ptr2); 00480 for (n = m + 1; n < Netl->NetN; n++) 00481 { 00482 b = &Netl->Net[n]; 00483 /* There can be only one connection in net b */ 00484 if (TEST_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2)) 00485 { 00486 CLEAR_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2); 00487 TransferNet (Netl, b, a); 00488 /* back up since new subnet is now at old index */ 00489 n--; 00490 } 00491 } 00492 /* now add other possible attachment points to the subnet */ 00493 /* e.g. line end-points and vias */ 00494 /* don't add non-manhattan lines, the auto-router can't route to them */ 00495 ALLLINE_LOOP (PCB->Data); 00496 { 00497 if (TEST_FLAG (DRCFLAG, line)) 00498 { 00499 conn = GetConnectionMemory (a); 00500 conn->X = line->Point1.X; 00501 conn->Y = line->Point1.Y; 00502 conn->type = LINE_TYPE; 00503 conn->ptr1 = layer; 00504 conn->ptr2 = line; 00505 conn->group = GetLayerGroupNumberByPointer (layer); 00506 conn->menu = NULL; /* agnostic view of where it belongs */ 00507 conn = GetConnectionMemory (a); 00508 conn->X = line->Point2.X; 00509 conn->Y = line->Point2.Y; 00510 conn->type = LINE_TYPE; 00511 conn->ptr1 = layer; 00512 conn->ptr2 = line; 00513 conn->group = GetLayerGroupNumberByPointer (layer); 00514 conn->menu = NULL; 00515 } 00516 } 00517 ENDALL_LOOP; 00518 /* add polygons so the auto-router can see them as targets */ 00519 ALLPOLYGON_LOOP (PCB->Data); 00520 { 00521 if (TEST_FLAG (DRCFLAG, polygon)) 00522 { 00523 conn = GetConnectionMemory (a); 00524 /* make point on a vertex */ 00525 conn->X = polygon->Clipped->contours->head.point[0]; 00526 conn->Y = polygon->Clipped->contours->head.point[1]; 00527 conn->type = POLYGON_TYPE; 00528 conn->ptr1 = layer; 00529 conn->ptr2 = polygon; 00530 conn->group = GetLayerGroupNumberByPointer (layer); 00531 conn->menu = NULL; /* agnostic view of where it belongs */ 00532 } 00533 } 00534 ENDALL_LOOP; 00535 VIA_LOOP (PCB->Data); 00536 { 00537 if (TEST_FLAG (DRCFLAG, via)) 00538 { 00539 conn = GetConnectionMemory (a); 00540 conn->X = via->X; 00541 conn->Y = via->Y; 00542 conn->type = VIA_TYPE; 00543 conn->ptr1 = via; 00544 conn->ptr2 = via; 00545 conn->group = bottom_group; 00546 } 00547 } 00548 END_LOOP; 00549 if (!NoWarn) 00550 Warned |= CheckShorts (a->Connection[0].menu); 00551 } 00552 ClearFlagOnAllObjects (false, DRCFLAG); 00553 return (Warned); 00554 } 00555 00590 static bool 00591 DrawShortestRats (NetListType *Netl, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) 00592 { 00593 RatType *line; 00594 register float distance, temp; 00595 register ConnectionType *conn1, *conn2, *firstpoint, *secondpoint; 00596 PolygonType *polygon; 00597 bool changed = false; 00598 bool havepoints; 00599 Cardinal n, m, j; 00600 NetType *next, *subnet, *theSubnet = NULL; 00601 00602 /* This is just a sanity check, to make sure we're passed 00603 * *something*. 00604 */ 00605 if (!Netl || Netl->NetN < 1) 00606 return false; 00607 00608 /* 00609 * We keep doing this do/while loop until everything's connected. 00610 * I.e. once per rat we add. 00611 */ 00612 distance = 0.0; 00613 havepoints = true; /* so we run the loop at least once */ 00614 while (Netl->NetN > 1 && havepoints) 00615 { 00616 /* This is the top of the "find one rat" logic. */ 00617 havepoints = false; 00618 firstpoint = secondpoint = NULL; 00619 00620 /* Test Net[0] vs Net[N] for N=1..max. Find the shortest 00621 distance between any two points in different blobs. */ 00622 subnet = &Netl->Net[0]; 00623 for (j = 1; j < Netl->NetN; j++) 00624 { 00625 /* 00626 * Scan between Net[0] blob (subnet) and Net[N] blob (next). 00627 * Note the shortest distance we find. 00628 */ 00629 next = &Netl->Net[j]; 00630 for (n = subnet->ConnectionN - 1; n != -1; n--) 00631 { 00632 conn1 = &subnet->Connection[n]; 00633 for (m = next->ConnectionN - 1; m != -1; m--) 00634 { 00635 conn2 = &next->Connection[m]; 00636 /* 00637 * At this point, conn1 and conn2 are two pins in 00638 * different blobs of the same net. See how far 00639 * apart they are, and if they're "closer" than what 00640 * we already have. 00641 */ 00642 00643 /* 00644 * Prefer to connect Connections over polygons to the 00645 * polygons (ie assume the user wants a via to a plane, 00646 * not a daisy chain). Further prefer to pick an existing 00647 * via in the Net to make that connection. 00648 */ 00649 if (conn1->type == POLYGON_TYPE && 00650 (polygon = (PolygonType *)conn1->ptr2) && 00651 !(distance == 0 && 00652 firstpoint && firstpoint->type == VIA_TYPE) && 00653 IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon)) 00654 { 00655 distance = 0; 00656 firstpoint = conn2; 00657 secondpoint = conn1; 00658 theSubnet = next; 00659 havepoints = true; 00660 } 00661 else if (conn2->type == POLYGON_TYPE && 00662 (polygon = (PolygonType *)conn2->ptr2) && 00663 !(distance == 0 && 00664 firstpoint && firstpoint->type == VIA_TYPE) && 00665 IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon)) 00666 { 00667 distance = 0; 00668 firstpoint = conn1; 00669 secondpoint = conn2; 00670 theSubnet = next; 00671 havepoints = true; 00672 } 00673 else if ((temp = SQUARE (conn1->X - conn2->X) + 00674 SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint) 00675 { 00676 distance = temp; 00677 firstpoint = conn1; 00678 secondpoint = conn2; 00679 theSubnet = next; 00680 havepoints = true; 00681 } 00682 } 00683 } 00684 } 00685 00686 /* 00687 * If HAVEPOINTS is true, we've found a pair of points in two 00688 * separate blobs of the net, and need to connect them together. 00689 */ 00690 if (havepoints) 00691 { 00692 if (funcp) 00693 { 00694 (*funcp) (firstpoint, secondpoint, subnet->Style); 00695 } 00696 else 00697 { 00698 /* found the shortest distance subnet, draw the rat */ 00699 if ((line = CreateNewRat (PCB->Data, 00700 firstpoint->X, firstpoint->Y, 00701 secondpoint->X, secondpoint->Y, 00702 firstpoint->group, secondpoint->group, 00703 Settings.RatThickness, 00704 NoFlags ())) != NULL) 00705 { 00706 if (distance == 0) 00707 SET_FLAG (VIAFLAG, line); 00708 AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line); 00709 DrawRat (line); 00710 changed = true; 00711 } 00712 } 00713 00714 /* copy theSubnet into the current subnet */ 00715 TransferNet (Netl, theSubnet, subnet); 00716 } 00717 } 00718 00719 /* presently nothing to do with the new subnet */ 00720 /* so we throw it away and free the space */ 00721 FreeNetMemory (&Netl->Net[--(Netl->NetN)]); 00722 /* Sadly adding a rat line messes up the sorted arrays in connection finder */ 00723 /* hace: perhaps not necessarily now that they aren't stored in normal layers */ 00724 if (changed) 00725 { 00726 FreeConnectionLookupMemory (); 00727 InitConnectionLookup (); 00728 } 00729 return (changed); 00730 } 00731 00732 00740 bool 00741 AddAllRats (bool SelectedOnly, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) 00742 { 00743 NetListType *Nets, *Wantlist; 00744 NetType *lonesome; 00745 ConnectionType *onepin; 00746 bool changed, Warned = false; 00747 00748 /* the netlist library has the text form 00749 * ProcNetlist fills in the Netlist 00750 * structure the way the final routing 00751 * is supposed to look 00752 */ 00753 Wantlist = ProcNetlist (&PCB->NetlistLib); 00754 if (!Wantlist) 00755 { 00756 Message (_("Can't add rat lines because no netlist is loaded.\n")); 00757 return (false); 00758 } 00759 changed = false; 00760 /* initialize finding engine */ 00761 InitConnectionLookup (); 00762 Nets = (NetListType *)calloc (1, sizeof (NetListType)); 00763 /* now we build another netlist (Nets) for each 00764 * net in Wantlist that shows how it actually looks now, 00765 * then fill in any missing connections with rat lines. 00766 * 00767 * we first assume each connection is separate 00768 * (no routing), then gather them into groups 00769 * if the net is all routed, the new netlist (Nets) 00770 * will have only one net entry. 00771 * Note that DrawShortestRats consumes all nets 00772 * from Nets, so *Nets is empty after the 00773 * DrawShortestRats call 00774 */ 00775 NET_LOOP (Wantlist); 00776 { 00777 CONNECTION_LOOP (net); 00778 { 00779 if (!SelectedOnly 00780 || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2)) 00781 { 00782 lonesome = GetNetMemory (Nets); 00783 onepin = GetConnectionMemory (lonesome); 00784 *onepin = *connection; 00785 lonesome->Style = net->Style; 00786 } 00787 } 00788 END_LOOP; 00789 Warned |= GatherSubnets (Nets, SelectedOnly, true); 00790 if (Nets->NetN > 0) 00791 changed |= DrawShortestRats (Nets, funcp); 00792 } 00793 END_LOOP; 00794 FreeNetListMemory (Nets); 00795 free (Nets); 00796 FreeConnectionLookupMemory (); 00797 if (funcp) 00798 return (true); 00799 00800 if (Warned || changed) 00801 Draw (); 00802 00803 if (Warned) 00804 Settings.RatWarn = true; 00805 00806 if (changed) 00807 { 00808 IncrementUndoSerialNumber (); 00809 if (PCB->Data->RatN > 0) 00810 { 00811 Message ("%d rat line%s remaining\n", PCB->Data->RatN, 00812 PCB->Data->RatN > 1 ? "s" : ""); 00813 } 00814 return (true); 00815 } 00816 if (!SelectedOnly && !Warned) 00817 { 00818 if (!PCB->Data->RatN && !badnet) 00819 Message (_("Congratulations!!\n" 00820 "The layout is complete and has no shorted nets.\n")); 00821 else 00822 Message (_("Nothing more to add, but there are\n" 00823 "either rat-lines in the layout, disabled nets\n" 00824 "in the net-list, or missing components\n")); 00825 } 00826 return (false); 00827 } 00828 00834 NetListListType 00835 CollectSubnets (bool SelectedOnly) 00836 { 00837 NetListListType result = { 0, 0, NULL }; 00838 NetListType *Nets, *Wantlist; 00839 NetType *lonesome; 00840 ConnectionType *onepin; 00841 00842 /* the netlist library has the text form 00843 * ProcNetlist fills in the Netlist 00844 * structure the way the final routing 00845 * is supposed to look 00846 */ 00847 Wantlist = ProcNetlist (&PCB->NetlistLib); 00848 if (!Wantlist) 00849 { 00850 Message (_("Can't add rat lines because no netlist is loaded.\n")); 00851 return result; 00852 } 00853 /* initialize finding engine */ 00854 InitConnectionLookup (); 00855 /* now we build another netlist (Nets) for each 00856 * net in Wantlist that shows how it actually looks now, 00857 * then fill in any missing connections with rat lines. 00858 * 00859 * we first assume each connection is separate 00860 * (no routing), then gather them into groups 00861 * if the net is all routed, the new netlist (Nets) 00862 * will have only one net entry. 00863 * Note that DrawShortestRats consumes all nets 00864 * from Nets, so *Nets is empty after the 00865 * DrawShortestRats call 00866 */ 00867 NET_LOOP (Wantlist); 00868 { 00869 Nets = GetNetListMemory (&result); 00870 CONNECTION_LOOP (net); 00871 { 00872 if (!SelectedOnly 00873 || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2)) 00874 { 00875 lonesome = GetNetMemory (Nets); 00876 onepin = GetConnectionMemory (lonesome); 00877 *onepin = *connection; 00878 lonesome->Style = net->Style; 00879 } 00880 } 00881 END_LOOP; 00882 /* Note that AndRats is *FALSE* here! */ 00883 GatherSubnets (Nets, SelectedOnly, false); 00884 } 00885 END_LOOP; 00886 FreeConnectionLookupMemory (); 00887 return result; 00888 } 00889 00894 static int 00895 rat_used (char *name) 00896 { 00897 if (name == NULL) 00898 return -1; 00899 00900 MENU_LOOP (&PCB->NetlistLib); 00901 { 00902 if (menu->Name && (strcmp (menu->Name, name) == 0)) 00903 return 1; 00904 } 00905 END_LOOP; 00906 00907 return 0; 00908 } 00909 00914 RatType * 00915 AddNet (void) 00916 { 00917 static int ratDrawn = 0; 00918 char name1[256], *name2; 00919 Cardinal group1, group2; 00920 char ratname[20]; 00921 int found; 00922 void *ptr1, *ptr2, *ptr3; 00923 LibraryMenuType *menu; 00924 LibraryEntryType *entry; 00925 00926 if (Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X 00927 && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y) 00928 return (NULL); 00929 00930 found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, 00931 Crosshair.AttachedLine.Point1.X, 00932 Crosshair.AttachedLine.Point1.Y, 5); 00933 if (found == NO_TYPE) 00934 { 00935 Message (_("No pad/pin under rat line\n")); 00936 return (NULL); 00937 } 00938 if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL 00939 || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) 00940 { 00941 Message (_("You must name the starting element first\n")); 00942 return (NULL); 00943 } 00944 00945 /* will work for pins to since the FLAG is common */ 00946 group1 = GetLayerGroupNumberBySide ( 00947 TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); 00948 strcpy (name1, ConnectionName (found, ptr1, ptr2)); 00949 found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, 00950 Crosshair.AttachedLine.Point2.X, 00951 Crosshair.AttachedLine.Point2.Y, 5); 00952 if (found == NO_TYPE) 00953 { 00954 Message (_("No pad/pin under rat line\n")); 00955 return (NULL); 00956 } 00957 if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL 00958 || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) 00959 { 00960 Message (_("You must name the ending element first\n")); 00961 return (NULL); 00962 } 00963 group2 = GetLayerGroupNumberBySide ( 00964 TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); 00965 name2 = ConnectionName (found, ptr1, ptr2); 00966 00967 menu = netnode_to_netname (name1); 00968 if (menu) 00969 { 00970 if (netnode_to_netname (name2)) 00971 { 00972 Message (_ 00973 ("Both connections already in netlist - cannot merge nets\n")); 00974 return (NULL); 00975 } 00976 entry = GetLibraryEntryMemory (menu); 00977 entry->ListEntry = strdup (name2); 00978 netnode_to_netname (name2); 00979 goto ratIt; 00980 } 00981 /* ok, the first name did not belong to a net */ 00982 menu = netnode_to_netname (name2); 00983 if (menu) 00984 { 00985 entry = GetLibraryEntryMemory (menu); 00986 entry->ListEntry = strdup (name1); 00987 netnode_to_netname (name1); 00988 goto ratIt; 00989 } 00990 00991 /* 00992 * neither belong to a net, so create a new one. 00993 * 00994 * before creating a new rats here, we need to search 00995 * for a unique name. 00996 */ 00997 sprintf (ratname, " ratDrawn%i", ++ratDrawn); 00998 while (rat_used (ratname)) 00999 { 01000 sprintf (ratname, " ratDrawn%i", ++ratDrawn); 01001 } 01002 01003 menu = GetLibraryMenuMemory (&PCB->NetlistLib); 01004 menu->Name = strdup (ratname); 01005 entry = GetLibraryEntryMemory (menu); 01006 entry->ListEntry = strdup (name1); 01007 entry = GetLibraryEntryMemory (menu); 01008 entry->ListEntry = strdup (name2); 01009 menu->flag = 1; 01010 01011 ratIt: 01012 NetlistChanged (0); 01013 return (CreateNewRat (PCB->Data, Crosshair.AttachedLine.Point1.X, 01014 Crosshair.AttachedLine.Point1.Y, 01015 Crosshair.AttachedLine.Point2.X, 01016 Crosshair.AttachedLine.Point2.Y, 01017 group1, group2, Settings.RatThickness, NoFlags ())); 01018 } 01019 01024 char * 01025 ConnectionName (int type, void *ptr1, void *ptr2) 01026 { 01027 static char name[256]; 01028 char *num; 01029 01030 switch (type) 01031 { 01032 case PIN_TYPE: 01033 num = ((PinType *) ptr2)->Number; 01034 break; 01035 case PAD_TYPE: 01036 num = ((PadType *) ptr2)->Number; 01037 break; 01038 default: 01039 return (NULL); 01040 } 01041 strcpy (name, UNKNOWN (NAMEONPCB_NAME ((ElementType *) ptr1))); 01042 strcat (name, "-"); 01043 strcat (name, UNKNOWN (num)); 01044 return (name); 01045 }