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
, FOUNDFLAG
| 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
, FOUNDFLAG
| 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 FOUNDFLAG
| 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 FOUNDFLAG
| 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 (FOUNDFLAG
| ExtraFlag
, polygon
);
208 /* ---------------------------------------------------------------------------
209 * copies a element to buffer
212 AddElementToBuffer (ElementType
*Element
)
214 ElementType
*element
;
216 element
= GetElementMemory (Dest
);
217 CopyElementLowLevel (Dest
, element
, Element
, false, 0, 0);
218 CLEAR_FLAG (ExtraFlag
, element
);
221 ELEMENTTEXT_LOOP (element
);
223 CLEAR_FLAG (ExtraFlag
, text
);
228 CLEAR_FLAG (FOUNDFLAG
| ExtraFlag
, pin
);
233 CLEAR_FLAG (FOUNDFLAG
| ExtraFlag
, pad
);
240 /* ---------------------------------------------------------------------------
241 * moves a via to paste buffer without allocating memory for the name
244 MoveViaToBuffer (PinType
*via
)
246 RestoreToPolygon (Source
, VIA_TYPE
, via
, via
);
248 r_delete_entry (Source
->via_tree
, (BoxType
*) via
);
249 Source
->Via
= g_list_remove (Source
->Via
, via
);
251 Dest
->Via
= g_list_append (Dest
->Via
, via
);
254 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, via
);
257 Dest
->via_tree
= r_create_tree (NULL
, 0, 0);
258 r_insert_entry (Dest
->via_tree
, (BoxType
*)via
, 0);
259 ClearFromPolygon (Dest
, VIA_TYPE
, via
, via
);
263 /* ---------------------------------------------------------------------------
264 * moves a rat-line to paste buffer
267 MoveRatToBuffer (RatType
*rat
)
269 r_delete_entry (Source
->rat_tree
, (BoxType
*)rat
);
271 Source
->Rat
= g_list_remove (Source
->Rat
, rat
);
273 Dest
->Rat
= g_list_append (Dest
->Rat
, rat
);
276 CLEAR_FLAG (FOUNDFLAG
, rat
);
279 Dest
->rat_tree
= r_create_tree (NULL
, 0, 0);
280 r_insert_entry (Dest
->rat_tree
, (BoxType
*)rat
, 0);
284 /* ---------------------------------------------------------------------------
285 * moves a line to buffer
288 MoveLineToBuffer (LayerType
*layer
, LineType
*line
)
290 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
292 RestoreToPolygon (Source
, LINE_TYPE
, layer
, line
);
293 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
295 layer
->Line
= g_list_remove (layer
->Line
, line
);
297 lay
->Line
= g_list_append (lay
->Line
, line
);
300 CLEAR_FLAG (FOUNDFLAG
, line
);
303 lay
->line_tree
= r_create_tree (NULL
, 0, 0);
304 r_insert_entry (lay
->line_tree
, (BoxType
*)line
, 0);
305 ClearFromPolygon (Dest
, LINE_TYPE
, lay
, line
);
309 /* ---------------------------------------------------------------------------
310 * moves an arc to buffer
313 MoveArcToBuffer (LayerType
*layer
, ArcType
*arc
)
315 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
317 RestoreToPolygon (Source
, ARC_TYPE
, layer
, arc
);
318 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
320 layer
->Arc
= g_list_remove (layer
->Arc
, arc
);
322 lay
->Arc
= g_list_append (lay
->Arc
, arc
);
325 CLEAR_FLAG (FOUNDFLAG
, arc
);
328 lay
->arc_tree
= r_create_tree (NULL
, 0, 0);
329 r_insert_entry (lay
->arc_tree
, (BoxType
*)arc
, 0);
330 ClearFromPolygon (Dest
, ARC_TYPE
, lay
, arc
);
334 /* ---------------------------------------------------------------------------
335 * moves a text to buffer without allocating memory for the name
338 MoveTextToBuffer (LayerType
*layer
, TextType
*text
)
340 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
342 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
343 RestoreToPolygon (Source
, TEXT_TYPE
, layer
, text
);
345 layer
->Text
= g_list_remove (layer
->Text
, text
);
347 lay
->Text
= g_list_append (lay
->Text
, text
);
351 lay
->text_tree
= r_create_tree (NULL
, 0, 0);
352 r_insert_entry (lay
->text_tree
, (BoxType
*)text
, 0);
353 ClearFromPolygon (Dest
, TEXT_TYPE
, lay
, text
);
357 /* ---------------------------------------------------------------------------
358 * moves a polygon to buffer. Doesn't allocate memory for the points
361 MovePolygonToBuffer (LayerType
*layer
, PolygonType
*polygon
)
363 LayerType
*lay
= &Dest
->Layer
[GetLayerNumber (Source
, layer
)];
365 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
367 layer
->Polygon
= g_list_remove (layer
->Polygon
, polygon
);
369 lay
->Polygon
= g_list_append (lay
->Polygon
, polygon
);
372 CLEAR_FLAG (FOUNDFLAG
, polygon
);
374 if (!lay
->polygon_tree
)
375 lay
->polygon_tree
= r_create_tree (NULL
, 0, 0);
376 r_insert_entry (lay
->polygon_tree
, (BoxType
*)polygon
, 0);
380 /* ---------------------------------------------------------------------------
381 * moves a element to buffer without allocating memory for pins/names
384 MoveElementToBuffer (ElementType
*element
)
387 * Delete the element from the source (remove it from trees,
388 * restore to polygons)
390 r_delete_element (Source
, element
);
392 Source
->Element
= g_list_remove (Source
->Element
, element
);
394 Dest
->Element
= g_list_append (Dest
->Element
, element
);
399 RestoreToPolygon(Source
, PIN_TYPE
, element
, pin
);
400 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pin
);
405 RestoreToPolygon(Source
, PAD_TYPE
, element
, pad
);
406 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pad
);
409 SetElementBoundingBox (Dest
, element
, &PCB
->Font
);
411 * Now clear the from the polygons in the destination
415 ClearFromPolygon (Dest
, PIN_TYPE
, element
, pin
);
420 ClearFromPolygon (Dest
, PAD_TYPE
, element
, pad
);
427 /* ---------------------------------------------------------------------------
428 * calculates the bounding box of the buffer
431 SetBufferBoundingBox (BufferType
*Buffer
)
433 BoxType
*box
= GetDataBoundingBox (Buffer
->Data
);
436 Buffer
->BoundingBox
= *box
;
439 /* ---------------------------------------------------------------------------
440 * clears the contents of the paste buffer
443 ClearBuffer (BufferType
*Buffer
)
445 if (Buffer
&& Buffer
->Data
)
447 FreeDataMemory (Buffer
->Data
);
448 Buffer
->Data
->pcb
= PCB
;
452 /* ----------------------------------------------------------------------
453 * copies all selected and visible objects to the paste buffer
454 * returns true if any objects have been removed
457 AddSelectedToBuffer (BufferType
*Buffer
, Coord X
, Coord Y
, bool LeaveSelected
)
459 /* switch crosshair off because adding objects to the pastebuffer
460 * may change the 'valid' area for the cursor
463 ExtraFlag
= SELECTEDFLAG
;
464 notify_crosshair_change (false);
467 SelectedOperation (&AddBufferFunctions
, false, ALL_TYPES
);
469 /* set origin to passed or current position */
477 Buffer
->X
= Crosshair
.X
;
478 Buffer
->Y
= Crosshair
.Y
;
480 notify_crosshair_change (true);
484 /* ---------------------------------------------------------------------------
485 * loads element data from file/library into buffer
486 * parse the file with disabled 'PCB mode' (see parser)
487 * returns false on error
488 * if successful, update some other stuff and reposition the pastebuffer
491 LoadElementToBuffer (BufferType
*Buffer
, char *Name
, bool FromFile
)
493 ElementType
*element
;
495 ClearBuffer (Buffer
);
498 if (!ParseElementFile (Buffer
->Data
, Name
))
500 if (Settings
.ShowSolderSide
)
502 SetBufferBoundingBox (Buffer
);
503 if (Buffer
->Data
->ElementN
)
505 element
= Buffer
->Data
->Element
->data
;
506 Buffer
->X
= element
->MarkX
;
507 Buffer
->Y
= element
->MarkY
;
519 if (!ParseLibraryEntry (Buffer
->Data
, Name
)
520 && Buffer
->Data
->ElementN
!= 0)
522 element
= Buffer
->Data
->Element
->data
;
524 /* always add elements using top-side coordinates */
525 if (Settings
.ShowSolderSide
)
526 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
527 SetElementBoundingBox (Buffer
->Data
, element
, &PCB
->Font
);
529 /* set buffer offset to 'mark' position */
530 Buffer
->X
= element
->MarkX
;
531 Buffer
->Y
= element
->MarkY
;
532 SetBufferBoundingBox (Buffer
);
536 /* release memory which might have been acquired */
537 ClearBuffer (Buffer
);
542 /*---------------------------------------------------------------------------
543 * Searches for the given element by "footprint" name, and loads it
547 /* Figuring out which library entry is the one we want is a little
548 tricky. For file-based footprints, it's just a matter of finding
549 the first match in the search list. For m4-based footprints you
550 need to know what magic to pass to the m4 functions. Fortunately,
551 the footprint needed is determined when we build the m4 libraries
552 and stored as a comment in the description, so we can search for
553 that to find the magic we need. We use a hash to store the
554 corresponding footprints and pointers to the library tree so we can
555 quickly find the various bits we need to load a given
560 int footprint_allocated
;
563 } FootprintHashEntry
;
565 static FootprintHashEntry
*footprint_hash
= 0;
566 int footprint_hash_size
= 0;
569 clear_footprint_hash ()
574 for (i
=0; i
<footprint_hash_size
; i
++)
575 if (footprint_hash
[i
].footprint_allocated
)
576 free (footprint_hash
[i
].footprint
);
577 free (footprint_hash
);
578 footprint_hash
= NULL
;
579 footprint_hash_size
= 0;
582 /* Used to sort footprint pointer entries. Note we include the index
583 numbers so that same-named footprints are sorted by the library
586 footprint_hash_cmp (const void *va
, const void *vb
)
589 FootprintHashEntry
*a
= (FootprintHashEntry
*)va
;
590 FootprintHashEntry
*b
= (FootprintHashEntry
*)vb
;
592 i
= strcmp (a
->footprint
, b
->footprint
);
594 i
= a
->menu_idx
- b
->menu_idx
;
596 i
= a
->entry_idx
- b
->entry_idx
;
601 make_footprint_hash ()
607 clear_footprint_hash ();
609 for (i
=0; i
<Library
.MenuN
; i
++)
610 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
612 footprint_hash
= (FootprintHashEntry
*)malloc (num_entries
* sizeof(FootprintHashEntry
));
615 /* There are two types of library entries. The file-based types
616 have a Template of (char *)-1 and the AllocatedMemory is the full
617 path to the footprint file. The m4 ones have the footprint name
618 in brackets in the description. */
619 for (i
=0; i
<Library
.MenuN
; i
++)
622 printf("In make_footprint_hash, looking for footprints in %s\n",
623 Library
.Menu
[i
].directory
);
626 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
628 footprint_hash
[num_entries
].menu_idx
= i
;
629 footprint_hash
[num_entries
].entry_idx
= j
;
630 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
634 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
636 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '/');
639 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '\\');
644 fp
= Library
.Menu
[i
].Entry
[j
].AllocatedMemory
;
647 /* printf(" ... found file footprint %s\n", fp); */
650 footprint_hash
[num_entries
].footprint
= fp
;
651 footprint_hash
[num_entries
].footprint_allocated
= 0;
656 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].Description
, '[');
659 footprint_hash
[num_entries
].footprint
= strdup (fp
+1);
660 footprint_hash
[num_entries
].footprint_allocated
= 1;
661 fp
= strchr (footprint_hash
[num_entries
].footprint
, ']');
667 fp
= Library
.Menu
[i
].Entry
[j
].Description
;
668 footprint_hash
[num_entries
].footprint
= fp
;
669 footprint_hash
[num_entries
].footprint_allocated
= 0;
676 footprint_hash_size
= num_entries
;
677 qsort (footprint_hash
, num_entries
, sizeof(footprint_hash
[0]), footprint_hash_cmp
);
680 printf(" found footprints: \n");
681 for (i=0; i<num_entries; i++)
682 printf("[%s]\n", footprint_hash[i].footprint);
688 search_footprint_hash (const char *footprint
)
692 /* Standard binary search */
695 max
= footprint_hash_size
;
697 while (max
- min
> 1)
700 c
= strcmp (footprint
, footprint_hash
[i
].footprint
);
707 /* We want to return the first match, not just any match. */
709 && strcmp (footprint
, footprint_hash
[i
-1].footprint
) == 0)
711 return & footprint_hash
[i
];
717 /* Returns zero on success, non-zero on error. */
719 LoadFootprintByName (BufferType
*Buffer
, char *Footprint
)
722 FootprintHashEntry
*fpe
;
723 LibraryMenuType
*menu
;
724 LibraryEntryType
*entry
;
725 char *with_fp
= NULL
;
728 make_footprint_hash ();
730 fpe
= search_footprint_hash (Footprint
);
733 with_fp
= Concat (Footprint
, ".fp", NULL
);
734 fpe
= search_footprint_hash (with_fp
);
740 Message("Unable to load footprint %s\n", Footprint
);
744 menu
= & Library
.Menu
[fpe
->menu_idx
];
745 entry
= & menu
->Entry
[fpe
->entry_idx
];
747 if (entry
->Template
== (char *) -1)
749 i
= LoadElementToBuffer (Buffer
, entry
->AllocatedMemory
, true);
758 args
= Concat("'", EMPTY (entry
->Template
), "' '",
759 EMPTY (entry
->Value
), "' '", EMPTY (entry
->Package
), "'", NULL
);
760 i
= LoadElementToBuffer (Buffer
, args
, false);
771 printf("Library path: %s\n", Settings
.LibraryPath
);
772 printf("Library tree: %s\n", Settings
.LibraryTree
);
774 printf("Library:\n");
775 for (i
=0; i
<Library
.MenuN
; i
++)
777 printf(" [%02d] Name: %s\n", i
, Library
.Menu
[i
].Name
);
778 printf(" Dir: %s\n", Library
.Menu
[i
].directory
);
779 printf(" Sty: %s\n", Library
.Menu
[i
].Style
);
780 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
782 printf(" [%02d] E: %s\n", j
, Library
.Menu
[i
].Entry
[j
].ListEntry
);
783 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
784 printf(" A: %s\n", Library
.Menu
[i
].Entry
[j
].AllocatedMemory
);
787 printf(" T: %s\n", Library
.Menu
[i
].Entry
[j
].Template
);
788 printf(" P: %s\n", Library
.Menu
[i
].Entry
[j
].Package
);
789 printf(" V: %s\n", Library
.Menu
[i
].Entry
[j
].Value
);
790 printf(" D: %s\n", Library
.Menu
[i
].Entry
[j
].Description
);
801 static const char loadfootprint_syntax
[] = "LoadFootprint(filename[,refdes,value])";
803 static const char loadfootprint_help
[] = "Loads a single footprint by name.";
805 /* %start-doc actions LoadFootprint
807 Loads a single footprint by name, rather than by reference or through
808 the library. If a refdes and value are specified, those are inserted
809 into the footprint as well. The footprint remains in the paste buffer.
814 LoadFootprint (int argc
, char **argv
, Coord x
, Coord y
)
817 char *refdes
= ARG(1);
818 char *value
= ARG(2);
822 AFAIL (loadfootprint
);
824 if (LoadFootprintByName (PASTEBUFFER
, name
))
827 if (PASTEBUFFER
->Data
->ElementN
== 0)
829 Message("Footprint %s contains no elements", name
);
832 if (PASTEBUFFER
->Data
->ElementN
> 1)
834 Message("Footprint %s contains multiple elements", name
);
838 e
= PASTEBUFFER
->Data
->Element
->data
;
840 if (e
->Name
[0].TextString
)
841 free (e
->Name
[0].TextString
);
842 e
->Name
[0].TextString
= strdup (name
);
844 if (e
->Name
[1].TextString
)
845 free (e
->Name
[1].TextString
);
846 e
->Name
[1].TextString
= refdes
? strdup (refdes
) : 0;
848 if (e
->Name
[2].TextString
)
849 free (e
->Name
[2].TextString
);
850 e
->Name
[2].TextString
= value
? strdup (value
) : 0;
855 /*---------------------------------------------------------------------------
857 * break buffer element into pieces
860 SmashBufferElement (BufferType
*Buffer
)
862 ElementType
*element
;
864 LayerType
*clayer
, *slayer
;
866 if (Buffer
->Data
->ElementN
!= 1)
868 Message (_("Error! Buffer doesn't contain a single element\n"));
872 * At this point the buffer should contain just a single element.
873 * Now we detach the single element from the buffer and then clear the
874 * buffer, ready to receive the smashed elements. As a result of detaching
875 * it the single element is orphaned from the buffer and thus will not be
876 * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it
877 * around for us to smash bits off it. It then becomes our responsibility,
878 * however, to free the single element when we're finished with it.
880 element
= Buffer
->Data
->Element
->data
;
881 Buffer
->Data
->Element
= NULL
;
882 Buffer
->Data
->ElementN
= 0;
883 ClearBuffer (Buffer
);
884 ELEMENTLINE_LOOP (element
);
886 CreateNewLineOnLayer (&Buffer
->Data
->SILKLAYER
,
887 line
->Point1
.X
, line
->Point1
.Y
,
888 line
->Point2
.X
, line
->Point2
.Y
,
889 line
->Thickness
, 0, NoFlags ());
891 line
->Number
= STRDUP (NAMEONPCB_NAME (element
));
896 CreateNewArcOnLayer (&Buffer
->Data
->SILKLAYER
,
897 arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
,
898 arc
->Delta
, arc
->Thickness
, 0, NoFlags ());
903 FlagType f
= NoFlags ();
904 AddFlags (f
, VIAFLAG
);
905 if (TEST_FLAG (HOLEFLAG
, pin
))
906 AddFlags (f
, HOLEFLAG
);
908 CreateNewVia (Buffer
->Data
, pin
->X
, pin
->Y
,
909 pin
->Thickness
, pin
->Clearance
, pin
->Mask
,
910 pin
->DrillingHole
, pin
->Number
, f
);
914 GetLayerGroupNumberByNumber (SWAP_IDENT
? solder_silk_layer
:
915 component_silk_layer
);
916 clayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
918 GetLayerGroupNumberByNumber (SWAP_IDENT
? component_silk_layer
:
920 slayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
924 line
= CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG
, pad
) ? slayer
: clayer
,
925 pad
->Point1
.X
, pad
->Point1
.Y
,
926 pad
->Point2
.X
, pad
->Point2
.Y
,
927 pad
->Thickness
, pad
->Clearance
, NoFlags ());
929 line
->Number
= STRDUP (pad
->Number
);
932 FreeElementMemory (element
);
933 g_slice_free (ElementType
, element
);
937 /*---------------------------------------------------------------------------
939 * see if a polygon is a rectangle. If so, canonicalize it.
943 polygon_is_rectangle (PolygonType
*poly
)
947 if (poly
->PointN
!= 4 || poly
->HoleIndexN
!= 0)
951 if (poly
->Points
[i
].X
< poly
->Points
[best
].X
952 || poly
->Points
[i
].Y
< poly
->Points
[best
].Y
)
955 temp
[i
] = poly
->Points
[(i
+best
)%4];
956 if (temp
[0].X
== temp
[1].X
)
957 memcpy (poly
->Points
, temp
, sizeof(temp
));
961 poly
->Points
[0] = temp
[0];
962 poly
->Points
[1] = temp
[3];
963 poly
->Points
[2] = temp
[2];
964 poly
->Points
[3] = temp
[1];
966 if (poly
->Points
[0].X
== poly
->Points
[1].X
967 && poly
->Points
[1].Y
== poly
->Points
[2].Y
968 && poly
->Points
[2].X
== poly
->Points
[3].X
969 && poly
->Points
[3].Y
== poly
->Points
[0].Y
)
974 /*---------------------------------------------------------------------------
976 * convert buffer contents into an element
979 ConvertBufferToElement (BufferType
*Buffer
)
981 ElementType
*Element
;
984 bool hasParts
= false, crooked
= false;
988 if (Buffer
->Data
->pcb
== 0)
989 Buffer
->Data
->pcb
= PCB
;
991 Element
= CreateNewElement (PCB
->Data
, NULL
, &PCB
->Font
, NoFlags (),
992 NULL
, NULL
, NULL
, PASTEBUFFER
->X
,
993 PASTEBUFFER
->Y
, 0, 100,
994 MakeFlags (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
),
998 VIA_LOOP (Buffer
->Data
);
1001 if (via
->Mask
< via
->Thickness
)
1002 via
->Mask
= via
->Thickness
+ 2 * MASKFRAME
;
1004 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
1005 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
1006 NULL
, via
->Name
, MaskFlags (via
->Flags
,
1007 VIAFLAG
| FOUNDFLAG
|
1008 SELECTEDFLAG
| WARNFLAG
));
1011 sprintf (num
, "%d", pin_n
++);
1012 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
1013 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
1014 NULL
, num
, MaskFlags (via
->Flags
,
1015 VIAFLAG
| FOUNDFLAG
| SELECTEDFLAG
1022 for (onsolder
= 0; onsolder
< 2; onsolder
++)
1027 if ((!onsolder
) == (!SWAP_IDENT
))
1029 silk_layer
= component_silk_layer
;
1030 onsolderflag
= NOFLAG
;
1034 silk_layer
= solder_silk_layer
;
1035 onsolderflag
= ONSOLDERFLAG
;
1038 #define MAYBE_WARN() \
1039 if (onsolder && !hasParts && !warned) \
1043 (_("Warning: All of the pads are on the opposite\n" \
1044 "side from the component - that's probably not what\n" \
1048 /* get the component-side SM pads */
1049 group
= GetLayerGroupNumberByNumber (silk_layer
);
1050 GROUP_LOOP (Buffer
->Data
, group
);
1055 sprintf (num
, "%d", pin_n
++);
1056 CreateNewPad (Element
, line
->Point1
.X
,
1057 line
->Point1
.Y
, line
->Point2
.X
,
1058 line
->Point2
.Y
, line
->Thickness
,
1060 line
->Thickness
+ line
->Clearance
, NULL
,
1061 line
->Number
? line
->Number
: num
,
1062 MakeFlags (onsolderflag
));
1067 POLYGON_LOOP (layer
);
1069 Coord x1
, y1
, x2
, y2
, w
, h
, t
;
1071 if (! polygon_is_rectangle (polygon
))
1077 w
= polygon
->Points
[2].X
- polygon
->Points
[0].X
;
1078 h
= polygon
->Points
[1].Y
- polygon
->Points
[0].Y
;
1079 t
= (w
< h
) ? w
: h
;
1080 x1
= polygon
->Points
[0].X
+ t
/2;
1081 y1
= polygon
->Points
[0].Y
+ t
/2;
1085 sprintf (num
, "%d", pin_n
++);
1086 CreateNewPad (Element
,
1088 2 * Settings
.Keepaway
,
1089 t
+ Settings
.Keepaway
,
1091 MakeFlags (SQUAREFLAG
| onsolderflag
));
1100 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1101 LINE_LOOP (&Buffer
->Data
->SILKLAYER
);
1103 if (line
->Number
&& !NAMEONPCB_NAME (Element
))
1104 NAMEONPCB_NAME (Element
) = strdup (line
->Number
);
1105 CreateNewLineInElement (Element
, line
->Point1
.X
,
1106 line
->Point1
.Y
, line
->Point2
.X
,
1107 line
->Point2
.Y
, line
->Thickness
);
1111 ARC_LOOP (&Buffer
->Data
->SILKLAYER
);
1113 CreateNewArcInElement (Element
, arc
->X
, arc
->Y
, arc
->Width
,
1114 arc
->Height
, arc
->StartAngle
, arc
->Delta
,
1121 DestroyObject (PCB
->Data
, ELEMENT_TYPE
, Element
, Element
, Element
);
1122 Message (_("There was nothing to convert!\n"
1123 "Elements must have some silk, pads or pins.\n"));
1127 Message (_("There were polygons that can't be made into pins!\n"
1128 "So they were not included in the element\n"));
1129 Element
->MarkX
= Buffer
->X
;
1130 Element
->MarkY
= Buffer
->Y
;
1132 SET_FLAG (ONSOLDERFLAG
, Element
);
1133 SetElementBoundingBox (PCB
->Data
, Element
, &PCB
->Font
);
1134 ClearBuffer (Buffer
);
1135 MoveObjectToBuffer (Buffer
->Data
, PCB
->Data
, ELEMENT_TYPE
, Element
, Element
,
1137 SetBufferBoundingBox (Buffer
);
1141 /* ---------------------------------------------------------------------------
1142 * load PCB into buffer
1143 * parse the file with enabled 'PCB mode' (see parser)
1144 * if successful, update some other stuff
1147 LoadLayoutToBuffer (BufferType
*Buffer
, char *Filename
)
1149 PCBType
*newPCB
= CreateNewPCB (false);
1151 /* new data isn't added to the undo list */
1152 if (!ParsePCB (newPCB
, Filename
))
1154 /* clear data area and replace pointer */
1155 ClearBuffer (Buffer
);
1156 free (Buffer
->Data
);
1157 Buffer
->Data
= newPCB
->Data
;
1158 newPCB
->Data
= NULL
;
1159 Buffer
->X
= newPCB
->CursorX
;
1160 Buffer
->Y
= newPCB
->CursorY
;
1162 Buffer
->Data
->pcb
= PCB
;
1166 /* release unused memory */
1168 Buffer
->Data
->pcb
= PCB
;
1172 /* ---------------------------------------------------------------------------
1173 * rotates the contents of the pastebuffer
1176 RotateBuffer (BufferType
*Buffer
, BYTE Number
)
1179 VIA_LOOP (Buffer
->Data
);
1181 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1182 ROTATE_VIA_LOWLEVEL (via
, Buffer
->X
, Buffer
->Y
, Number
);
1183 SetPinBoundingBox (via
);
1184 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1189 ELEMENT_LOOP (Buffer
->Data
);
1191 RotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1196 /* all layer related objects */
1197 ALLLINE_LOOP (Buffer
->Data
);
1199 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1200 RotateLineLowLevel (line
, Buffer
->X
, Buffer
->Y
, Number
);
1201 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1204 ALLARC_LOOP (Buffer
->Data
);
1206 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1207 RotateArcLowLevel (arc
, Buffer
->X
, Buffer
->Y
, Number
);
1208 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1211 ALLTEXT_LOOP (Buffer
->Data
);
1213 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
1214 RotateTextLowLevel (text
, Buffer
->X
, Buffer
->Y
, Number
);
1215 r_insert_entry (layer
->text_tree
, (BoxType
*)text
, 0);
1218 ALLPOLYGON_LOOP (Buffer
->Data
);
1220 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1221 RotatePolygonLowLevel (polygon
, Buffer
->X
, Buffer
->Y
, Number
);
1222 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1226 /* finally the origin and the bounding box */
1227 ROTATE (Buffer
->X
, Buffer
->Y
, Buffer
->X
, Buffer
->Y
, Number
);
1228 RotateBoxLowLevel (&Buffer
->BoundingBox
, Buffer
->X
, Buffer
->Y
, Number
);
1229 SetCrosshairRangeToBuffer ();
1233 free_rotate (Coord
*x
, Coord
*y
, Coord cx
, Coord cy
, double cosa
, double sina
)
1239 nx
= px
* cosa
+ py
* sina
;
1240 ny
= py
* cosa
- px
* sina
;
1247 FreeRotateElementLowLevel (DataType
*Data
, ElementType
*Element
,
1249 double cosa
, double sina
, Angle angle
)
1251 /* solder side objects need a different orientation */
1253 /* the text subroutine decides by itself if the direction
1254 * is to be corrected
1257 ELEMENTTEXT_LOOP (Element
);
1259 if (Data
&& Data
->name_tree
[n
])
1260 r_delete_entry (Data
->name_tree
[n
], (BoxType
*)text
);
1261 RotateTextLowLevel (text
, X
, Y
, Number
);
1265 ELEMENTLINE_LOOP (Element
);
1267 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, X
, Y
, cosa
, sina
);
1268 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, X
, Y
, cosa
, sina
);
1269 SetLineBoundingBox (line
);
1274 /* pre-delete the pins from the pin-tree before their coordinates change */
1276 r_delete_entry (Data
->pin_tree
, (BoxType
*)pin
);
1277 RestoreToPolygon (Data
, PIN_TYPE
, Element
, pin
);
1278 free_rotate (&pin
->X
, &pin
->Y
, X
, Y
, cosa
, sina
);
1279 SetPinBoundingBox (pin
);
1284 /* pre-delete the pads before their coordinates change */
1286 r_delete_entry (Data
->pad_tree
, (BoxType
*)pad
);
1287 RestoreToPolygon (Data
, PAD_TYPE
, Element
, pad
);
1288 free_rotate (&pad
->Point1
.X
, &pad
->Point1
.Y
, X
, Y
, cosa
, sina
);
1289 free_rotate (&pad
->Point2
.X
, &pad
->Point2
.Y
, X
, Y
, cosa
, sina
);
1290 SetLineBoundingBox ((LineType
*) pad
);
1295 free_rotate (&arc
->X
, &arc
->Y
, X
, Y
, cosa
, sina
);
1296 arc
->StartAngle
= NormalizeAngle (arc
->StartAngle
+ angle
);
1300 free_rotate (&Element
->MarkX
, &Element
->MarkY
, X
, Y
, cosa
, sina
);
1301 SetElementBoundingBox (Data
, Element
, &PCB
->Font
);
1302 ClearFromPolygon (Data
, ELEMENT_TYPE
, Element
, Element
);
1306 FreeRotateBuffer (BufferType
*Buffer
, Angle angle
)
1310 cosa
= cos(angle
* M_PI
/180.0);
1311 sina
= sin(angle
* M_PI
/180.0);
1314 VIA_LOOP (Buffer
->Data
);
1316 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1317 free_rotate (&via
->X
, &via
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1318 SetPinBoundingBox (via
);
1319 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1324 ELEMENT_LOOP (Buffer
->Data
);
1326 FreeRotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1331 /* all layer related objects */
1332 ALLLINE_LOOP (Buffer
->Data
);
1334 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1335 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1336 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1337 SetLineBoundingBox (line
);
1338 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1341 ALLARC_LOOP (Buffer
->Data
);
1343 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1344 free_rotate (&arc
->X
, &arc
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1345 arc
->StartAngle
= NormalizeAngle (arc
->StartAngle
+ angle
);
1346 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1349 /* FIXME: rotate text */
1350 ALLPOLYGON_LOOP (Buffer
->Data
);
1352 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1353 POLYGONPOINT_LOOP (polygon
);
1355 free_rotate (&point
->X
, &point
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1358 SetPolygonBoundingBox (polygon
);
1359 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1363 SetBufferBoundingBox (Buffer
);
1364 SetCrosshairRangeToBuffer ();
1368 /* -------------------------------------------------------------------------- */
1370 static const char freerotatebuffer_syntax
[] =
1371 "FreeRotateBuffer([Angle])";
1373 static const char freerotatebuffer_help
[] =
1374 "Rotates the current paste buffer contents by the specified angle. The\n"
1375 "angle is given in degrees. If no angle is given, the user is prompted\n"
1378 /* %start-doc actions FreeRotateBuffer
1380 Rotates the contents of the pastebuffer by an arbitrary angle. If no
1381 angle is given, the user is prompted for one.
1386 ActionFreeRotateBuffer(int argc
, char **argv
, Coord x
, Coord y
)
1391 angle_s
= gui
->prompt_for ("Enter Rotation (degrees, CCW):", "0");
1395 notify_crosshair_change (false);
1396 FreeRotateBuffer(PASTEBUFFER
, strtod(angle_s
, 0));
1397 notify_crosshair_change (true);
1401 /* ---------------------------------------------------------------------------
1402 * initializes the buffers by allocating memory
1409 for (i
= 0; i
< MAX_BUFFER
; i
++)
1410 Buffers
[i
].Data
= CreateNewBuffer ();
1418 for (i
= 0; i
< MAX_BUFFER
; i
++)
1419 SwapBuffer (&Buffers
[i
]);
1420 SetCrosshairRangeToBuffer ();
1424 MirrorBuffer (BufferType
*Buffer
)
1428 if (Buffer
->Data
->ElementN
)
1430 Message (_("You can't mirror a buffer that has elements!\n"));
1433 for (i
= 0; i
< max_copper_layer
+ 2; i
++)
1435 LayerType
*layer
= Buffer
->Data
->Layer
+ i
;
1438 Message (_("You can't mirror a buffer that has text!\n"));
1442 /* set buffer offset to 'mark' position */
1443 Buffer
->X
= SWAP_X (Buffer
->X
);
1444 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1445 VIA_LOOP (Buffer
->Data
);
1447 via
->X
= SWAP_X (via
->X
);
1448 via
->Y
= SWAP_Y (via
->Y
);
1451 ALLLINE_LOOP (Buffer
->Data
);
1453 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1454 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1455 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1456 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1459 ALLARC_LOOP (Buffer
->Data
);
1461 arc
->X
= SWAP_X (arc
->X
);
1462 arc
->Y
= SWAP_Y (arc
->Y
);
1463 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1464 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1465 SetArcBoundingBox (arc
);
1468 ALLPOLYGON_LOOP (Buffer
->Data
);
1470 POLYGONPOINT_LOOP (polygon
);
1472 point
->X
= SWAP_X (point
->X
);
1473 point
->Y
= SWAP_Y (point
->Y
);
1476 SetPolygonBoundingBox (polygon
);
1479 SetBufferBoundingBox (Buffer
);
1480 SetCrosshairRangeToBuffer ();
1484 /* ---------------------------------------------------------------------------
1485 * flip components/tracks from one side to the other
1488 SwapBuffer (BufferType
*Buffer
)
1491 Cardinal sgroup
, cgroup
;
1494 ELEMENT_LOOP (Buffer
->Data
);
1496 r_delete_element (Buffer
->Data
, element
);
1497 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
1500 /* set buffer offset to 'mark' position */
1501 Buffer
->X
= SWAP_X (Buffer
->X
);
1502 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1503 VIA_LOOP (Buffer
->Data
);
1505 r_delete_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
);
1506 via
->X
= SWAP_X (via
->X
);
1507 via
->Y
= SWAP_Y (via
->Y
);
1508 SetPinBoundingBox (via
);
1509 r_insert_entry (Buffer
->Data
->via_tree
, (BoxType
*)via
, 0);
1512 ALLLINE_LOOP (Buffer
->Data
);
1514 r_delete_entry (layer
->line_tree
, (BoxType
*)line
);
1515 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1516 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1517 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1518 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1519 SetLineBoundingBox (line
);
1520 r_insert_entry (layer
->line_tree
, (BoxType
*)line
, 0);
1523 ALLARC_LOOP (Buffer
->Data
);
1525 r_delete_entry (layer
->arc_tree
, (BoxType
*)arc
);
1526 arc
->X
= SWAP_X (arc
->X
);
1527 arc
->Y
= SWAP_Y (arc
->Y
);
1528 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1529 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1530 SetArcBoundingBox (arc
);
1531 r_insert_entry (layer
->arc_tree
, (BoxType
*)arc
, 0);
1534 ALLPOLYGON_LOOP (Buffer
->Data
);
1536 r_delete_entry (layer
->polygon_tree
, (BoxType
*)polygon
);
1537 POLYGONPOINT_LOOP (polygon
);
1539 point
->X
= SWAP_X (point
->X
);
1540 point
->Y
= SWAP_Y (point
->Y
);
1543 SetPolygonBoundingBox (polygon
);
1544 r_insert_entry (layer
->polygon_tree
, (BoxType
*)polygon
, 0);
1545 /* hmmm, how to handle clip */
1548 ALLTEXT_LOOP (Buffer
->Data
);
1550 r_delete_entry (layer
->text_tree
, (BoxType
*)text
);
1551 text
->X
= SWAP_X (text
->X
);
1552 text
->Y
= SWAP_Y (text
->Y
);
1553 TOGGLE_FLAG (ONSOLDERFLAG
, text
);
1554 SetTextBoundingBox (&PCB
->Font
, text
);
1555 r_insert_entry (layer
->text_tree
, (BoxType
*)text
, 0);
1558 /* swap silkscreen layers */
1559 swap
= Buffer
->Data
->Layer
[solder_silk_layer
];
1560 Buffer
->Data
->Layer
[solder_silk_layer
] =
1561 Buffer
->Data
->Layer
[component_silk_layer
];
1562 Buffer
->Data
->Layer
[component_silk_layer
] = swap
;
1564 /* swap layer groups when balanced */
1565 sgroup
= GetLayerGroupNumberByNumber (solder_silk_layer
);
1566 cgroup
= GetLayerGroupNumberByNumber (component_silk_layer
);
1567 if (PCB
->LayerGroups
.Number
[cgroup
] == PCB
->LayerGroups
.Number
[sgroup
])
1569 for (j
= k
= 0; j
< PCB
->LayerGroups
.Number
[sgroup
]; j
++)
1572 Cardinal cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1573 Cardinal snumber
= PCB
->LayerGroups
.Entries
[sgroup
][j
];
1575 if (snumber
>= max_copper_layer
)
1577 swap
= Buffer
->Data
->Layer
[snumber
];
1579 while (cnumber
>= max_copper_layer
)
1582 cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1584 Buffer
->Data
->Layer
[snumber
] = Buffer
->Data
->Layer
[cnumber
];
1585 Buffer
->Data
->Layer
[cnumber
] = swap
;
1587 /* move the thermal flags with the layers */
1588 ALLPIN_LOOP (Buffer
->Data
);
1590 t1
= TEST_THERM (snumber
, pin
);
1591 t2
= TEST_THERM (cnumber
, pin
);
1592 ASSIGN_THERM (snumber
, t2
, pin
);
1593 ASSIGN_THERM (cnumber
, t1
, pin
);
1596 VIA_LOOP (Buffer
->Data
);
1598 t1
= TEST_THERM (snumber
, via
);
1599 t2
= TEST_THERM (cnumber
, via
);
1600 ASSIGN_THERM (snumber
, t2
, via
);
1601 ASSIGN_THERM (cnumber
, t1
, via
);
1606 SetBufferBoundingBox (Buffer
);
1607 SetCrosshairRangeToBuffer ();
1610 /* ----------------------------------------------------------------------
1611 * moves the passed object to the passed buffer and removes it
1612 * from its original place
1615 MoveObjectToBuffer (DataType
*Destination
, DataType
*Src
,
1616 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1618 /* setup local identifiers used by move operations */
1621 return (ObjectOperation (&MoveBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1624 /* ----------------------------------------------------------------------
1625 * Adds the passed object to the passed buffer
1628 CopyObjectToBuffer (DataType
*Destination
, DataType
*Src
,
1629 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1631 /* setup local identifiers used by Add operations */
1634 return (ObjectOperation (&AddBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1637 /* ---------------------------------------------------------------------- */
1639 HID_Action rotate_action_list
[] = {
1640 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer
,
1641 freerotatebuffer_syntax
, freerotatebuffer_help
},
1642 {"LoadFootprint", 0, LoadFootprint
,
1646 REGISTER_ACTIONS (rotate_action_list
)