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 top_group
, bottom_group
; /* layer group holding top/bottom 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
) ? bottom_group
: top_group
;
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
= bottom_group
; /* 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 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
231 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
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 ClearFlagOnAllObjects (false, DRCFLAG
);
462 RatFindHook (a
->Connection
[0].type
, a
->Connection
[0].ptr1
,
463 a
->Connection
[0].ptr2
, a
->Connection
[0].ptr2
,
464 false, DRCFLAG
, AndRats
);
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
))
487 conn
= GetConnectionMemory (a
);
488 conn
->X
= line
->Point1
.X
;
489 conn
->Y
= line
->Point1
.Y
;
490 conn
->type
= LINE_TYPE
;
493 conn
->group
= GetLayerGroupNumberByPointer (layer
);
494 conn
->menu
= NULL
; /* agnostic view of where it belongs */
495 conn
= GetConnectionMemory (a
);
496 conn
->X
= line
->Point2
.X
;
497 conn
->Y
= line
->Point2
.Y
;
498 conn
->type
= LINE_TYPE
;
501 conn
->group
= GetLayerGroupNumberByPointer (layer
);
506 /* add polygons so the auto-router can see them as targets */
507 ALLPOLYGON_LOOP (PCB
->Data
);
509 if (TEST_FLAG (DRCFLAG
, polygon
))
511 conn
= GetConnectionMemory (a
);
512 /* make point on a vertex */
513 conn
->X
= polygon
->Clipped
->contours
->head
.point
[0];
514 conn
->Y
= polygon
->Clipped
->contours
->head
.point
[1];
515 conn
->type
= POLYGON_TYPE
;
517 conn
->ptr2
= polygon
;
518 conn
->group
= GetLayerGroupNumberByPointer (layer
);
519 conn
->menu
= NULL
; /* agnostic view of where it belongs */
523 VIA_LOOP (PCB
->Data
);
525 if (TEST_FLAG (DRCFLAG
, via
))
527 conn
= GetConnectionMemory (a
);
530 conn
->type
= VIA_TYPE
;
533 conn
->group
= bottom_group
;
538 Warned
|= CheckShorts (a
->Connection
[0].menu
);
540 ClearFlagOnAllObjects (false, DRCFLAG
);
544 /* ---------------------------------------------------------------------------
545 * Draw a rat net (tree) having the shortest lines
546 * this also frees the subnet memory as they are consumed
548 * Note that the Netl we are passed is NOT the main netlist - it's the
549 * connectivity for ONE net. It represents the CURRENT connectivity
550 * state for the net, with each Netl->Net[N] representing one
551 * copper-connected subset of the net.
555 DrawShortestRats (NetListType
*Netl
, void (*funcp
) (register ConnectionType
*, register ConnectionType
*, register RouteStyleType
*))
558 register float distance
, temp
;
559 register ConnectionType
*conn1
, *conn2
, *firstpoint
, *secondpoint
;
560 PolygonType
*polygon
;
561 bool changed
= false;
564 NetType
*next
, *subnet
, *theSubnet
= NULL
;
566 /* This is just a sanity check, to make sure we're passed
569 if (!Netl
|| Netl
->NetN
< 1)
573 * Everything inside the NetList Netl should be connected together.
574 * Each Net in Netl is a group of Connections which are already
575 * connected together somehow, either by real wires or by rats we've
576 * already drawn. Each Connection is a vertex within that blob of
577 * connected items. This loop finds the closest vertex pairs between
578 * each blob and draws rats that merge the blobs until there's just
581 * Just to clarify, with some examples:
583 * Each Netl is one full net from a netlist, like from gnetlist.
584 * Each Netl->Net[N] is a subset of that net that's already
585 * physically connected on the pcb.
587 * So a new design with no traces yet, would have a huge list of Net[N],
588 * each with one pin in it.
590 * A fully routed design would have one Net[N] with all the pins
591 * (for that net) in it.
595 * We keep doing this do/while loop until everything's connected.
596 * I.e. once per rat we add.
599 havepoints
= true; /* so we run the loop at least once */
600 while (Netl
->NetN
> 1 && havepoints
)
602 /* This is the top of the "find one rat" logic. */
604 firstpoint
= secondpoint
= NULL
;
606 /* Test Net[0] vs Net[N] for N=1..max. Find the shortest
607 distance between any two points in different blobs. */
608 subnet
= &Netl
->Net
[0];
609 for (j
= 1; j
< Netl
->NetN
; j
++)
612 * Scan between Net[0] blob (subnet) and Net[N] blob (next).
613 * Note the shortest distance we find.
615 next
= &Netl
->Net
[j
];
616 for (n
= subnet
->ConnectionN
- 1; n
!= -1; n
--)
618 conn1
= &subnet
->Connection
[n
];
619 for (m
= next
->ConnectionN
- 1; m
!= -1; m
--)
621 conn2
= &next
->Connection
[m
];
623 * At this point, conn1 and conn2 are two pins in
624 * different blobs of the same net. See how far
625 * apart they are, and if they're "closer" than what
630 * Prefer to connect Connections over polygons to the
631 * polygons (ie assume the user wants a via to a plane,
632 * not a daisy chain). Further prefer to pick an existing
633 * via in the Net to make that connection.
635 if (conn1
->type
== POLYGON_TYPE
&&
636 (polygon
= (PolygonType
*)conn1
->ptr2
) &&
638 firstpoint
&& firstpoint
->type
== VIA_TYPE
) &&
639 IsPointInPolygonIgnoreHoles (conn2
->X
, conn2
->Y
, polygon
))
647 else if (conn2
->type
== POLYGON_TYPE
&&
648 (polygon
= (PolygonType
*)conn2
->ptr2
) &&
650 firstpoint
&& firstpoint
->type
== VIA_TYPE
) &&
651 IsPointInPolygonIgnoreHoles (conn1
->X
, conn1
->Y
, polygon
))
659 else if ((temp
= SQUARE (conn1
->X
- conn2
->X
) +
660 SQUARE (conn1
->Y
- conn2
->Y
)) < distance
|| !firstpoint
)
673 * If HAVEPOINTS is true, we've found a pair of points in two
674 * separate blobs of the net, and need to connect them together.
680 (*funcp
) (firstpoint
, secondpoint
, subnet
->Style
);
684 /* found the shortest distance subnet, draw the rat */
685 if ((line
= CreateNewRat (PCB
->Data
,
686 firstpoint
->X
, firstpoint
->Y
,
687 secondpoint
->X
, secondpoint
->Y
,
688 firstpoint
->group
, secondpoint
->group
,
689 Settings
.RatThickness
,
690 NoFlags ())) != NULL
)
693 SET_FLAG (VIAFLAG
, line
);
694 AddObjectToCreateUndoList (RATLINE_TYPE
, line
, line
, line
);
700 /* copy theSubnet into the current subnet */
701 TransferNet (Netl
, theSubnet
, subnet
);
705 /* presently nothing to do with the new subnet */
706 /* so we throw it away and free the space */
707 FreeNetMemory (&Netl
->Net
[--(Netl
->NetN
)]);
708 /* Sadly adding a rat line messes up the sorted arrays in connection finder */
709 /* hace: perhaps not necessarily now that they aren't stored in normal layers */
712 FreeConnectionLookupMemory ();
713 InitConnectionLookup ();
719 /* ---------------------------------------------------------------------------
720 * AddAllRats puts the rats nest into the layout from the loaded netlist
721 * if SelectedOnly is true, it will only draw rats to selected pins and pads
724 AddAllRats (bool SelectedOnly
, void (*funcp
) (register ConnectionType
*, register ConnectionType
*, register RouteStyleType
*))
726 NetListType
*Nets
, *Wantlist
;
728 ConnectionType
*onepin
;
729 bool changed
, Warned
= false;
731 /* the netlist library has the text form
732 * ProcNetlist fills in the Netlist
733 * structure the way the final routing
734 * is supposed to look
736 Wantlist
= ProcNetlist (&PCB
->NetlistLib
);
739 Message (_("Can't add rat lines because no netlist is loaded.\n"));
743 /* initialize finding engine */
744 InitConnectionLookup ();
745 Nets
= (NetListType
*)calloc (1, sizeof (NetListType
));
746 /* now we build another netlist (Nets) for each
747 * net in Wantlist that shows how it actually looks now,
748 * then fill in any missing connections with rat lines.
750 * we first assume each connection is separate
751 * (no routing), then gather them into groups
752 * if the net is all routed, the new netlist (Nets)
753 * will have only one net entry.
754 * Note that DrawShortestRats consumes all nets
755 * from Nets, so *Nets is empty after the
756 * DrawShortestRats call
760 CONNECTION_LOOP (net
);
763 || TEST_FLAG (SELECTEDFLAG
, (PinType
*) connection
->ptr2
))
765 lonesome
= GetNetMemory (Nets
);
766 onepin
= GetConnectionMemory (lonesome
);
767 *onepin
= *connection
;
768 lonesome
->Style
= net
->Style
;
772 Warned
|= GatherSubnets (Nets
, SelectedOnly
, true);
774 changed
|= DrawShortestRats (Nets
, funcp
);
777 FreeNetListMemory (Nets
);
779 FreeConnectionLookupMemory ();
783 if (Warned
|| changed
)
787 Settings
.RatWarn
= true;
791 IncrementUndoSerialNumber ();
792 if (PCB
->Data
->RatN
> 0)
794 Message ("%d rat line%s remaining\n", PCB
->Data
->RatN
,
795 PCB
->Data
->RatN
> 1 ? "s" : "");
799 if (!SelectedOnly
&& !Warned
)
801 if (!PCB
->Data
->RatN
&& !badnet
)
802 Message (_("Congratulations!!\n"
803 "The layout is complete and has no shorted nets.\n"));
805 Message (_("Nothing more to add, but there are\n"
806 "either rat-lines in the layout, disabled nets\n"
807 "in the net-list, or missing components\n"));
812 /* XXX: This is copied in large part from AddAllRats above; for
813 * maintainability, AddAllRats probably wants to be tweaked to use this
814 * version of the code so that we don't have duplication. */
816 CollectSubnets (bool SelectedOnly
)
818 NetListListType result
= { 0, 0, NULL
};
819 NetListType
*Nets
, *Wantlist
;
821 ConnectionType
*onepin
;
823 /* the netlist library has the text form
824 * ProcNetlist fills in the Netlist
825 * structure the way the final routing
826 * is supposed to look
828 Wantlist
= ProcNetlist (&PCB
->NetlistLib
);
831 Message (_("Can't add rat lines because no netlist is loaded.\n"));
834 /* initialize finding engine */
835 InitConnectionLookup ();
836 /* now we build another netlist (Nets) for each
837 * net in Wantlist that shows how it actually looks now,
838 * then fill in any missing connections with rat lines.
840 * we first assume each connection is separate
841 * (no routing), then gather them into groups
842 * if the net is all routed, the new netlist (Nets)
843 * will have only one net entry.
844 * Note that DrawShortestRats consumes all nets
845 * from Nets, so *Nets is empty after the
846 * DrawShortestRats call
850 Nets
= GetNetListMemory (&result
);
851 CONNECTION_LOOP (net
);
854 || TEST_FLAG (SELECTEDFLAG
, (PinType
*) connection
->ptr2
))
856 lonesome
= GetNetMemory (Nets
);
857 onepin
= GetConnectionMemory (lonesome
);
858 *onepin
= *connection
;
859 lonesome
->Style
= net
->Style
;
863 /* Note that AndRats is *FALSE* here! */
864 GatherSubnets (Nets
, SelectedOnly
, false);
867 FreeConnectionLookupMemory ();
872 * Check to see if a particular name is the name of an already existing rats
876 rat_used (char *name
)
881 MENU_LOOP (&PCB
->NetlistLib
);
883 if (menu
->Name
&& (strcmp (menu
->Name
, name
) == 0))
891 /* These next two functions moved from the original netlist.c as part of the
892 | gui code separation for the Gtk port.
897 static int ratDrawn
= 0;
898 char name1
[256], *name2
;
899 Cardinal group1
, group2
;
902 void *ptr1
, *ptr2
, *ptr3
;
903 LibraryMenuType
*menu
;
904 LibraryEntryType
*entry
;
906 if (Crosshair
.AttachedLine
.Point1
.X
== Crosshair
.AttachedLine
.Point2
.X
907 && Crosshair
.AttachedLine
.Point1
.Y
== Crosshair
.AttachedLine
.Point2
.Y
)
910 found
= SearchObjectByLocation (PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
911 Crosshair
.AttachedLine
.Point1
.X
,
912 Crosshair
.AttachedLine
.Point1
.Y
, 5);
913 if (found
== NO_TYPE
)
915 Message (_("No pad/pin under rat line\n"));
918 if (NAMEONPCB_NAME ((ElementType
*) ptr1
) == NULL
919 || *NAMEONPCB_NAME ((ElementType
*) ptr1
) == 0)
921 Message (_("You must name the starting element first\n"));
925 /* will work for pins to since the FLAG is common */
926 group1
= GetLayerGroupNumberBySide (
927 TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ? BOTTOM_SIDE
: TOP_SIDE
);
928 strcpy (name1
, ConnectionName (found
, ptr1
, ptr2
));
929 found
= SearchObjectByLocation (PAD_TYPE
| PIN_TYPE
, &ptr1
, &ptr2
, &ptr3
,
930 Crosshair
.AttachedLine
.Point2
.X
,
931 Crosshair
.AttachedLine
.Point2
.Y
, 5);
932 if (found
== NO_TYPE
)
934 Message (_("No pad/pin under rat line\n"));
937 if (NAMEONPCB_NAME ((ElementType
*) ptr1
) == NULL
938 || *NAMEONPCB_NAME ((ElementType
*) ptr1
) == 0)
940 Message (_("You must name the ending element first\n"));
943 group2
= GetLayerGroupNumberBySide (
944 TEST_FLAG (ONSOLDERFLAG
, (PadType
*) ptr2
) ? BOTTOM_SIDE
: TOP_SIDE
);
945 name2
= ConnectionName (found
, ptr1
, ptr2
);
947 menu
= netnode_to_netname (name1
);
950 if (netnode_to_netname (name2
))
953 ("Both connections already in netlist - cannot merge nets\n"));
956 entry
= GetLibraryEntryMemory (menu
);
957 entry
->ListEntry
= strdup (name2
);
958 netnode_to_netname (name2
);
961 /* ok, the first name did not belong to a net */
962 menu
= netnode_to_netname (name2
);
965 entry
= GetLibraryEntryMemory (menu
);
966 entry
->ListEntry
= strdup (name1
);
967 netnode_to_netname (name1
);
972 * neither belong to a net, so create a new one.
974 * before creating a new rats here, we need to search
977 sprintf (ratname
, " ratDrawn%i", ++ratDrawn
);
978 while (rat_used (ratname
))
980 sprintf (ratname
, " ratDrawn%i", ++ratDrawn
);
983 menu
= GetLibraryMenuMemory (&PCB
->NetlistLib
);
984 menu
->Name
= strdup (ratname
);
985 entry
= GetLibraryEntryMemory (menu
);
986 entry
->ListEntry
= strdup (name1
);
987 entry
= GetLibraryEntryMemory (menu
);
988 entry
->ListEntry
= strdup (name2
);
993 return (CreateNewRat (PCB
->Data
, Crosshair
.AttachedLine
.Point1
.X
,
994 Crosshair
.AttachedLine
.Point1
.Y
,
995 Crosshair
.AttachedLine
.Point2
.X
,
996 Crosshair
.AttachedLine
.Point2
.Y
,
997 group1
, group2
, Settings
.RatThickness
, NoFlags ()));
1002 ConnectionName (int type
, void *ptr1
, void *ptr2
)
1004 static char name
[256];
1010 num
= ((PinType
*) ptr2
)->Number
;
1013 num
= ((PadType
*) ptr2
)->Number
;
1018 strcpy (name
, UNKNOWN (NAMEONPCB_NAME ((ElementType
*) ptr1
)));
1020 strcat (name
, UNKNOWN (num
));