4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This module, rats.c, was written and is Copyright (C) 1997 by harry eaton
8 * this module is also subject to the GNU GPL as described below
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Added support for minimum length rat lines 6/13/97
29 * rat lines to nearest line/via 8/29/98
30 * support for netlist window 10/24/98
58 #ifdef HAVE_LIBDMALLOC
62 #define TRIEDFIRST 0x1
65 /* ---------------------------------------------------------------------------
66 * some forward declarations
68 static bool FindPad (char *, char *, ConnectionType
*, bool);
69 static bool ParseConnection (char *, char *, char *);
70 static bool DrawShortestRats (NetListType
*, void (*)(register ConnectionType
*, register ConnectionType
*, register RouteStyleType
*));
71 static bool GatherSubnets (NetListType
*, bool, bool);
72 static bool CheckShorts (LibraryMenuType
*);
73 static void TransferNet (NetListType
*, NetType
*, NetType
*);
75 /* ---------------------------------------------------------------------------
76 * some local identifiers
78 static bool badnet
= false;
79 static Cardinal SLayer
, CLayer
; /* layer group holding solder/component side */
81 /* ---------------------------------------------------------------------------
82 * parse a connection description from a string
83 * puts the element name in the string and the pin number in
84 * the number. If a valid connection is found, it returns the
85 * number of characters processed from the string, otherwise
89 ParseConnection (char *InString
, char *ElementName
, char *PinNum
)
93 /* copy element name portion */
94 for (j
= 0; InString
[j
] != '\0' && InString
[j
] != '-'; j
++)
95 ElementName
[j
] = InString
[j
];
96 if (InString
[j
] == '-')
98 for (i
= j
; i
> 0 && ElementName
[i
- 1] >= 'a'; i
--);
99 ElementName
[i
] = '\0';
100 for (i
= 0, j
++; InString
[j
] != '\0'; i
++, j
++)
101 PinNum
[i
] = InString
[j
];
107 ElementName
[j
] = '\0';
108 Message (_("Bad net-list format encountered near: \"%s\"\n"),
114 /* ---------------------------------------------------------------------------
115 * Find a particular pad from an element name and pin number
118 FindPad (char *ElementName
, char *PinNum
, ConnectionType
* conn
, bool Same
)
120 ElementType
*element
;
123 if ((element
= SearchElementByName (PCB
->Data
, ElementName
)) == NULL
)
126 for (i
= element
->Pad
; i
!= NULL
; i
= g_list_next (i
))
128 PadType
*pad
= i
->data
;
130 if (NSTRCMP (PinNum
, pad
->Number
) == 0 &&
131 (!Same
|| !TEST_FLAG (DRCFLAG
, pad
)))
133 conn
->type
= PAD_TYPE
;
134 conn
->ptr1
= element
;
136 conn
->group
= TEST_FLAG (ONSOLDERFLAG
, pad
) ? SLayer
: CLayer
;
138 if (TEST_FLAG (EDGE2FLAG
, pad
))
140 conn
->X
= pad
->Point2
.X
;
141 conn
->Y
= pad
->Point2
.Y
;
145 conn
->X
= pad
->Point1
.X
;
146 conn
->Y
= pad
->Point1
.Y
;
152 for (i
= element
->Pin
; i
!= NULL
; i
= g_list_next (i
))
154 PinType
*pin
= i
->data
;
156 if (!TEST_FLAG (HOLEFLAG
, pin
) &&
157 pin
->Number
&& NSTRCMP (PinNum
, pin
->Number
) == 0 &&
158 (!Same
|| !TEST_FLAG (DRCFLAG
, pin
)))
160 conn
->type
= PIN_TYPE
;
161 conn
->ptr1
= element
;
163 conn
->group
= SLayer
; /* any layer will do */
173 /*--------------------------------------------------------------------------
174 * parse a netlist menu entry and locate the corresponding pad
175 * returns true if found, and fills in Connection information
178 SeekPad (LibraryEntryType
* entry
, ConnectionType
* conn
, bool Same
)
181 char ElementName
[256];
184 if (ParseConnection (entry
->ListEntry
, ElementName
, PinNum
))
186 for (j
= 0; PinNum
[j
] != '\0'; j
++);
189 Message (_("Error! Netlist file is missing pin!\n"
190 "white space after \"%s-\"\n"), ElementName
);
195 if (FindPad (ElementName
, PinNum
, conn
, Same
))
199 if (PinNum
[j
- 1] < '0' || PinNum
[j
- 1] > '9')
201 Message ("WARNING! Pin number ending with '%c'"
202 " encountered in netlist file\n"
203 "Probably a bad netlist file format\n", PinNum
[j
- 1]);
206 Message (_("Can't find %s pin %s called for in netlist.\n"),
207 ElementName
, PinNum
);
211 /* ---------------------------------------------------------------------------
212 * Read the library-netlist build a true Netlist structure
216 ProcNetlist (LibraryType
*net_menu
)
218 ConnectionType
*connection
;
219 ConnectionType LastPoint
;
221 static NetListType
*Wantlist
= NULL
;
223 if (!net_menu
->MenuN
)
225 FreeNetListMemory (Wantlist
);
229 /* find layer groups of the component side and solder side */
230 SLayer
= GetLayerGroupNumberByNumber (solder_silk_layer
);
231 CLayer
= GetLayerGroupNumberByNumber (component_silk_layer
);
233 Wantlist
= (NetListType
*)calloc (1, sizeof (NetListType
));
236 ALLPIN_LOOP (PCB
->Data
);
239 CLEAR_FLAG (DRCFLAG
, pin
);
242 ALLPAD_LOOP (PCB
->Data
);
245 CLEAR_FLAG (DRCFLAG
, pad
);
248 MENU_LOOP (net_menu
);
250 if (menu
->Name
[0] == '*' || menu
->flag
== 0)
255 net
= GetNetMemory (Wantlist
);
260 if (style
->Name
&& !NSTRCMP (style
->Name
, menu
->Style
))
268 else /* default to NULL if none found */
272 if (SeekPad (entry
, &LastPoint
, false))
274 if (TEST_FLAG (DRCFLAG
, (PinType
*) LastPoint
.ptr2
))
276 ("Error! Element %s pin %s appears multiple times in the netlist file.\n"),
277 NAMEONPCB_NAME ((ElementType
*) LastPoint
.ptr1
),
279 PIN_TYPE
) ? ((PinType
*) LastPoint
.ptr2
)->
280 Number
: ((PadType
*) LastPoint
.ptr2
)->Number
);
283 connection
= GetConnectionMemory (net
);
284 *connection
= LastPoint
;
285 /* indicate expect net */
286 connection
->menu
= menu
;
287 /* mark as visited */
288 SET_FLAG (DRCFLAG
, (PinType
*) LastPoint
.ptr2
);
289 if (LastPoint
.type
== PIN_TYPE
)
290 ((PinType
*) LastPoint
.ptr2
)->Spare
= (void *) menu
;
292 ((PadType
*) LastPoint
.ptr2
)->Spare
= (void *) menu
;
297 /* check for more pins with the same number */
298 for (; SeekPad (entry
, &LastPoint
, true);)
300 connection
= GetConnectionMemory (net
);
301 *connection
= LastPoint
;
302 /* indicate expect net */
303 connection
->menu
= menu
;
304 /* mark as visited */
305 SET_FLAG (DRCFLAG
, (PinType
*) LastPoint
.ptr2
);
306 if (LastPoint
.type
== PIN_TYPE
)
307 ((PinType
*) LastPoint
.ptr2
)->Spare
= (void *) menu
;
309 ((PadType
*) LastPoint
.ptr2
)->Spare
= (void *) menu
;
316 /* clear all visit marks */
317 ALLPIN_LOOP (PCB
->Data
);
319 CLEAR_FLAG (DRCFLAG
, pin
);
322 ALLPAD_LOOP (PCB
->Data
);
324 CLEAR_FLAG (DRCFLAG
, pad
);
331 * copy all connections from one net into another
332 * and then remove the first net from its netlist
335 TransferNet (NetListType
*Netl
, NetType
*SourceNet
, NetType
*DestNet
)
337 ConnectionType
*conn
;
339 /* It would be worth checking if SourceNet is NULL here to avoid a segfault. Seb James. */
340 CONNECTION_LOOP (SourceNet
);
342 conn
= GetConnectionMemory (DestNet
);
346 DestNet
->Style
= SourceNet
->Style
;
347 /* free the connection memory */
348 FreeNetMemory (SourceNet
);
349 /* remove SourceNet from its netlist */
350 *SourceNet
= Netl
->Net
[--(Netl
->NetN
)];
351 /* zero out old garbage */
352 memset (&Netl
->Net
[Netl
->NetN
], 0, sizeof (NetType
));
356 CheckShorts (LibraryMenuType
*theNet
)
358 bool newone
, warn
= false;
359 PointerListType
*generic
= (PointerListType
*)calloc (1, sizeof (PointerListType
));
360 /* the first connection was starting point so
361 * the menu is always non-null
363 void **menu
= GetPointerMemory (generic
);
366 ALLPIN_LOOP (PCB
->Data
);
368 if (TEST_FLAG (DRCFLAG
, pin
))
373 Message (_("Warning! Net \"%s\" is shorted to %s pin %s\n"),
375 UNKNOWN (NAMEONPCB_NAME (element
)),
376 UNKNOWN (pin
->Number
));
377 SET_FLAG (WARNFLAG
, pin
);
381 POINTER_LOOP (generic
);
383 if (*ptr
== pin
->Spare
)
392 menu
= GetPointerMemory (generic
);
394 Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"),
396 &((LibraryMenuType
*) (pin
->Spare
))->Name
[2]);
397 SET_FLAG (WARNFLAG
, pin
);
402 ALLPAD_LOOP (PCB
->Data
);
404 if (TEST_FLAG (DRCFLAG
, pad
))
409 Message (_("Warning! Net \"%s\" is shorted to %s pad %s\n"),
411 UNKNOWN (NAMEONPCB_NAME (element
)),
412 UNKNOWN (pad
->Number
));
413 SET_FLAG (WARNFLAG
, pad
);
417 POINTER_LOOP (generic
);
419 if (*ptr
== pad
->Spare
)
428 menu
= GetPointerMemory (generic
);
430 Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"),
432 &((LibraryMenuType
*) (pad
->Spare
))->Name
[2]);
433 SET_FLAG (WARNFLAG
, pad
);
438 FreePointerListMemory (generic
);
444 /* ---------------------------------------------------------------------------
445 * Determine existing interconnections of the net and gather into sub-nets
447 * initially the netlist has each connection in its own individual net
448 * afterwards there can be many fewer nets with multiple connections each
451 GatherSubnets (NetListType
*Netl
, bool NoWarn
, bool AndRats
)
454 ConnectionType
*conn
;
458 for (m
= 0; Netl
->NetN
> 0 && m
< Netl
->NetN
; m
++)
461 ResetConnections (false);
462 RatFindHook (a
->Connection
[0].type
, a
->Connection
[0].ptr1
,
463 a
->Connection
[0].ptr2
, a
->Connection
[0].ptr2
, false,
465 /* now anybody connected to the first point has DRCFLAG set */
466 /* so move those to this subnet */
467 CLEAR_FLAG (DRCFLAG
, (PinType
*) a
->Connection
[0].ptr2
);
468 for (n
= m
+ 1; n
< Netl
->NetN
; n
++)
471 /* There can be only one connection in net b */
472 if (TEST_FLAG (DRCFLAG
, (PinType
*) b
->Connection
[0].ptr2
))
474 CLEAR_FLAG (DRCFLAG
, (PinType
*) b
->Connection
[0].ptr2
);
475 TransferNet (Netl
, b
, a
);
476 /* back up since new subnet is now at old index */
480 /* now add other possible attachment points to the subnet */
481 /* e.g. line end-points and vias */
482 /* don't add non-manhattan lines, the auto-router can't route to them */
483 ALLLINE_LOOP (PCB
->Data
);
485 if (TEST_FLAG (DRCFLAG
, line
)
486 && ((line
->Point1
.X
== line
->Point2
.X
)
487 || (line
->Point1
.Y
== line
->Point2
.Y
)))
489 conn
= GetConnectionMemory (a
);
490 conn
->X
= line
->Point1
.X
;
491 conn
->Y
= line
->Point1
.Y
;
492 conn
->type
= LINE_TYPE
;
495 conn
->group
= GetLayerGroupNumberByPointer (layer
);
496 conn
->menu
= NULL
; /* agnostic view of where it belongs */
497 conn
= GetConnectionMemory (a
);
498 conn
->X
= line
->Point2
.X
;
499 conn
->Y
= line
->Point2
.Y
;
500 conn
->type
= LINE_TYPE
;
503 conn
->group
= GetLayerGroupNumberByPointer (layer
);
508 /* add polygons so the auto-router can see them as targets */
509 ALLPOLYGON_LOOP (PCB
->Data
);
511 if (TEST_FLAG (DRCFLAG
, polygon
))
513 conn
= GetConnectionMemory (a
);
514 /* make point on a vertex */
515 conn
->X
= polygon
->Clipped
->contours
->head
.point
[0];
516 conn
->Y
= polygon
->Clipped
->contours
->head
.point
[1];
517 conn
->type
= POLYGON_TYPE
;
519 conn
->ptr2
= polygon
;
520 conn
->group
= GetLayerGroupNumberByPointer (layer
);
521 conn
->menu
= NULL
; /* agnostic view of where it belongs */
525 VIA_LOOP (PCB
->Data
);
527 if (TEST_FLAG (DRCFLAG
, via
))
529 conn
= GetConnectionMemory (a
);
532 conn
->type
= VIA_TYPE
;
535 conn
->group
= SLayer
;
540 Warned
|= CheckShorts (a
->Connection
[0].menu
);
542 ResetConnections (false);
546 /* ---------------------------------------------------------------------------
547 * Draw a rat net (tree) having the shortest lines
548 * this also frees the subnet memory as they are consumed
550 * Note that the Netl we are passed is NOT the main netlist - it's the
551 * connectivity for ONE net. It represents the CURRENT connectivity
552 * state for the net, with each Netl->Net[N] representing one
553 * copper-connected subset of the net.
557 DrawShortestRats (NetListType
*Netl
, void (*funcp
) (register ConnectionType
*, register ConnectionType
*, register RouteStyleType
*))
560 register float distance
, temp
;
561 register ConnectionType
*conn1
, *conn2
, *firstpoint
, *secondpoint
;
562 PolygonType
*polygon
;
563 bool changed
= false;
566 NetType
*next
, *subnet
, *theSubnet
= NULL
;
568 /* This is just a sanity check, to make sure we're passed
571 if (!Netl
|| Netl
->NetN
< 1)
575 * Everything inside the NetList Netl should be connected together.
576 * Each Net in Netl is a group of Connections which are already
577 * connected together somehow, either by real wires or by rats we've
578 * already drawn. Each Connection is a vertex within that blob of
579 * connected items. This loop finds the closest vertex pairs between
580 * each blob and draws rats that merge the blobs until there's just
583 * Just to clarify, with some examples:
585 * Each Netl is one full net from a netlist, like from gnetlist.
586 * Each Netl->Net[N] is a subset of that net that's already
587 * physically connected on the pcb.
589 * So a new design with no traces yet, would have a huge list of Net[N],
590 * each with one pin in it.
592 * A fully routed design would have one Net[N] with all the pins
593 * (for that net) in it.
597 * We keep doing this do/while loop until everything's connected.
598 * I.e. once per rat we add.
601 havepoints
= true; /* so we run the loop at least once */
602 while (Netl
->NetN
> 1 && havepoints
)
604 /* This is the top of the "find one rat" logic. */
606 firstpoint
= secondpoint
= NULL
;
608 /* Test Net[0] vs Net[N] for N=1..max. Find the shortest
609 distance between any two points in different blobs. */
610 subnet
= &Netl
->Net
[0];
611 for (j
= 1; j
< Netl
->NetN
; j
++)
614 * Scan between Net[0] blob (subnet) and Net[N] blob (next).
615 * Note the shortest distance we find.
617 next
= &Netl
->Net
[j
];
618 for (n
= subnet
->ConnectionN
- 1; n
!= -1; n
--)
620 conn1
= &subnet
->Connection
[n
];
621 for (m
= next
->ConnectionN
- 1; m
!= -1; m
--)
623 conn2
= &next
->Connection
[m
];
625 * At this point, conn1 and conn2 are two pins in
626 * different blobs of the same net. See how far
627 * apart they are, and if they're "closer" than what
632 * Prefer to connect Connections over polygons to the
633 * polygons (ie assume the user wants a via to a plane,
634 * not a daisy chain). Further prefer to pick an existing
635 * via in the Net to make that connection.
637 if (conn1
->type
== POLYGON_TYPE
&&
638 (polygon
= (PolygonType
*)conn1
->ptr2
) &&
640 firstpoint
&& firstpoint
->type
== VIA_TYPE
) &&
641 IsPointInPolygonIgnoreHoles (conn2
->X
, conn2
->Y
, polygon
))
649 else if (conn2
->type
== POLYGON_TYPE
&&
650 (polygon
= (PolygonType
*)conn2
->ptr2
) &&
652 firstpoint
&& firstpoint
->type
== VIA_TYPE
) &&
653 IsPointInPolygonIgnoreHoles (conn1
->X
, conn1
->Y
, polygon
))
661 else if ((temp
= SQUARE (conn1
->X
- conn2
->X
) +
662 SQUARE (conn1
->Y
- conn2
->Y
)) < distance
|| !firstpoint
)
675 * If HAVEPOINTS is true, we've found a pair of points in two
676 * separate blobs of the net, and need to connect them together.
682 (*funcp
) (firstpoint
, secondpoint
, subnet
->Style
);
686 /* found the shortest distance subnet, draw the rat */
687 if ((line
= CreateNewRat (PCB
->Data
,
688 firstpoint
->X
, firstpoint
->Y
,
689 secondpoint
->X
, secondpoint
->Y
,
690 firstpoint
->group
, secondpoint
->group
,
691 Settings
.RatThickness
,
692 NoFlags ())) != NULL
)
695 SET_FLAG (VIAFLAG
, line
);
696 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
702 /* copy theSubnet into the current subnet */
703 TransferNet (Netl
, theSubnet
, subnet
);
707 /* presently nothing to do with the new subnet */
708 /* so we throw it away and free the space */
709 FreeNetMemory (&Netl
->Net
[--(Netl
->NetN
)]);
710 /* Sadly adding a rat line messes up the sorted arrays in connection finder */
711 /* hace: perhaps not necessarily now that they aren't stored in normal layers */
714 FreeConnectionLookupMemory ();
715 InitConnectionLookup ();
721 /* ---------------------------------------------------------------------------
722 * AddAllRats puts the rats nest into the layout from the loaded netlist
723 * if SelectedOnly is true, it will only draw rats to selected pins and pads
726 AddAllRats (bool SelectedOnly
, void (*funcp
) (register ConnectionType
*, register ConnectionType
*, register RouteStyleType
*))
728 NetListType
*Nets
, *Wantlist
;
730 ConnectionType
*onepin
;
731 bool changed
, Warned
= false;
733 /* the netlist library has the text form
734 * ProcNetlist fills in the Netlist
735 * structure the way the final routing
736 * is supposed to look
738 Wantlist
= ProcNetlist (&PCB
->NetlistLib
);
741 Message (_("Can't add rat lines because no netlist is loaded.\n"));
745 /* initialize finding engine */
746 InitConnectionLookup ();
747 SaveFindFlag (DRCFLAG
);
748 Nets
= (NetListType
*)calloc (1, sizeof (NetListType
));
749 /* now we build another netlist (Nets) for each
750 * net in Wantlist that shows how it actually looks now,
751 * then fill in any missing connections with rat lines.
753 * we first assume each connection is separate
754 * (no routing), then gather them into groups
755 * if the net is all routed, the new netlist (Nets)
756 * will have only one net entry.
757 * Note that DrawShortestRats consumes all nets
758 * from Nets, so *Nets is empty after the
759 * DrawShortestRats call
763 CONNECTION_LOOP (net
);
766 || TEST_FLAG (SELECTEDFLAG
, (PinType
*) connection
->ptr2
))
768 lonesome
= GetNetMemory (Nets
);
769 onepin
= GetConnectionMemory (lonesome
);
770 *onepin
= *connection
;
771 lonesome
->Style
= net
->Style
;
775 Warned
|= GatherSubnets (Nets
, SelectedOnly
, true);
777 changed
|= DrawShortestRats (Nets
, funcp
);
780 FreeNetListMemory (Nets
);
782 FreeConnectionLookupMemory ();
787 if (Warned
|| changed
)
791 Settings
.RatWarn
= true;
795 IncrementUndoSerialNumber ();
796 if (PCB
->Data
->RatN
> 0)
798 Message ("%d rat line%s remaining\n", PCB
->Data
->RatN
,
799 PCB
->Data
->RatN
> 1 ? "s" : "");
803 if (!SelectedOnly
&& !Warned
)
805 if (!PCB
->Data
->RatN
&& !badnet
)
806 Message (_("Congratulations!!\n"
807 "The layout is complete and has no shorted nets.\n"));
809 Message (_("Nothing more to add, but there are\n"
810 "either rat-lines in the layout, disabled nets\n"
811 "in the net-list, or missing components\n"));
816 /* XXX: This is copied in large part from AddAllRats above; for
817 * maintainability, AddAllRats probably wants to be tweaked to use this
818 * version of the code so that we don't have duplication. */
820 CollectSubnets (bool SelectedOnly
)
822 NetListListType result
= { 0, 0, NULL
};
823 NetListType
*Nets
, *Wantlist
;
825 ConnectionType
*onepin
;
827 /* the netlist library has the text form
828 * ProcNetlist fills in the Netlist
829 * structure the way the final routing
830 * is supposed to look
832 Wantlist
= ProcNetlist (&PCB
->NetlistLib
);
835 Message (_("Can't add rat lines because no netlist is loaded.\n"));
838 /* initialize finding engine */
839 InitConnectionLookup ();
840 SaveFindFlag (DRCFLAG
);
841 /* now we build another netlist (Nets) for each
842 * net in Wantlist that shows how it actually looks now,
843 * then fill in any missing connections with rat lines.
845 * we first assume each connection is separate
846 * (no routing), then gather them into groups
847 * if the net is all routed, the new netlist (Nets)
848 * will have only one net entry.
849 * Note that DrawShortestRats consumes all nets
850 * from Nets, so *Nets is empty after the
851 * DrawShortestRats call
855 Nets
= GetNetListMemory (&result
);
856 CONNECTION_LOOP (net
);
859 || TEST_FLAG (SELECTEDFLAG
, (PinType
*) connection
->ptr2
))
861 lonesome
= GetNetMemory (Nets
);
862 onepin
= GetConnectionMemory (lonesome
);
863 *onepin
= *connection
;
864 lonesome
->Style
= net
->Style
;
868 /* Note that AndRats is *FALSE* here! */
869 GatherSubnets (Nets
, SelectedOnly
, false);
872 FreeConnectionLookupMemory ();
878 * Check to see if a particular name is the name of an already existing rats
882 rat_used (char *name
)
887 MENU_LOOP (&PCB
->NetlistLib
);
889 if (menu
->Name
&& (strcmp (menu
->Name
, name
) == 0))
897 /* These next two functions moved from the original netlist.c as part of the
898 | gui code separation for the Gtk port.
903 static int ratDrawn
= 0;
904 char name1
[256], *name2
;
905 Cardinal group1
, group2
;
908 void *ptr1
, *ptr2
, *ptr3
;
909 LibraryMenuType
*menu
;
910 LibraryEntryType
*entry
;
912 if (Crosshair
.AttachedLine
.Point1
.X
== Crosshair
.AttachedLine
.Point2
.X
913 && Crosshair
.AttachedLine
.Point1
.Y
== Crosshair
.AttachedLine
.Point2
.Y
)
916 found
= SearchObjectByLocation (PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
917 Crosshair
.AttachedLine
.Point1
.X
,
918 Crosshair
.AttachedLine
.Point1
.Y
, 5);
919 if (found
== NO_TYPE
)
921 Message (_("No pad/pin under rat line\n"));
924 if (NAMEONPCB_NAME ((ElementType
*) ptr1
) == NULL
925 || *NAMEONPCB_NAME ((ElementType
*) ptr1
) == 0)
927 Message (_("You must name the starting element first\n"));
931 /* will work for pins to since the FLAG is common */
932 group1
= (TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ?
933 GetLayerGroupNumberByNumber (solder_silk_layer
) :
934 GetLayerGroupNumberByNumber (component_silk_layer
));
935 strcpy (name1
, ConnectionName (found
, ptr1
, ptr2
));
936 found
= SearchObjectByLocation (PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
937 Crosshair
.AttachedLine
.Point2
.X
,
938 Crosshair
.AttachedLine
.Point2
.Y
, 5);
939 if (found
== NO_TYPE
)
941 Message (_("No pad/pin under rat line\n"));
944 if (NAMEONPCB_NAME ((ElementType
*) ptr1
) == NULL
945 || *NAMEONPCB_NAME ((ElementType
*) ptr1
) == 0)
947 Message (_("You must name the ending element first\n"));
950 group2
= (TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ?
951 GetLayerGroupNumberByNumber (solder_silk_layer
) :
952 GetLayerGroupNumberByNumber (component_silk_layer
));
953 name2
= ConnectionName (found
, ptr1
, ptr2
);
955 menu
= netnode_to_netname (name1
);
958 if (netnode_to_netname (name2
))
961 ("Both connections already in netlist - cannot merge nets\n"));
964 entry
= GetLibraryEntryMemory (menu
);
965 entry
->ListEntry
= strdup (name2
);
966 netnode_to_netname (name2
);
969 /* ok, the first name did not belong to a net */
970 menu
= netnode_to_netname (name2
);
973 entry
= GetLibraryEntryMemory (menu
);
974 entry
->ListEntry
= strdup (name1
);
975 netnode_to_netname (name1
);
980 * neither belong to a net, so create a new one.
982 * before creating a new rats here, we need to search
985 sprintf (ratname
, " ratDrawn%i", ++ratDrawn
);
986 while (rat_used (ratname
))
988 sprintf (ratname
, " ratDrawn%i", ++ratDrawn
);
991 menu
= GetLibraryMenuMemory (&PCB
->NetlistLib
);
992 menu
->Name
= strdup (ratname
);
993 entry
= GetLibraryEntryMemory (menu
);
994 entry
->ListEntry
= strdup (name1
);
995 entry
= GetLibraryEntryMemory (menu
);
996 entry
->ListEntry
= strdup (name2
);
1001 return (CreateNewRat (PCB
->Data
, Crosshair
.AttachedLine
.Point1
.X
,
1002 Crosshair
.AttachedLine
.Point1
.Y
,
1003 Crosshair
.AttachedLine
.Point2
.X
,
1004 Crosshair
.AttachedLine
.Point2
.Y
,
1005 group1
, group2
, Settings
.RatThickness
, NoFlags ()));
1010 ConnectionName (int type
, void *ptr1
, void *ptr2
)
1012 static char name
[256];
1018 num
= ((PinType
*) ptr2
)->Number
;
1021 num
= ((PadType
*) ptr2
)->Number
;
1026 strcpy (name
, UNKNOWN (NAMEONPCB_NAME ((ElementType
*) ptr1
)));
1028 strcat (name
, UNKNOWN (num
));