/* XXX: This is copied in large part from AddAllRats above; for * maintainability, AddAllRats probably wants to be tweaked to use this * version of the code so that we don't have duplication. */ NetListListType CollectSubnets (bool SelectedOnly) { NetListListType result = { 0, 0, NULL }; NetListTypePtr Nets, Wantlist; NetTypePtr lonesome; ConnectionTypePtr onepin; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return result; } /* initialize finding engine */ InitConnectionLookup (); SaveFindFlag (DRCFLAG); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { Nets = GetNetListMemory (&result); CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinTypePtr) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; /* Note that AndRats is *FALSE* here! */ GatherSubnets (Nets, SelectedOnly, false); } END_LOOP; FreeConnectionLookupMemory (); RestoreFindFlag (); return result; }
/* returns 0 on succes */ static int proc_short(PinType *pin, PadType *pad, int ignore) { find_callback_t old_cb; Coord x, y; short_conn_t *n, **lut_by_oid, **lut_by_gid, *next; int gids; gr_t *g; void *S, *T; int *solution; int i, maxedges; int bad_gr = 0; if (!TEST_FLAG (ENABLEMINCUTFLAG, PCB)) return bad_gr; if (!Settings.EnableMincut) return bad_gr; /* only one should be set, but one must be set */ assert((pin != NULL) || (pad != NULL)); assert((pin == NULL) || (pad == NULL)); if (pin != NULL) { debprintf("short on pin!\n"); SET_FLAG (WARNFLAG, pin); x = pin->X; y = pin->Y; } else if (pad != NULL) { debprintf("short on pad!\n"); SET_FLAG (WARNFLAG, pad); if (TEST_FLAG (EDGE2FLAG, pad)) { x = pad->Point2.X; y = pad->Point2.Y; } else { x = pad->Point1.X; y = pad->Point1.Y; } } /* run only if net is not ignored */ if (ignore) return 0; short_conns = NULL; num_short_conns = 0; short_conns_maxid = 0; /* perform a search using MINCUTFLAG, calling back proc_short_cb() with the connections */ old_cb = find_callback; find_callback = proc_short_cb; SaveFindFlag(MINCUTFLAG); LookupConnection (x, y, false, 1, MINCUTFLAG); debprintf("- alloced for %d\n", (short_conns_maxid+1)); lut_by_oid = calloc(sizeof(short_conn_t *), (short_conns_maxid+1)); lut_by_gid = calloc(sizeof(short_conn_t *), (num_short_conns+3)); g = gr_alloc(num_short_conns+2); g->node2name = calloc(sizeof(char *), (num_short_conns+2)); /* conn 0 is S and conn 1 is T and set up lookup arrays */ for(n = short_conns, gids=2; n != NULL; n = n->next, gids++) { char *s, *typ; ElementType *parent; n->gid = gids; debprintf(" {%d} found %d %d/%p type %d from %d\n", n->gid, n->to_type, n->to->ID, n->to, n->type, n->from_id); lut_by_oid[n->to->ID] = n; lut_by_gid[n->gid] = n; s = malloc(256); parent = NULL; switch(n->to_type) { case PIN_TYPE: typ = "pin"; parent = ((PinType *)(n->to))->Element; break; case VIA_TYPE: typ = "via"; parent = ((PinType *)(n->to))->Element; break; case PAD_TYPE: typ = "pad"; parent = ((PadType *)(n->to))->Element; break; case LINE_TYPE: typ = "line"; break; default: typ="other"; break; } if (parent != NULL) { TextType *name; name = &parent->Name[1]; if ((name->TextString == NULL) || (*name->TextString == '\0')) sprintf(s, "%s #%d \\nof #%d", typ, n->to->ID, parent->ID); else sprintf(s, "%s #%d \\nof %s", typ, n->to->ID, name->TextString); } else sprintf(s, "%s #%d", typ, n->to->ID); g->node2name[n->gid] = s; } g->node2name[0] = strdup("S"); g->node2name[1] = strdup("T"); /* calculate how many edges each node has and the max edge count */ maxedges = 0; for(n = short_conns; n != NULL; n = n->next) { short_conn_t *from; n->edges++; if (n->edges > maxedges) maxedges = n->edges; if (n->from_id >= 0) { from = lut_by_oid[n->from_id]; if (from == NULL) { /* no from means broken graph (multiple components) */ if (n->from_id >= 2) { /* ID 0 and 1 are start/stop, there won't be from for them */ fprintf(stderr, "rats_mincut.c error: graph has multiple components, bug in find.c (n->from_id=%d)!\n", n->from_id); bad_gr = 1; } continue; } from->edges++; if (from->edges > maxedges) maxedges = from->edges; } } S = NULL; T = NULL; for(n = short_conns; n != NULL; n = n->next) { short_conn_t *from; void *spare; spare = NULL; if (n->to_type == PIN_TYPE) spare = ((PinType *)n->to)->Spare; if (n->to_type == PAD_TYPE) spare = ((PadType *)n->to)->Spare; if (spare != NULL) { void *net = &(((LibraryMenuTypePtr)spare)->Name[2]); debprintf(" net=%s\n", net); if (S == NULL) { debprintf(" -> became S\n"); S = net; } else if ((T == NULL) && (net != S)) { debprintf(" -> became T\n"); T = net; } if (net == S) gr_add_(g, n->gid, 0, 100000); else if (net == T) gr_add_(g, n->gid, 1, 100000); } /* if we have a from object, look it up and make a connection between the two gids */ if (n->from_id >= 0) { int weight; short_conn_t *from = lut_by_oid[n->from_id]; from = lut_by_oid[n->from_id]; /* weight: 1 for connections we can break, large value for connections we shall not break */ if ((n->type == FCT_COPPER) || (n->type == FCT_START)) { /* connection to a pin/pad is slightly stronger than the strongest obj-obj conn; obj-obj conns are weaker at junctions where many objects connect */ if ((n->from_type == PIN_TYPE) || (n->from_type == PAD_TYPE) || (n->to_type == PIN_TYPE) || (n->to_type == PAD_TYPE)) weight = maxedges*2 + 2; else weight = maxedges*2 - n->edges - from->edges + 1; } else weight = 10000; if (from != NULL) { gr_add_(g, n->gid, from->gid, weight); debprintf(" CONN %d %d\n", n->gid, from->gid); } } } /*#define MINCUT_DRAW*/ #ifdef MINCUT_DRAW { static int drw = 0; char gfn[256]; drw++; sprintf(gfn, "A_%d_a", drw); debprintf("gfn=%s\n", gfn); gr_draw(g, gfn, "png"); } #endif if (!bad_gr) { solution = solve(g); if (solution != NULL) { debprintf("Would cut:\n"); for(i = 0; solution[i] != -1; i++) { short_conn_t *s; debprintf("%d:", i); s = lut_by_gid[solution[i]]; debprintf("%d %p", solution[i], s); if (s != NULL) { SET_FLAG (WARNFLAG, s->to); debprintf(" -> %d", s->to->ID); } debprintf("\n"); } free(solution); } else { fprintf(stderr, "mincut didn't find a solution, falling back to the old warn\n"); bad_gr=1; } } free(lut_by_oid); free(lut_by_gid); for(n = short_conns; n != NULL; n = next) { next = n->next; free(n); } ResetFoundLinesAndPolygons(false); ResetFoundPinsViasAndPads(false); RestoreFindFlag(); find_callback = old_cb; return bad_gr; }
/* --------------------------------------------------------------------------- * AddAllRats puts the rats nest into the layout from the loaded netlist * if SelectedOnly is true, it will only draw rats to selected pins and pads */ bool AddAllRats (bool SelectedOnly, void (*funcp) (register ConnectionTypePtr, register ConnectionTypePtr, register RouteStyleTypePtr)) { NetListTypePtr Nets, Wantlist; NetTypePtr lonesome; ConnectionTypePtr onepin; bool changed, Warned = false; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return (false); } changed = false; /* initialize finding engine */ InitConnectionLookup (); SaveFindFlag (DRCFLAG); Nets = (NetListTypePtr)calloc (1, sizeof (NetListType)); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinTypePtr) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; Warned |= GatherSubnets (Nets, SelectedOnly, true); if (Nets->NetN > 0) changed |= DrawShortestRats (Nets, funcp); } END_LOOP; FreeNetListMemory (Nets); free (Nets); FreeConnectionLookupMemory (); RestoreFindFlag (); if (funcp) return (true); if (Warned || changed) Draw (); if (Warned) Settings.RatWarn = true; if (changed) { IncrementUndoSerialNumber (); if (PCB->Data->RatN > 0) { Message ("%d rat line%s remaining\n", PCB->Data->RatN, PCB->Data->RatN > 1 ? "s" : ""); } return (true); } if (!SelectedOnly && !Warned) { if (!PCB->Data->RatN && !badnet) Message (_("Congratulations!!\n" "The layout is complete and has no shorted nets.\n")); else Message (_("Nothing more to add, but there are\n" "either rat-lines in the layout, disabled nets\n" "in the net-list, or missing components\n")); } return (false); }