4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* functions used by paste- and move/copy buffer
43 #include "crosshair.h"
59 #ifdef HAVE_LIBDMALLOC
63 /* ---------------------------------------------------------------------------
64 * some local prototypes
66 static void *AddViaToBuffer (PinType
*);
67 static void *AddLineToBuffer (LayerType
*, LineType
*);
68 static void *AddArcToBuffer (LayerType
*, ArcType
*);
69 static void *AddRatToBuffer (RatType
*);
70 static void *AddTextToBuffer (LayerType
*, TextType
*);
71 static void *AddPolygonToBuffer (LayerType
*, PolygonType
*);
72 static void *AddElementToBuffer (ElementType
*);
73 static void *MoveViaToBuffer (PinType
*);
74 static void *MoveLineToBuffer (LayerType
*, LineType
*);
75 static void *MoveArcToBuffer (LayerType
*, ArcType
*);
76 static void *MoveRatToBuffer (RatType
*);
77 static void *MoveTextToBuffer (LayerType
*, TextType
*);
78 static void *MovePolygonToBuffer (LayerType
*, PolygonType
*);
79 static void *MoveElementToBuffer (ElementType
*);
80 static void SwapBuffer (BufferType
*);
82 #define ARG(n) (argc > (n) ? argv[n] : 0)
84 /* ---------------------------------------------------------------------------
85 * some local identifiers
87 static DataType
*Dest
, *Source
;
89 static ObjectFunctionType AddBufferFunctions
= {
102 }, MoveBufferFunctions
=
110 NULL
, NULL
, NULL
, NULL
, NULL
, MoveArcToBuffer
, MoveRatToBuffer
};
112 static int ExtraFlag
= 0;
114 /* ---------------------------------------------------------------------------
115 * copies a via to paste buffer
118 AddViaToBuffer (PinType
*Via
)
120 return (CreateNewVia (Dest
, Via
->X
, Via
->Y
, Via
->Thickness
, Via
->Clearance
,
121 Via
->Mask
, Via
->DrillingHole
, Via
->Name
,
122 MaskFlags (Via
->Flags
, NOCOPY_FLAGS
| ExtraFlag
)));
125 /* ---------------------------------------------------------------------------
126 * copies a rat-line to paste buffer
129 AddRatToBuffer (RatType
*Rat
)
131 return (CreateNewRat (Dest
, Rat
->Point1
.X
, Rat
->Point1
.Y
,
132 Rat
->Point2
.X
, Rat
->Point2
.Y
, Rat
->group1
,
133 Rat
->group2
, Rat
->Thickness
,
134 MaskFlags (Rat
->Flags
, NOCOPY_FLAGS
| ExtraFlag
)));
137 /* ---------------------------------------------------------------------------
138 * copies a line to buffer
141 AddLineToBuffer (LayerType
*Layer
, LineType
*Line
)
144 LayerType
*layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
146 line
= CreateNewLineOnLayer (layer
, Line
->Point1
.X
, Line
->Point1
.Y
,
147 Line
->Point2
.X
, Line
->Point2
.Y
,
148 Line
->Thickness
, Line
->Clearance
,
149 MaskFlags (Line
->Flags
,
150 NOCOPY_FLAGS
| ExtraFlag
));
151 if (line
&& Line
->Number
)
152 line
->Number
= strdup (Line
->Number
);
156 /* ---------------------------------------------------------------------------
157 * copies an arc to buffer
160 AddArcToBuffer (LayerType
*Layer
, ArcType
*Arc
)
162 LayerType
*layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
164 return (CreateNewArcOnLayer (layer
, Arc
->X
, Arc
->Y
,
165 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
,
166 Arc
->Thickness
, Arc
->Clearance
,
167 MaskFlags (Arc
->Flags
,
168 NOCOPY_FLAGS
| ExtraFlag
)));
171 /* ---------------------------------------------------------------------------
172 * copies a text to buffer
175 AddTextToBuffer (LayerType
*Layer
, TextType
*Text
)
177 LayerType
*layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
179 return (CreateNewText (layer
, &PCB
->Font
, Text
->X
, Text
->Y
,
180 Text
->Direction
, Text
->Scale
, Text
->TextString
,
181 MaskFlags (Text
->Flags
, ExtraFlag
)));
184 /* ---------------------------------------------------------------------------
185 * copies a polygon to buffer
188 AddPolygonToBuffer (LayerType
*Layer
, PolygonType
*Polygon
)
190 LayerType
*layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
191 PolygonType
*polygon
;
193 polygon
= CreateNewPolygon (layer
, Polygon
->Flags
);
194 CopyPolygonLowLevel (polygon
, Polygon
);
196 /* Update the polygon r-tree. Unlike similarly named functions for
197 * other objects, CreateNewPolygon does not do this as it creates a
198 * skeleton polygon object, which won't have correct bounds.
200 if (!layer
->polygon_tree
)
201 layer
->polygon_tree
= r_create_tree (NULL
, 0, 0);
202 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
204 CLEAR_FLAG (NOCOPY_FLAGS
| ExtraFlag
, polygon
);
208 /* ---------------------------------------------------------------------------
209 * copies a element to buffer
212 AddElementToBuffer (ElementType
*Element
)
214 return CopyElementLowLevel (Dest
, Element
, false, 0, 0, NOCOPY_FLAGS
| ExtraFlag
);
217 /* ---------------------------------------------------------------------------
218 * moves a via to paste buffer without allocating memory for the name
221 MoveViaToBuffer (PinType
*via
)
223 RestoreToPolygon (Source
, VIA_TYPE
, via
, via
);
225 r_delete_entry (Source
->via_tree
, (BoxType
*) via
);
226 Source
->Via
= g_list_remove (Source
->Via
, via
);
228 Dest
->Via
= g_list_append (Dest
->Via
, via
);
231 CLEAR_FLAG (WARNFLAG
| NOCOPY_FLAGS
, via
);
234 Dest
->via_tree
= r_create_tree (NULL
, 0, 0);
235 r_insert_entry (Dest
->via_tree
, (BoxType
*)via
, 0);
236 ClearFromPolygon (Dest
, VIA_TYPE
, via
, via
);
240 /* ---------------------------------------------------------------------------
241 * moves a rat-line to paste buffer
244 MoveRatToBuffer (RatType
*rat
)
246 r_delete_entry (Source
->rat_tree
, (BoxType
*)rat
);
248 Source
->Rat
= g_list_remove (Source
->Rat
, rat
);
250 Dest
->Rat
= g_list_append (Dest
->Rat
, rat
);
253 CLEAR_FLAG (NOCOPY_FLAGS
, rat
);
256 Dest
->rat_tree
= r_create_tree (NULL
, 0, 0);
257 r_insert_entry (Dest
->rat_tree
, (BoxType
*)rat
, 0);
261 /* ---------------------------------------------------------------------------
262 * moves a line to buffer
265 MoveLineToBuffer (LayerType
*layer
, LineType
*line
)
267 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
269 RestoreToPolygon (Source
, LINE_TYPE
, layer
, line
);
270 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
272 layer
->Line
= g_list_remove (layer
->Line
, line
);
274 lay
->Line
= g_list_append (lay
->Line
, line
);
277 CLEAR_FLAG (NOCOPY_FLAGS
, line
);
280 lay
->line_tree
= r_create_tree (NULL
, 0, 0);
281 r_insert_entry (lay
->line_tree
, (BoxType
*)line
, 0);
282 ClearFromPolygon (Dest
, LINE_TYPE
, lay
, line
);
286 /* ---------------------------------------------------------------------------
287 * moves an arc to buffer
290 MoveArcToBuffer (LayerType
*layer
, ArcType
*arc
)
292 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
294 RestoreToPolygon (Source
, ARC_TYPE
, layer
, arc
);
295 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
297 layer
->Arc
= g_list_remove (layer
->Arc
, arc
);
299 lay
->Arc
= g_list_append (lay
->Arc
, arc
);
302 CLEAR_FLAG (NOCOPY_FLAGS
, arc
);
305 lay
->arc_tree
= r_create_tree (NULL
, 0, 0);
306 r_insert_entry (lay
->arc_tree
, (BoxType
*)arc
, 0);
307 ClearFromPolygon (Dest
, ARC_TYPE
, lay
, arc
);
311 /* ---------------------------------------------------------------------------
312 * moves a text to buffer without allocating memory for the name
315 MoveTextToBuffer (LayerType
*layer
, TextType
*text
)
317 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
319 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
320 RestoreToPolygon (Source
, TEXT_TYPE
, layer
, text
);
322 layer
->Text
= g_list_remove (layer
->Text
, text
);
324 lay
->Text
= g_list_append (lay
->Text
, text
);
328 lay
->text_tree
= r_create_tree (NULL
, 0, 0);
329 r_insert_entry (lay
->text_tree
, (BoxType
*)text
, 0);
330 ClearFromPolygon (Dest
, TEXT_TYPE
, lay
, text
);
334 /* ---------------------------------------------------------------------------
335 * moves a polygon to buffer. Doesn't allocate memory for the points
338 MovePolygonToBuffer (LayerType
*layer
, PolygonType
*polygon
)
340 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
342 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
344 layer
->Polygon
= g_list_remove (layer
->Polygon
, polygon
);
346 lay
->Polygon
= g_list_append (lay
->Polygon
, polygon
);
349 CLEAR_FLAG (NOCOPY_FLAGS
, polygon
);
351 if (!lay
->polygon_tree
)
352 lay
->polygon_tree
= r_create_tree (NULL
, 0, 0);
353 r_insert_entry (lay
->polygon_tree
, (BoxType
*)polygon
, 0);
357 /* ---------------------------------------------------------------------------
358 * moves a element to buffer without allocating memory for pins/names
361 MoveElementToBuffer (ElementType
*element
)
364 * Delete the element from the source (remove it from trees,
365 * restore to polygons)
367 r_delete_element (Source
, element
);
369 Source
->Element
= g_list_remove (Source
->Element
, element
);
371 Dest
->Element
= g_list_append (Dest
->Element
, element
);
376 RestoreToPolygon(Source
, PIN_TYPE
, element
, pin
);
377 CLEAR_FLAG (WARNFLAG
| NOCOPY_FLAGS
, pin
);
382 RestoreToPolygon(Source
, PAD_TYPE
, element
, pad
);
383 CLEAR_FLAG (WARNFLAG
| NOCOPY_FLAGS
, pad
);
386 SetElementBoundingBox (Dest
, element
, &PCB
->Font
);
388 * Now clear the from the polygons in the destination
392 ClearFromPolygon (Dest
, PIN_TYPE
, element
, pin
);
397 ClearFromPolygon (Dest
, PAD_TYPE
, element
, pad
);
404 /* ---------------------------------------------------------------------------
405 * calculates the bounding box of the buffer
408 SetBufferBoundingBox (BufferType
*Buffer
)
410 BoxType
*box
= GetDataBoundingBox (Buffer
->Data
);
413 Buffer
->BoundingBox
= *box
;
416 /* ---------------------------------------------------------------------------
417 * clears the contents of the paste buffer
420 ClearBuffer (BufferType
*Buffer
)
422 if (Buffer
&& Buffer
->Data
)
424 FreeDataMemory (Buffer
->Data
);
425 Buffer
->Data
->pcb
= PCB
;
429 /* ----------------------------------------------------------------------
430 * copies all selected and visible objects to the paste buffer
431 * returns true if any objects have been removed
434 AddSelectedToBuffer (BufferType
*Buffer
, Coord X
, Coord Y
, bool LeaveSelected
)
436 /* switch crosshair off because adding objects to the pastebuffer
437 * may change the 'valid' area for the cursor
440 ExtraFlag
= SELECTEDFLAG
;
441 notify_crosshair_change (false);
444 SelectedOperation (&AddBufferFunctions
, false, ALL_TYPES
);
446 /* set origin to passed or current position */
454 Buffer
->X
= Crosshair
.X
;
455 Buffer
->Y
= Crosshair
.Y
;
457 notify_crosshair_change (true);
461 /* ---------------------------------------------------------------------------
462 * loads element data from file/library into buffer
463 * parse the file with disabled 'PCB mode' (see parser)
464 * returns false on error
465 * if successful, update some other stuff and reposition the pastebuffer
468 LoadElementToBuffer (BufferType
*Buffer
, char *Name
, bool FromFile
)
470 ElementType
*element
;
472 ClearBuffer (Buffer
);
475 if (!ParseElementFile (Buffer
->Data
, Name
))
477 if (Settings
.ShowBottomSide
)
479 SetBufferBoundingBox (Buffer
);
480 if (Buffer
->Data
->ElementN
)
482 element
= Buffer
->Data
->Element
->data
;
483 Buffer
->X
= element
->MarkX
;
484 Buffer
->Y
= element
->MarkY
;
496 if (!ParseLibraryEntry (Buffer
->Data
, Name
)
497 && Buffer
->Data
->ElementN
!= 0)
499 element
= Buffer
->Data
->Element
->data
;
501 /* always add elements using top-side coordinates */
502 if (Settings
.ShowBottomSide
)
503 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
504 SetElementBoundingBox (Buffer
->Data
, element
, &PCB
->Font
);
506 /* set buffer offset to 'mark' position */
507 Buffer
->X
= element
->MarkX
;
508 Buffer
->Y
= element
->MarkY
;
509 SetBufferBoundingBox (Buffer
);
513 /* release memory which might have been acquired */
514 ClearBuffer (Buffer
);
519 /*---------------------------------------------------------------------------
520 * Searches for the given element by "footprint" name, and loads it
524 /* Figuring out which library entry is the one we want is a little
525 tricky. For file-based footprints, it's just a matter of finding
526 the first match in the search list. For m4-based footprints you
527 need to know what magic to pass to the m4 functions. Fortunately,
528 the footprint needed is determined when we build the m4 libraries
529 and stored as a comment in the description, so we can search for
530 that to find the magic we need. We use a hash to store the
531 corresponding footprints and pointers to the library tree so we can
532 quickly find the various bits we need to load a given
537 int footprint_allocated
;
540 } FootprintHashEntry
;
542 static FootprintHashEntry
*footprint_hash
= 0;
543 int footprint_hash_size
= 0;
546 clear_footprint_hash ()
551 for (i
=0; i
<footprint_hash_size
; i
++)
552 if (footprint_hash
[i
].footprint_allocated
)
553 free (footprint_hash
[i
].footprint
);
554 free (footprint_hash
);
555 footprint_hash
= NULL
;
556 footprint_hash_size
= 0;
559 /* Used to sort footprint pointer entries. Note we include the index
560 numbers so that same-named footprints are sorted by the library
563 footprint_hash_cmp (const void *va
, const void *vb
)
566 FootprintHashEntry
*a
= (FootprintHashEntry
*)va
;
567 FootprintHashEntry
*b
= (FootprintHashEntry
*)vb
;
569 i
= strcmp (a
->footprint
, b
->footprint
);
571 i
= a
->menu_idx
- b
->menu_idx
;
573 i
= a
->entry_idx
- b
->entry_idx
;
578 make_footprint_hash ()
584 clear_footprint_hash ();
586 for (i
=0; i
<Library
.MenuN
; i
++)
587 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
589 footprint_hash
= (FootprintHashEntry
*)malloc (num_entries
* sizeof(FootprintHashEntry
));
592 /* There are two types of library entries. The file-based types
593 have a Template of (char *)-1 and the AllocatedMemory is the full
594 path to the footprint file. The m4 ones have the footprint name
595 in brackets in the description. */
596 for (i
=0; i
<Library
.MenuN
; i
++)
599 printf("In make_footprint_hash, looking for footprints in %s\n",
600 Library
.Menu
[i
].directory
);
603 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
605 footprint_hash
[num_entries
].menu_idx
= i
;
606 footprint_hash
[num_entries
].entry_idx
= j
;
607 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
611 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
613 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '/');
616 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '\\');
621 fp
= Library
.Menu
[i
].Entry
[j
].AllocatedMemory
;
624 /* printf(" ... found file footprint %s\n", fp); */
627 footprint_hash
[num_entries
].footprint
= fp
;
628 footprint_hash
[num_entries
].footprint_allocated
= 0;
633 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].Description
, '[');
636 footprint_hash
[num_entries
].footprint
= strdup (fp
+1);
637 footprint_hash
[num_entries
].footprint_allocated
= 1;
638 fp
= strchr (footprint_hash
[num_entries
].footprint
, ']');
644 fp
= Library
.Menu
[i
].Entry
[j
].Description
;
645 footprint_hash
[num_entries
].footprint
= fp
;
646 footprint_hash
[num_entries
].footprint_allocated
= 0;
653 footprint_hash_size
= num_entries
;
654 qsort (footprint_hash
, num_entries
, sizeof(footprint_hash
[0]), footprint_hash_cmp
);
657 printf(" found footprints: \n");
658 for (i=0; i<num_entries; i++)
659 printf("[%s]\n", footprint_hash[i].footprint);
665 search_footprint_hash (const char *footprint
)
669 /* Standard binary search */
672 max
= footprint_hash_size
;
674 while (max
- min
> 1)
677 c
= strcmp (footprint
, footprint_hash
[i
].footprint
);
684 /* We want to return the first match, not just any match. */
686 && strcmp (footprint
, footprint_hash
[i
-1].footprint
) == 0)
688 return & footprint_hash
[i
];
694 /* Returns zero on success, non-zero on error. */
696 LoadFootprintByName (BufferType
*Buffer
, char *Footprint
)
699 FootprintHashEntry
*fpe
;
700 LibraryMenuType
*menu
;
701 LibraryEntryType
*entry
;
702 char *with_fp
= NULL
;
705 make_footprint_hash ();
707 fpe
= search_footprint_hash (Footprint
);
710 with_fp
= Concat (Footprint
, ".fp", NULL
);
711 fpe
= search_footprint_hash (with_fp
);
717 Message(_("Unable to load footprint %s\n"), Footprint
);
721 menu
= & Library
.Menu
[fpe
->menu_idx
];
722 entry
= & menu
->Entry
[fpe
->entry_idx
];
724 if (entry
->Template
== (char *) -1)
726 i
= LoadElementToBuffer (Buffer
, entry
->AllocatedMemory
, true);
735 args
= Concat("'", EMPTY (entry
->Template
), "' '",
736 EMPTY (entry
->Value
), "' '", EMPTY (entry
->Package
), "'", NULL
);
737 i
= LoadElementToBuffer (Buffer
, args
, false);
748 printf("Library path: %s\n", Settings
.LibraryPath
);
749 printf("Library tree: %s\n", Settings
.LibraryTree
);
751 printf("Library:\n");
752 for (i
=0; i
<Library
.MenuN
; i
++)
754 printf(" [%02d] Name: %s\n", i
, Library
.Menu
[i
].Name
);
755 printf(" Dir: %s\n", Library
.Menu
[i
].directory
);
756 printf(" Sty: %s\n", Library
.Menu
[i
].Style
);
757 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
759 printf(" [%02d] E: %s\n", j
, Library
.Menu
[i
].Entry
[j
].ListEntry
);
760 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
761 printf(" A: %s\n", Library
.Menu
[i
].Entry
[j
].AllocatedMemory
);
764 printf(" T: %s\n", Library
.Menu
[i
].Entry
[j
].Template
);
765 printf(" P: %s\n", Library
.Menu
[i
].Entry
[j
].Package
);
766 printf(" V: %s\n", Library
.Menu
[i
].Entry
[j
].Value
);
767 printf(" D: %s\n", Library
.Menu
[i
].Entry
[j
].Description
);
778 static const char loadfootprint_syntax
[] =
779 N_("LoadFootprint(filename[,refdes,value])");
781 static const char loadfootprint_help
[] =
782 N_("Loads a single footprint by name.");
784 /* %start-doc actions LoadFootprint
786 Loads a single footprint by name, rather than by reference or through
787 the library. If a refdes and value are specified, those are inserted
788 into the footprint as well. The footprint remains in the paste buffer.
793 LoadFootprint (int argc
, char **argv
, Coord x
, Coord y
)
796 char *refdes
= ARG(1);
797 char *value
= ARG(2);
801 AFAIL (loadfootprint
);
803 if (LoadFootprintByName (PASTEBUFFER
, name
))
806 if (PASTEBUFFER
->Data
->ElementN
== 0)
808 Message(_("Footprint %s contains no elements"), name
);
811 if (PASTEBUFFER
->Data
->ElementN
> 1)
813 Message(_("Footprint %s contains multiple elements"), name
);
817 e
= PASTEBUFFER
->Data
->Element
->data
;
819 if (e
->Name
[0].TextString
)
820 free (e
->Name
[0].TextString
);
821 e
->Name
[0].TextString
= strdup (name
);
823 if (e
->Name
[1].TextString
)
824 free (e
->Name
[1].TextString
);
825 e
->Name
[1].TextString
= refdes
? strdup (refdes
) : 0;
827 if (e
->Name
[2].TextString
)
828 free (e
->Name
[2].TextString
);
829 e
->Name
[2].TextString
= value
? strdup (value
) : 0;
834 /*---------------------------------------------------------------------------
836 * break buffer element into pieces
839 SmashBufferElement (BufferType
*Buffer
)
841 ElementType
*element
;
843 LayerType
*top_layer
, *bottom_layer
;
845 if (Buffer
->Data
->ElementN
!= 1)
847 Message (_("Error! Buffer doesn't contain a single element\n"));
851 * At this point the buffer should contain just a single element.
852 * Now we detach the single element from the buffer and then clear the
853 * buffer, ready to receive the smashed elements. As a result of detaching
854 * it the single element is orphaned from the buffer and thus will not be
855 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
856 * around for us to smash bits off it. It then becomes our responsibility,
857 * however, to free the single element when we're finished with it.
859 element
= Buffer
->Data
->Element
->data
;
860 Buffer
->Data
->Element
= NULL
;
861 Buffer
->Data
->ElementN
= 0;
862 ClearBuffer (Buffer
);
863 ELEMENTLINE_LOOP (element
);
865 CreateNewLineOnLayer (&Buffer
->Data
->SILKLAYER
,
866 line
->Point1
.X
, line
->Point1
.Y
,
867 line
->Point2
.X
, line
->Point2
.Y
,
868 line
->Thickness
, 0, NoFlags ());
870 line
->Number
= STRDUP (NAMEONPCB_NAME (element
));
875 CreateNewArcOnLayer (&Buffer
->Data
->SILKLAYER
,
876 arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
,
877 arc
->Delta
, arc
->Thickness
, 0, NoFlags ());
882 FlagType f
= NoFlags ();
883 AddFlags (f
, VIAFLAG
);
884 if (TEST_FLAG (HOLEFLAG
, pin
))
885 AddFlags (f
, HOLEFLAG
);
887 CreateNewVia (Buffer
->Data
, pin
->X
, pin
->Y
,
888 pin
->Thickness
, pin
->Clearance
, pin
->Mask
,
889 pin
->DrillingHole
, pin
->Number
, f
);
892 group
= GetLayerGroupNumberBySide (SWAP_IDENT
? BOTTOM_SIDE
: TOP_SIDE
);
893 top_layer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
894 group
= GetLayerGroupNumberBySide (SWAP_IDENT
? TOP_SIDE
: BOTTOM_SIDE
);
895 bottom_layer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
899 line
= CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG
, pad
) ? bottom_layer
: top_layer
,
900 pad
->Point1
.X
, pad
->Point1
.Y
,
901 pad
->Point2
.X
, pad
->Point2
.Y
,
902 pad
->Thickness
, pad
->Clearance
, NoFlags ());
904 line
->Number
= STRDUP (pad
->Number
);
907 FreeElementMemory (element
);
908 g_slice_free (ElementType
, element
);
912 /*---------------------------------------------------------------------------
914 * see if a polygon is a rectangle. If so, canonicalize it.
918 polygon_is_rectangle (PolygonType
*poly
)
922 if (poly
->PointN
!= 4 || poly
->HoleIndexN
!= 0)
926 if (poly
->Points
[i
].X
< poly
->Points
[best
].X
927 || poly
->Points
[i
].Y
< poly
->Points
[best
].Y
)
930 temp
[i
] = poly
->Points
[(i
+best
)%4];
931 if (temp
[0].X
== temp
[1].X
)
932 memcpy (poly
->Points
, temp
, sizeof(temp
));
936 poly
->Points
[0] = temp
[0];
937 poly
->Points
[1] = temp
[3];
938 poly
->Points
[2] = temp
[2];
939 poly
->Points
[3] = temp
[1];
941 if (poly
->Points
[0].X
== poly
->Points
[1].X
942 && poly
->Points
[1].Y
== poly
->Points
[2].Y
943 && poly
->Points
[2].X
== poly
->Points
[3].X
944 && poly
->Points
[3].Y
== poly
->Points
[0].Y
)
949 /*---------------------------------------------------------------------------
951 * convert buffer contents into an element
954 ConvertBufferToElement (BufferType
*Buffer
)
956 ElementType
*Element
;
959 bool hasParts
= false, crooked
= false;
963 if (Buffer
->Data
->pcb
== 0)
964 Buffer
->Data
->pcb
= PCB
;
966 Element
= CreateNewElement (PCB
->Data
, &PCB
->Font
, NoFlags (),
967 NULL
, NULL
, NULL
, PASTEBUFFER
->X
,
968 PASTEBUFFER
->Y
, 0, 100,
969 MakeFlags (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
),
973 VIA_LOOP (Buffer
->Data
);
976 if (via
->Mask
< via
->Thickness
)
977 via
->Mask
= via
->Thickness
+ 2 * MASKFRAME
;
979 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
980 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
981 NULL
, via
->Name
, MaskFlags (via
->Flags
,
982 VIAFLAG
| NOCOPY_FLAGS
|
983 SELECTEDFLAG
| WARNFLAG
));
986 sprintf (num
, "%d", pin_n
++);
987 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
988 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
989 NULL
, num
, MaskFlags (via
->Flags
,
990 VIAFLAG
| NOCOPY_FLAGS
| SELECTEDFLAG
997 for (onsolder
= 0; onsolder
< 2; onsolder
++)
1002 if ((!onsolder
) == (!SWAP_IDENT
))
1005 onsolderflag
= NOFLAG
;
1010 onsolderflag
= ONSOLDERFLAG
;
1013 #define MAYBE_WARN() \
1014 if (onsolder && !hasParts && !warned) \
1018 (_("Warning: All of the pads are on the opposite\n" \
1019 "side from the component - that's probably not what\n" \
1023 /* get the component-side SM pads */
1024 group
= GetLayerGroupNumberBySide (side
);
1025 GROUP_LOOP (Buffer
->Data
, group
);
1030 sprintf (num
, "%d", pin_n
++);
1031 CreateNewPad (Element
, line
->Point1
.X
,
1032 line
->Point1
.Y
, line
->Point2
.X
,
1033 line
->Point2
.Y
, line
->Thickness
,
1035 line
->Thickness
+ line
->Clearance
, NULL
,
1036 line
->Number
? line
->Number
: num
,
1037 MakeFlags (onsolderflag
));
1042 POLYGON_LOOP (layer
);
1044 Coord x1
, y1
, x2
, y2
, w
, h
, t
;
1046 if (! polygon_is_rectangle (polygon
))
1052 w
= polygon
->Points
[2].X
- polygon
->Points
[0].X
;
1053 h
= polygon
->Points
[1].Y
- polygon
->Points
[0].Y
;
1054 t
= (w
< h
) ? w
: h
;
1055 x1
= polygon
->Points
[0].X
+ t
/2;
1056 y1
= polygon
->Points
[0].Y
+ t
/2;
1060 sprintf (num
, "%d", pin_n
++);
1061 CreateNewPad (Element
,
1063 2 * Settings
.Keepaway
,
1064 t
+ Settings
.Keepaway
,
1066 MakeFlags (SQUAREFLAG
| onsolderflag
));
1075 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1076 LINE_LOOP (&Buffer
->Data
->SILKLAYER
);
1078 if (line
->Number
&& !NAMEONPCB_NAME (Element
))
1079 NAMEONPCB_NAME (Element
) = strdup (line
->Number
);
1080 CreateNewLineInElement (Element
, line
->Point1
.X
,
1081 line
->Point1
.Y
, line
->Point2
.X
,
1082 line
->Point2
.Y
, line
->Thickness
);
1086 ARC_LOOP (&Buffer
->Data
->SILKLAYER
);
1088 CreateNewArcInElement (Element
, arc
->X
, arc
->Y
, arc
->Width
,
1089 arc
->Height
, arc
->StartAngle
, arc
->Delta
,
1096 DestroyObject (PCB
->Data
, ELEMENT_TYPE
, Element
, Element
, Element
);
1097 Message (_("There was nothing to convert!\n"
1098 "Elements must have some silk, pads or pins.\n"));
1102 Message (_("There were polygons that can't be made into pins!\n"
1103 "So they were not included in the element\n"));
1104 Element
->MarkX
= Buffer
->X
;
1105 Element
->MarkY
= Buffer
->Y
;
1107 SET_FLAG (ONSOLDERFLAG
, Element
);
1108 SetElementBoundingBox (PCB
->Data
, Element
, &PCB
->Font
);
1109 ClearBuffer (Buffer
);
1110 MoveObjectToBuffer (Buffer
->Data
, PCB
->Data
, ELEMENT_TYPE
, Element
, Element
,
1112 SetBufferBoundingBox (Buffer
);
1116 /* ---------------------------------------------------------------------------
1117 * load PCB into buffer
1118 * parse the file with enabled 'PCB mode' (see parser)
1119 * if successful, update some other stuff
1122 LoadLayoutToBuffer (BufferType
*Buffer
, char *Filename
)
1124 PCBType
*newPCB
= CreateNewPCB (false);
1126 /* new data isn't added to the undo list */
1127 if (!ParsePCB (newPCB
, Filename
))
1129 /* clear data area and replace pointer */
1130 ClearBuffer (Buffer
);
1131 free (Buffer
->Data
);
1132 Buffer
->Data
= newPCB
->Data
;
1133 newPCB
->Data
= NULL
;
1134 Buffer
->X
= newPCB
->CursorX
;
1135 Buffer
->Y
= newPCB
->CursorY
;
1137 Buffer
->Data
->pcb
= PCB
;
1141 /* release unused memory */
1143 Buffer
->Data
->pcb
= PCB
;
1147 /* ---------------------------------------------------------------------------
1148 * rotates the contents of the pastebuffer
1151 RotateBuffer (BufferType
*Buffer
, BYTE Number
)
1154 VIA_LOOP (Buffer
->Data
);
1156 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1157 ROTATE_VIA_LOWLEVEL (via
, Buffer
->X
, Buffer
->Y
, Number
);
1158 SetPinBoundingBox (via
);
1159 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1164 ELEMENT_LOOP (Buffer
->Data
);
1166 RotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1171 /* all layer related objects */
1172 ALLLINE_LOOP (Buffer
->Data
);
1174 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1175 RotateLineLowLevel (line
, Buffer
->X
, Buffer
->Y
, Number
);
1176 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1179 ALLARC_LOOP (Buffer
->Data
);
1181 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1182 RotateArcLowLevel (arc
, Buffer
->X
, Buffer
->Y
, Number
);
1183 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1186 ALLTEXT_LOOP (Buffer
->Data
);
1188 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
1189 RotateTextLowLevel (text
, Buffer
->X
, Buffer
->Y
, Number
);
1190 r_insert_entry (layer
->text_tree
, (BoxType
*)text
, 0);
1193 ALLPOLYGON_LOOP (Buffer
->Data
);
1195 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1196 RotatePolygonLowLevel (polygon
, Buffer
->X
, Buffer
->Y
, Number
);
1197 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1201 /* finally the origin and the bounding box */
1202 ROTATE (Buffer
->X
, Buffer
->Y
, Buffer
->X
, Buffer
->Y
, Number
);
1203 RotateBoxLowLevel (&Buffer
->BoundingBox
, Buffer
->X
, Buffer
->Y
, Number
);
1204 SetCrosshairRangeToBuffer ();
1208 free_rotate (Coord
*x
, Coord
*y
, Coord cx
, Coord cy
, double cosa
, double sina
)
1214 nx
= px
* cosa
+ py
* sina
;
1215 ny
= py
* cosa
- px
* sina
;
1222 FreeRotateElementLowLevel (DataType
*Data
, ElementType
*Element
,
1224 double cosa
, double sina
, Angle angle
)
1226 /* solder side objects need a different orientation */
1228 /* the text subroutine decides by itself if the direction
1229 * is to be corrected
1232 ELEMENTTEXT_LOOP (Element
);
1234 if (Data
&& Data
->name_tree
[n
])
1235 r_delete_entry (Data
->name_tree
[n
], (BoxType
*)text
);
1236 RotateTextLowLevel (text
, X
, Y
, Number
);
1240 ELEMENTLINE_LOOP (Element
);
1242 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, X
, Y
, cosa
, sina
);
1243 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, X
, Y
, cosa
, sina
);
1244 SetLineBoundingBox (line
);
1249 /* pre-delete the pins from the pin-tree before their coordinates change */
1251 r_delete_entry (Data
->pin_tree
, (BoxType
*)pin
);
1252 RestoreToPolygon (Data
, PIN_TYPE
, Element
, pin
);
1253 free_rotate (&pin
->X
, &pin
->Y
, X
, Y
, cosa
, sina
);
1254 SetPinBoundingBox (pin
);
1259 /* pre-delete the pads before their coordinates change */
1261 r_delete_entry (Data
->pad_tree
, (BoxType
*)pad
);
1262 RestoreToPolygon (Data
, PAD_TYPE
, Element
, pad
);
1263 free_rotate (&pad
->Point1
.X
, &pad
->Point1
.Y
, X
, Y
, cosa
, sina
);
1264 free_rotate (&pad
->Point2
.X
, &pad
->Point2
.Y
, X
, Y
, cosa
, sina
);
1265 SetLineBoundingBox ((LineType
*) pad
);
1270 free_rotate (&arc
->X
, &arc
->Y
, X
, Y
, cosa
, sina
);
1271 arc
->StartAngle
= NormalizeAngle (arc
->StartAngle
+ angle
);
1275 free_rotate (&Element
->MarkX
, &Element
->MarkY
, X
, Y
, cosa
, sina
);
1276 SetElementBoundingBox (Data
, Element
, &PCB
->Font
);
1277 ClearFromPolygon (Data
, ELEMENT_TYPE
, Element
, Element
);
1281 FreeRotateBuffer (BufferType
*Buffer
, Angle angle
)
1285 cosa
= cos(angle
* M_PI
/180.0);
1286 sina
= sin(angle
* M_PI
/180.0);
1289 VIA_LOOP (Buffer
->Data
);
1291 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1292 free_rotate (&via
->X
, &via
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1293 SetPinBoundingBox (via
);
1294 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1299 ELEMENT_LOOP (Buffer
->Data
);
1301 FreeRotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1306 /* all layer related objects */
1307 ALLLINE_LOOP (Buffer
->Data
);
1309 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1310 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1311 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1312 SetLineBoundingBox (line
);
1313 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1316 ALLARC_LOOP (Buffer
->Data
);
1318 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1319 free_rotate (&arc
->X
, &arc
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1320 arc
->StartAngle
= NormalizeAngle (arc
->StartAngle
+ angle
);
1321 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1324 /* FIXME: rotate text */
1325 ALLPOLYGON_LOOP (Buffer
->Data
);
1327 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1328 POLYGONPOINT_LOOP (polygon
);
1330 free_rotate (&point
->X
, &point
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1333 SetPolygonBoundingBox (polygon
);
1334 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1338 SetBufferBoundingBox (Buffer
);
1339 SetCrosshairRangeToBuffer ();
1343 /* -------------------------------------------------------------------------- */
1345 static const char freerotatebuffer_syntax
[] =
1346 N_("FreeRotateBuffer([Angle])");
1348 static const char freerotatebuffer_help
[] =
1349 N_("Rotates the current paste buffer contents by the specified angle. The\n"
1350 "angle is given in degrees. If no angle is given, the user is prompted\n"
1353 /* %start-doc actions FreeRotateBuffer
1355 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1356 angle is given, the user is prompted for one.
1361 ActionFreeRotateBuffer(int argc
, char **argv
, Coord x
, Coord y
)
1366 angle_s
= gui
->prompt_for (_("Enter Rotation (degrees, CCW):"), "0");
1370 notify_crosshair_change (false);
1371 FreeRotateBuffer(PASTEBUFFER
, strtod(angle_s
, 0));
1372 notify_crosshair_change (true);
1376 /* ---------------------------------------------------------------------------
1377 * initializes the buffers by allocating memory
1384 for (i
= 0; i
< MAX_BUFFER
; i
++)
1385 Buffers
[i
].Data
= CreateNewBuffer ();
1393 for (i
= 0; i
< MAX_BUFFER
; i
++)
1394 SwapBuffer (&Buffers
[i
]);
1395 SetCrosshairRangeToBuffer ();
1399 MirrorBuffer (BufferType
*Buffer
)
1403 if (Buffer
->Data
->ElementN
)
1405 Message (_("You can't mirror a buffer that has elements!\n"));
1408 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
1410 LayerType
*layer
= Buffer
->Data
->Layer
+ i
;
1413 Message (_("You can't mirror a buffer that has text!\n"));
1417 /* set buffer offset to 'mark' position */
1418 Buffer
->X
= SWAP_X (Buffer
->X
);
1419 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1420 VIA_LOOP (Buffer
->Data
);
1422 via
->X
= SWAP_X (via
->X
);
1423 via
->Y
= SWAP_Y (via
->Y
);
1426 ALLLINE_LOOP (Buffer
->Data
);
1428 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1429 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1430 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1431 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1434 ALLARC_LOOP (Buffer
->Data
);
1436 arc
->X
= SWAP_X (arc
->X
);
1437 arc
->Y
= SWAP_Y (arc
->Y
);
1438 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1439 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1440 SetArcBoundingBox (arc
);
1443 ALLPOLYGON_LOOP (Buffer
->Data
);
1445 POLYGONPOINT_LOOP (polygon
);
1447 point
->X
= SWAP_X (point
->X
);
1448 point
->Y
= SWAP_Y (point
->Y
);
1451 SetPolygonBoundingBox (polygon
);
1454 SetBufferBoundingBox (Buffer
);
1455 SetCrosshairRangeToBuffer ();
1459 /* ---------------------------------------------------------------------------
1460 * flip components/tracks from one side to the other
1463 SwapBuffer (BufferType
*Buffer
)
1466 Cardinal top_group
, bottom_group
;
1469 ELEMENT_LOOP (Buffer
->Data
);
1471 r_delete_element (Buffer
->Data
, element
);
1472 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
1475 /* set buffer offset to 'mark' position */
1476 Buffer
->X
= SWAP_X (Buffer
->X
);
1477 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1478 VIA_LOOP (Buffer
->Data
);
1480 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1481 via
->X
= SWAP_X (via
->X
);
1482 via
->Y
= SWAP_Y (via
->Y
);
1483 SetPinBoundingBox (via
);
1484 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1487 ALLLINE_LOOP (Buffer
->Data
);
1489 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1490 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1491 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1492 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1493 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1494 SetLineBoundingBox (line
);
1495 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1498 ALLARC_LOOP (Buffer
->Data
);
1500 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1501 arc
->X
= SWAP_X (arc
->X
);
1502 arc
->Y
= SWAP_Y (arc
->Y
);
1503 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1504 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1505 SetArcBoundingBox (arc
);
1506 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1509 ALLPOLYGON_LOOP (Buffer
->Data
);
1511 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1512 POLYGONPOINT_LOOP (polygon
);
1514 point
->X
= SWAP_X (point
->X
);
1515 point
->Y
= SWAP_Y (point
->Y
);
1518 SetPolygonBoundingBox (polygon
);
1519 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1520 /* hmmm, how to handle clip */
1523 ALLTEXT_LOOP (Buffer
->Data
);
1525 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
1526 text
->X
= SWAP_X (text
->X
);
1527 text
->Y
= SWAP_Y (text
->Y
);
1528 TOGGLE_FLAG (ONSOLDERFLAG
, text
);
1529 SetTextBoundingBox (&PCB
->Font
, text
);
1530 r_insert_entry (layer
->text_tree
, (BoxType
*)text
, 0);
1533 /* swap silkscreen layers */
1534 swap
= Buffer
->Data
->Layer
[bottom_silk_layer
];
1535 Buffer
->Data
->Layer
[bottom_silk_layer
] =
1536 Buffer
->Data
->Layer
[top_silk_layer
];
1537 Buffer
->Data
->Layer
[top_silk_layer
] = swap
;
1539 /* swap layer groups when balanced */
1540 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
1541 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
1542 if (PCB
->LayerGroups
.Number
[top_group
] == PCB
->LayerGroups
.Number
[bottom_group
])
1544 for (j
= k
= 0; j
< PCB
->LayerGroups
.Number
[bottom_group
]; j
++)
1547 Cardinal top_number
= PCB
->LayerGroups
.Entries
[top_group
][k
];
1548 Cardinal bottom_number
= PCB
->LayerGroups
.Entries
[bottom_group
][j
];
1550 if (bottom_number
>= max_copper_layer
)
1552 swap
= Buffer
->Data
->Layer
[bottom_number
];
1554 while (top_number
>= max_copper_layer
)
1557 top_number
= PCB
->LayerGroups
.Entries
[top_group
][k
];
1559 Buffer
->Data
->Layer
[bottom_number
] = Buffer
->Data
->Layer
[top_number
];
1560 Buffer
->Data
->Layer
[top_number
] = swap
;
1562 /* move the thermal flags with the layers */
1563 ALLPIN_LOOP (Buffer
->Data
);
1565 t1
= TEST_THERM (bottom_number
, pin
);
1566 t2
= TEST_THERM (top_number
, pin
);
1567 ASSIGN_THERM (bottom_number
, t2
, pin
);
1568 ASSIGN_THERM (top_number
, t1
, pin
);
1571 VIA_LOOP (Buffer
->Data
);
1573 t1
= TEST_THERM (bottom_number
, via
);
1574 t2
= TEST_THERM (top_number
, via
);
1575 ASSIGN_THERM (bottom_number
, t2
, via
);
1576 ASSIGN_THERM (top_number
, t1
, via
);
1581 SetBufferBoundingBox (Buffer
);
1582 SetCrosshairRangeToBuffer ();
1585 /* ----------------------------------------------------------------------
1586 * moves the passed object to the passed buffer and removes it
1587 * from its original place
1590 MoveObjectToBuffer (DataType
*Destination
, DataType
*Src
,
1591 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1593 /* setup local identifiers used by move operations */
1596 return (ObjectOperation (&MoveBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1599 /* ----------------------------------------------------------------------
1600 * Adds the passed object to the passed buffer
1603 CopyObjectToBuffer (DataType
*Destination
, DataType
*Src
,
1604 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1606 /* setup local identifiers used by Add operations */
1609 return (ObjectOperation (&AddBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1612 /* ---------------------------------------------------------------------- */
1614 HID_Action rotate_action_list
[] = {
1615 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer
,
1616 freerotatebuffer_syntax
, freerotatebuffer_help
},
1617 {"LoadFootprint", 0, LoadFootprint
,
1621 REGISTER_ACTIONS (rotate_action_list
)