6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used by paste- and move/copy buffer
45 #include "crosshair.h"
61 #ifdef HAVE_LIBDMALLOC
67 /* ---------------------------------------------------------------------------
68 * some local prototypes
70 static void *AddViaToBuffer (PinTypePtr
);
71 static void *AddLineToBuffer (LayerTypePtr
, LineTypePtr
);
72 static void *AddArcToBuffer (LayerTypePtr
, ArcTypePtr
);
73 static void *AddRatToBuffer (RatTypePtr
);
74 static void *AddTextToBuffer (LayerTypePtr
, TextTypePtr
);
75 static void *AddPolygonToBuffer (LayerTypePtr
, PolygonTypePtr
);
76 static void *AddElementToBuffer (ElementTypePtr
);
77 static void *MoveViaToBuffer (PinTypePtr
);
78 static void *MoveLineToBuffer (LayerTypePtr
, LineTypePtr
);
79 static void *MoveArcToBuffer (LayerTypePtr
, ArcTypePtr
);
80 static void *MoveRatToBuffer (RatTypePtr
);
81 static void *MoveTextToBuffer (LayerTypePtr
, TextTypePtr
);
82 static void *MovePolygonToBuffer (LayerTypePtr
, PolygonTypePtr
);
83 static void *MoveElementToBuffer (ElementTypePtr
);
84 static void SwapBuffer (BufferTypePtr
);
86 #define ARG(n) (argc > (n) ? argv[n] : 0)
88 /* ---------------------------------------------------------------------------
89 * some local identifiers
91 static DataTypePtr Dest
, Source
;
93 static ObjectFunctionType AddBufferFunctions
= {
106 }, MoveBufferFunctions
=
114 NULL
, NULL
, NULL
, NULL
, NULL
, MoveArcToBuffer
, MoveRatToBuffer
};
116 static int ExtraFlag
= 0;
118 /* ---------------------------------------------------------------------------
119 * copies a via to paste buffer
122 AddViaToBuffer (PinTypePtr Via
)
124 return (CreateNewVia (Dest
, Via
->X
, Via
->Y
, Via
->Thickness
, Via
->Clearance
,
125 Via
->Mask
, Via
->DrillingHole
, Via
->Name
,
126 MaskFlags (Via
->Flags
, FOUNDFLAG
| ExtraFlag
)));
129 /* ---------------------------------------------------------------------------
130 * copies a rat-line to paste buffer
133 AddRatToBuffer (RatTypePtr Rat
)
135 return (CreateNewRat (Dest
, Rat
->Point1
.X
, Rat
->Point1
.Y
,
136 Rat
->Point2
.X
, Rat
->Point2
.Y
, Rat
->group1
,
137 Rat
->group2
, Rat
->Thickness
,
138 MaskFlags (Rat
->Flags
, FOUNDFLAG
| ExtraFlag
)));
141 /* ---------------------------------------------------------------------------
142 * copies a line to buffer
145 AddLineToBuffer (LayerTypePtr Layer
, LineTypePtr Line
)
148 LayerTypePtr layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
150 line
= CreateNewLineOnLayer (layer
, Line
->Point1
.X
, Line
->Point1
.Y
,
151 Line
->Point2
.X
, Line
->Point2
.Y
,
152 Line
->Thickness
, Line
->Clearance
,
153 MaskFlags (Line
->Flags
,
154 FOUNDFLAG
| ExtraFlag
));
155 if (line
&& Line
->Number
)
156 line
->Number
= MyStrdup (Line
->Number
, "AddLineToBuffer");
160 /* ---------------------------------------------------------------------------
161 * copies an arc to buffer
164 AddArcToBuffer (LayerTypePtr Layer
, ArcTypePtr Arc
)
166 LayerTypePtr layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
168 return (CreateNewArcOnLayer (layer
, Arc
->X
, Arc
->Y
,
169 Arc
->Width
, Arc
->Height
, Arc
->StartAngle
, Arc
->Delta
,
170 Arc
->Thickness
, Arc
->Clearance
,
171 MaskFlags (Arc
->Flags
,
172 FOUNDFLAG
| ExtraFlag
)));
175 /* ---------------------------------------------------------------------------
176 * copies a text to buffer
179 AddTextToBuffer (LayerTypePtr Layer
, TextTypePtr Text
)
181 LayerTypePtr layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
183 return (CreateNewText (layer
, &PCB
->Font
, Text
->X
, Text
->Y
,
184 Text
->Direction
, Text
->Scale
, Text
->TextString
,
185 MaskFlags (Text
->Flags
, ExtraFlag
)));
188 /* ---------------------------------------------------------------------------
189 * copies a polygon to buffer
192 AddPolygonToBuffer (LayerTypePtr Layer
, PolygonTypePtr Polygon
)
194 LayerTypePtr layer
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
195 PolygonTypePtr polygon
;
197 polygon
= GetPolygonMemory (layer
);
198 CopyPolygonLowLevel (polygon
, Polygon
);
199 CLEAR_FLAG (FOUNDFLAG
| ExtraFlag
, polygon
);
203 /* ---------------------------------------------------------------------------
204 * copies a element to buffer
207 AddElementToBuffer (ElementTypePtr Element
)
209 ElementTypePtr element
;
211 element
= GetElementMemory (Dest
);
212 CopyElementLowLevel (Dest
, element
, Element
, false, 0, 0);
213 CLEAR_FLAG (ExtraFlag
, element
);
216 ELEMENTTEXT_LOOP (element
);
218 CLEAR_FLAG (ExtraFlag
, text
);
223 CLEAR_FLAG (FOUNDFLAG
| ExtraFlag
, pin
);
228 CLEAR_FLAG (FOUNDFLAG
| ExtraFlag
, pad
);
235 /* ---------------------------------------------------------------------------
236 * moves a via to paste buffer without allocating memory for the name
239 MoveViaToBuffer (PinTypePtr Via
)
243 RestoreToPolygon (Source
, VIA_TYPE
, Via
, Via
);
244 r_delete_entry (Source
->via_tree
, (BoxType
*) Via
);
245 via
= GetViaMemory (Dest
);
247 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, via
);
248 if (Via
!= &Source
->Via
[--Source
->ViaN
])
250 *Via
= Source
->Via
[Source
->ViaN
];
251 r_substitute (Source
->via_tree
, (BoxType
*) & Source
->Via
[Source
->ViaN
],
254 memset (&Source
->Via
[Source
->ViaN
], 0, sizeof (PinType
));
256 Dest
->via_tree
= r_create_tree (NULL
, 0, 0);
257 r_insert_entry (Dest
->via_tree
, (BoxType
*) via
, 0);
258 ClearFromPolygon (Dest
, VIA_TYPE
, via
, via
);
262 /* ---------------------------------------------------------------------------
263 * moves a rat-line to paste buffer
266 MoveRatToBuffer (RatTypePtr Rat
)
270 r_delete_entry (Source
->rat_tree
, &Rat
->BoundingBox
);
271 rat
= GetRatMemory (Dest
);
273 CLEAR_FLAG (FOUNDFLAG
, rat
);
274 if (Rat
!= &Source
->Rat
[--Source
->RatN
])
276 *Rat
= Source
->Rat
[Source
->RatN
];
277 r_substitute (Source
->rat_tree
, &Source
->Rat
[Source
->RatN
].BoundingBox
,
280 memset (&Source
->Rat
[Source
->RatN
], 0, sizeof (RatType
));
282 Dest
->rat_tree
= r_create_tree (NULL
, 0, 0);
283 r_insert_entry (Dest
->rat_tree
, &rat
->BoundingBox
, 0);
287 /* ---------------------------------------------------------------------------
288 * moves a line to buffer
291 MoveLineToBuffer (LayerTypePtr Layer
, LineTypePtr Line
)
296 RestoreToPolygon (Source
, LINE_TYPE
, Layer
, Line
);
297 r_delete_entry (Layer
->line_tree
, (BoxTypePtr
) Line
);
298 lay
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
299 line
= GetLineMemory (lay
);
301 CLEAR_FLAG (FOUNDFLAG
, line
);
302 /* line pointers being shuffled */
303 if (Line
!= &Layer
->Line
[--Layer
->LineN
])
305 *Line
= Layer
->Line
[Layer
->LineN
];
306 r_substitute (Layer
->line_tree
, (BoxTypePtr
) & Layer
->Line
[Layer
->LineN
],
309 memset (&Layer
->Line
[Layer
->LineN
], 0, sizeof (LineType
));
311 lay
->line_tree
= r_create_tree (NULL
, 0, 0);
312 r_insert_entry (lay
->line_tree
, (BoxTypePtr
) line
, 0);
313 ClearFromPolygon (Dest
, LINE_TYPE
, lay
, line
);
317 /* ---------------------------------------------------------------------------
318 * moves an arc to buffer
321 MoveArcToBuffer (LayerTypePtr Layer
, ArcTypePtr Arc
)
326 RestoreToPolygon (Source
, ARC_TYPE
, Layer
, Arc
);
327 r_delete_entry (Layer
->arc_tree
, (BoxTypePtr
) Arc
);
328 lay
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
329 arc
= GetArcMemory (lay
);
331 CLEAR_FLAG (FOUNDFLAG
, arc
);
332 /* arc pointers being shuffled */
333 if (Arc
!= &Layer
->Arc
[--Layer
->ArcN
])
335 *Arc
= Layer
->Arc
[Layer
->ArcN
];
336 r_substitute (Layer
->arc_tree
, (BoxTypePtr
) & Layer
->Arc
[Layer
->ArcN
],
339 memset (&Layer
->Arc
[Layer
->ArcN
], 0, sizeof (ArcType
));
341 lay
->arc_tree
= r_create_tree (NULL
, 0, 0);
342 r_insert_entry (lay
->arc_tree
, (BoxTypePtr
) arc
, 0);
343 ClearFromPolygon (Dest
, ARC_TYPE
, lay
, arc
);
347 /* ---------------------------------------------------------------------------
348 * moves a text to buffer without allocating memory for the name
351 MoveTextToBuffer (LayerTypePtr Layer
, TextTypePtr Text
)
356 r_delete_entry (Layer
->text_tree
, (BoxTypePtr
) Text
);
357 RestoreToPolygon (Source
, TEXT_TYPE
, Layer
, Text
);
358 lay
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
359 text
= GetTextMemory (lay
);
361 if (Text
!= &Layer
->Text
[--Layer
->TextN
])
363 *Text
= Layer
->Text
[Layer
->TextN
];
364 r_substitute (Layer
->text_tree
, (BoxTypePtr
) & Layer
->Text
[Layer
->TextN
],
367 memset (&Layer
->Text
[Layer
->TextN
], 0, sizeof (TextType
));
369 lay
->text_tree
= r_create_tree (NULL
, 0, 0);
370 r_insert_entry (lay
->text_tree
, (BoxTypePtr
) text
, 0);
371 ClearFromPolygon (Dest
, TEXT_TYPE
, lay
, text
);
375 /* ---------------------------------------------------------------------------
376 * moves a polygon to buffer. Doesn't allocate memory for the points
379 MovePolygonToBuffer (LayerTypePtr Layer
, PolygonTypePtr Polygon
)
382 PolygonTypePtr polygon
;
384 r_delete_entry (Layer
->polygon_tree
, (BoxTypePtr
) Polygon
);
385 lay
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
386 polygon
= GetPolygonMemory (lay
);
388 CLEAR_FLAG (FOUNDFLAG
, polygon
);
389 if (Polygon
!= &Layer
->Polygon
[--Layer
->PolygonN
])
391 *Polygon
= Layer
->Polygon
[Layer
->PolygonN
];
392 r_substitute (Layer
->polygon_tree
,
393 (BoxTypePtr
) & Layer
->Polygon
[Layer
->PolygonN
],
394 (BoxTypePtr
) Polygon
);
396 memset (&Layer
->Polygon
[Layer
->PolygonN
], 0, sizeof (PolygonType
));
397 if (!lay
->polygon_tree
)
398 lay
->polygon_tree
= r_create_tree (NULL
, 0, 0);
399 r_insert_entry (lay
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
403 /* ---------------------------------------------------------------------------
404 * moves a element to buffer without allocating memory for pins/names
407 MoveElementToBuffer (ElementTypePtr Element
)
409 ElementTypePtr element
;
413 * Two steps at once: Delete the element from the source (remove it
414 * from trees, restore to polygons) and simultaneously adjust its
415 * component pointers to the new storage in Dest
417 r_delete_element (Source
, Element
);
418 element
= GetElementMemory (Dest
);
422 RestoreToPolygon(Source
, PIN_TYPE
, Element
, pin
);
423 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pin
);
424 pin
->Element
= element
;
429 RestoreToPolygon(Source
, PAD_TYPE
, Element
, pad
);
430 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pad
);
431 pad
->Element
= element
;
434 ELEMENTTEXT_LOOP (element
);
436 text
->Element
= element
;
439 SetElementBoundingBox (Dest
, element
, &PCB
->Font
);
441 * Now clear the from the polygons in the destination
445 ClearFromPolygon (Dest
, PIN_TYPE
, element
, pin
);
450 ClearFromPolygon (Dest
, PAD_TYPE
, element
, pad
);
455 * Now compact the Source's Element array by moving the last element
456 * to the hole created by the removal above. Then make a pass adjusting
457 * *its* component pointers. Confusingly, this element (which is of no
458 * particular relation to this removal) becomes `Element' while the
459 * original Element is now in `element'.
461 if (Element
!= &Source
->Element
[--Source
->ElementN
])
463 *Element
= Source
->Element
[Source
->ElementN
];
464 r_substitute (Source
->element_tree
,
465 (BoxType
*) & Source
->Element
[Source
->ElementN
],
466 (BoxType
*) Element
);
467 for (i
= 0; i
< MAX_ELEMENTNAMES
; i
++)
468 r_substitute (Source
->name_tree
[i
],
469 (BoxType
*) & Source
->Element
[Source
->ElementN
].Name
[i
],
470 (BoxType
*) & Element
->Name
[i
]);
471 ELEMENTTEXT_LOOP (Element
);
473 text
->Element
= Element
;
478 pin
->Element
= Element
;
483 pad
->Element
= Element
;
487 memset (&Source
->Element
[Source
->ElementN
], 0, sizeof (ElementType
));
491 /* ---------------------------------------------------------------------------
492 * calculates the bounding box of the buffer
495 SetBufferBoundingBox (BufferTypePtr Buffer
)
497 BoxTypePtr box
= GetDataBoundingBox (Buffer
->Data
);
500 Buffer
->BoundingBox
= *box
;
503 /* ---------------------------------------------------------------------------
504 * clears the contents of the paste buffer
507 ClearBuffer (BufferTypePtr Buffer
)
509 if (Buffer
&& Buffer
->Data
)
511 FreeDataMemory (Buffer
->Data
);
512 Buffer
->Data
->pcb
= PCB
;
516 /* ----------------------------------------------------------------------
517 * copies all selected and visible objects to the paste buffer
518 * returns true if any objects have been removed
521 AddSelectedToBuffer (BufferTypePtr Buffer
, LocationType X
, LocationType Y
,
524 /* switch crosshair off because adding objects to the pastebuffer
525 * may change the 'valid' area for the cursor
528 ExtraFlag
= SELECTEDFLAG
;
529 HideCrosshair (true);
532 SelectedOperation (&AddBufferFunctions
, false, ALL_TYPES
);
534 /* set origin to passed or current position */
542 Buffer
->X
= Crosshair
.X
;
543 Buffer
->Y
= Crosshair
.Y
;
545 RestoreCrosshair (true);
549 /* ---------------------------------------------------------------------------
550 * loads element data from file/library into buffer
551 * parse the file with disabled 'PCB mode' (see parser)
552 * returns false on error
553 * if successful, update some other stuff and reposition the pastebuffer
556 LoadElementToBuffer (BufferTypePtr Buffer
, char *Name
, bool FromFile
)
558 ElementTypePtr element
;
560 ClearBuffer (Buffer
);
563 if (!ParseElementFile (Buffer
->Data
, Name
))
565 if (Settings
.ShowSolderSide
)
567 SetBufferBoundingBox (Buffer
);
568 if (Buffer
->Data
->ElementN
)
570 element
= &(Buffer
->Data
->Element
[0]);
571 Buffer
->X
= element
->MarkX
;
572 Buffer
->Y
= element
->MarkY
;
584 if (!ParseLibraryEntry (Buffer
->Data
, Name
)
585 && Buffer
->Data
->ElementN
!= 0)
587 element
= &(Buffer
->Data
->Element
[0]);
589 /* always add elements using top-side coordinates */
590 if (Settings
.ShowSolderSide
)
591 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
592 SetElementBoundingBox (Buffer
->Data
, element
, &PCB
->Font
);
594 /* set buffer offset to 'mark' position */
595 Buffer
->X
= element
->MarkX
;
596 Buffer
->Y
= element
->MarkY
;
597 SetBufferBoundingBox (Buffer
);
601 /* release memory which might have been acquired */
602 ClearBuffer (Buffer
);
607 /*---------------------------------------------------------------------------
608 * Searches for the given element by "footprint" name, and loads it
612 /* Figuring out which library entry is the one we want is a little
613 tricky. For file-based footprints, it's just a matter of finding
614 the first match in the search list. For m4-based footprints you
615 need to know what magic to pass to the m4 functions. Fortunately,
616 the footprint needed is determined when we build the m4 libraries
617 and stored as a comment in the description, so we can search for
618 that to find the magic we need. We use a hash to store the
619 corresponding footprints and pointers to the library tree so we can
620 quickly find the various bits we need to load a given
625 int footprint_allocated
;
628 } FootprintHashEntry
;
630 static FootprintHashEntry
*footprint_hash
= 0;
631 int footprint_hash_size
= 0;
634 clear_footprint_hash ()
639 for (i
=0; i
<footprint_hash_size
; i
++)
640 if (footprint_hash
[i
].footprint_allocated
)
641 free (footprint_hash
[i
].footprint
);
642 free (footprint_hash
);
643 footprint_hash
= NULL
;
644 footprint_hash_size
= 0;
647 /* Used to sort footprint pointer entries. Note we include the index
648 numbers so that same-named footprints are sorted by the library
651 footprint_hash_cmp (const void *va
, const void *vb
)
654 FootprintHashEntry
*a
= (FootprintHashEntry
*)va
;
655 FootprintHashEntry
*b
= (FootprintHashEntry
*)vb
;
657 i
= strcmp (a
->footprint
, b
->footprint
);
659 i
= a
->menu_idx
- b
->menu_idx
;
661 i
= a
->entry_idx
- b
->entry_idx
;
666 make_footprint_hash ()
672 clear_footprint_hash ();
674 for (i
=0; i
<Library
.MenuN
; i
++)
675 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
677 footprint_hash
= (FootprintHashEntry
*)malloc (num_entries
* sizeof(FootprintHashEntry
));
680 /* There are two types of library entries. The file-based types
681 have a Template of (char *)-1 and the AllocatedMemory is the full
682 path to the footprint file. The m4 ones have the footprint name
683 in brackets in the description. */
684 for (i
=0; i
<Library
.MenuN
; i
++)
687 printf("In make_footprint_hash, looking for footprints in %s\n",
688 Library
.Menu
[i
].directory
);
691 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
693 footprint_hash
[num_entries
].menu_idx
= i
;
694 footprint_hash
[num_entries
].entry_idx
= j
;
695 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
699 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
701 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '/');
704 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].AllocatedMemory
, '\\');
709 fp
= Library
.Menu
[i
].Entry
[j
].AllocatedMemory
;
712 /* printf(" ... found file footprint %s\n", fp); */
715 footprint_hash
[num_entries
].footprint
= fp
;
716 footprint_hash
[num_entries
].footprint_allocated
= 0;
721 fp
= strrchr (Library
.Menu
[i
].Entry
[j
].Description
, '[');
724 footprint_hash
[num_entries
].footprint
= strdup (fp
+1);
725 footprint_hash
[num_entries
].footprint_allocated
= 1;
726 fp
= strchr (footprint_hash
[num_entries
].footprint
, ']');
732 fp
= Library
.Menu
[i
].Entry
[j
].Description
;
733 footprint_hash
[num_entries
].footprint
= fp
;
734 footprint_hash
[num_entries
].footprint_allocated
= 0;
741 footprint_hash_size
= num_entries
;
742 qsort (footprint_hash
, num_entries
, sizeof(footprint_hash
[0]), footprint_hash_cmp
);
745 printf(" found footprints: \n");
746 for (i=0; i<num_entries; i++)
747 printf("[%s]\n", footprint_hash[i].footprint);
753 search_footprint_hash (const char *footprint
)
757 /* Standard binary search */
760 max
= footprint_hash_size
;
762 while (max
- min
> 1)
765 c
= strcmp (footprint
, footprint_hash
[i
].footprint
);
772 /* We want to return the first match, not just any match. */
774 && strcmp (footprint
, footprint_hash
[i
-1].footprint
) == 0)
776 return & footprint_hash
[i
];
782 /* Returns zero on success, non-zero on error. */
784 LoadFootprintByName (BufferTypePtr Buffer
, char *Footprint
)
787 FootprintHashEntry
*fpe
;
788 LibraryMenuType
*menu
;
789 LibraryEntryType
*entry
;
790 char *with_fp
= NULL
;
793 make_footprint_hash ();
795 fpe
= search_footprint_hash (Footprint
);
798 with_fp
= Concat (Footprint
, ".fp", NULL
);
799 fpe
= search_footprint_hash (with_fp
);
805 Message("Unable to load footprint %s\n", Footprint
);
809 menu
= & Library
.Menu
[fpe
->menu_idx
];
810 entry
= & menu
->Entry
[fpe
->entry_idx
];
812 if (entry
->Template
== (char *) -1)
814 i
= LoadElementToBuffer (Buffer
, entry
->AllocatedMemory
, true);
823 args
= Concat("'", EMPTY (entry
->Template
), "' '",
824 EMPTY (entry
->Value
), "' '", EMPTY (entry
->Package
), "'", NULL
);
825 i
= LoadElementToBuffer (Buffer
, args
, false);
836 printf("Library path: %s\n", Settings
.LibraryPath
);
837 printf("Library tree: %s\n", Settings
.LibraryTree
);
839 printf("Library:\n");
840 for (i
=0; i
<Library
.MenuN
; i
++)
842 printf(" [%02d] Name: %s\n", i
, Library
.Menu
[i
].Name
);
843 printf(" Dir: %s\n", Library
.Menu
[i
].directory
);
844 printf(" Sty: %s\n", Library
.Menu
[i
].Style
);
845 for (j
=0; j
<Library
.Menu
[i
].EntryN
; j
++)
847 printf(" [%02d] E: %s\n", j
, Library
.Menu
[i
].Entry
[j
].ListEntry
);
848 if (Library
.Menu
[i
].Entry
[j
].Template
== (char *) -1)
849 printf(" A: %s\n", Library
.Menu
[i
].Entry
[j
].AllocatedMemory
);
852 printf(" T: %s\n", Library
.Menu
[i
].Entry
[j
].Template
);
853 printf(" P: %s\n", Library
.Menu
[i
].Entry
[j
].Package
);
854 printf(" V: %s\n", Library
.Menu
[i
].Entry
[j
].Value
);
855 printf(" D: %s\n", Library
.Menu
[i
].Entry
[j
].Description
);
866 static const char loadfootprint_syntax
[] = "LoadFootprint(filename[,refdes,value])";
868 static const char loadfootprint_help
[] = "Loads a single footprint by name";
870 /* %start-doc actions LoadFootprint
872 Loads a single footprint by name, rather than by reference or through
873 the library. If a refdes and value are specified, those are inserted
874 into the footprint as well. The footprint remains in the paste buffer.
879 LoadFootprint (int argc
, char **argv
, int x
, int y
)
882 char *refdes
= ARG(1);
883 char *value
= ARG(2);
887 AFAIL (loadfootprint
);
889 if (LoadFootprintByName (PASTEBUFFER
, name
))
892 if (PASTEBUFFER
->Data
->ElementN
== 0)
894 Message("Footprint %s contains no elements", name
);
897 if (PASTEBUFFER
->Data
->ElementN
> 1)
899 Message("Footprint %s contains multiple elements", name
);
903 e
= & PASTEBUFFER
->Data
->Element
[0];
905 if (e
->Name
[0].TextString
)
906 free (e
->Name
[0].TextString
);
907 e
->Name
[0].TextString
= strdup (name
);
909 if (e
->Name
[1].TextString
)
910 free (e
->Name
[1].TextString
);
911 e
->Name
[1].TextString
= refdes
? strdup (refdes
) : 0;
913 if (e
->Name
[2].TextString
)
914 free (e
->Name
[2].TextString
);
915 e
->Name
[2].TextString
= value
? strdup (value
) : 0;
920 /*---------------------------------------------------------------------------
922 * break buffer element into pieces
925 SmashBufferElement (BufferTypePtr Buffer
)
927 ElementTypePtr element
;
929 LayerTypePtr clayer
, slayer
;
931 if (Buffer
->Data
->ElementN
!= 1)
933 Message (_("Error! Buffer doesn't contain a single element\n"));
936 element
= &Buffer
->Data
->Element
[0];
937 Buffer
->Data
->ElementN
= 0;
938 ClearBuffer (Buffer
);
939 ELEMENTLINE_LOOP (element
);
941 CreateNewLineOnLayer (&Buffer
->Data
->SILKLAYER
,
942 line
->Point1
.X
, line
->Point1
.Y
,
943 line
->Point2
.X
, line
->Point2
.Y
,
944 line
->Thickness
, 0, NoFlags ());
946 line
->Number
= MyStrdup (NAMEONPCB_NAME (element
), "SmashBuffer");
951 CreateNewArcOnLayer (&Buffer
->Data
->SILKLAYER
,
952 arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
,
953 arc
->Delta
, arc
->Thickness
, 0, NoFlags ());
958 FlagType f
= NoFlags ();
959 AddFlags (f
, VIAFLAG
);
960 if (TEST_FLAG (HOLEFLAG
, pin
))
961 AddFlags (f
, HOLEFLAG
);
963 CreateNewVia (Buffer
->Data
, pin
->X
, pin
->Y
,
964 pin
->Thickness
, pin
->Clearance
, pin
->Mask
,
965 pin
->DrillingHole
, pin
->Number
, f
);
969 GetLayerGroupNumberByNumber (max_layer
+
970 (SWAP_IDENT
? SOLDER_LAYER
:
972 clayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
974 GetLayerGroupNumberByNumber (max_layer
+
975 (SWAP_IDENT
? COMPONENT_LAYER
:
977 slayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
981 line
= CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG
, pad
) ? slayer
: clayer
,
982 pad
->Point1
.X
, pad
->Point1
.Y
,
983 pad
->Point2
.X
, pad
->Point2
.Y
,
984 pad
->Thickness
, pad
->Clearance
, NoFlags ());
986 line
->Number
= MyStrdup (pad
->Number
, "SmashBuffer");
989 FreeElementMemory (element
);
994 /*---------------------------------------------------------------------------
996 * see if a polygon is a rectangle. If so, canonicalize it.
1000 polygon_is_rectangle (PolygonTypePtr poly
)
1004 if (poly
->PointN
!= 4)
1008 if (poly
->Points
[i
].X
< poly
->Points
[best
].X
1009 || poly
->Points
[i
].Y
< poly
->Points
[best
].Y
)
1012 temp
[i
] = poly
->Points
[(i
+best
)%4];
1013 if (temp
[0].X
== temp
[1].X
)
1014 memcpy (poly
->Points
, temp
, sizeof(temp
));
1018 poly
->Points
[0] = temp
[0];
1019 poly
->Points
[1] = temp
[3];
1020 poly
->Points
[2] = temp
[2];
1021 poly
->Points
[3] = temp
[1];
1023 if (poly
->Points
[0].X
== poly
->Points
[1].X
1024 && poly
->Points
[1].Y
== poly
->Points
[2].Y
1025 && poly
->Points
[2].X
== poly
->Points
[3].X
1026 && poly
->Points
[3].Y
== poly
->Points
[0].Y
)
1031 /*---------------------------------------------------------------------------
1033 * convert buffer contents into an element
1036 ConvertBufferToElement (BufferTypePtr Buffer
)
1038 ElementTypePtr Element
;
1041 bool hasParts
= false, crooked
= false;
1043 if (Buffer
->Data
->pcb
== 0)
1044 Buffer
->Data
->pcb
= PCB
;
1046 Element
= CreateNewElement (PCB
->Data
, NULL
, &PCB
->Font
, NoFlags (),
1047 NULL
, NULL
, NULL
, PASTEBUFFER
->X
,
1048 PASTEBUFFER
->Y
, 0, 100,
1049 MakeFlags (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
),
1053 VIA_LOOP (Buffer
->Data
);
1056 if (via
->Mask
< via
->Thickness
)
1057 via
->Mask
= via
->Thickness
+ 2 * MASKFRAME
* 100; /* MASKFRAME is in mils */
1059 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
1060 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
1061 NULL
, via
->Name
, MaskFlags (via
->Flags
,
1062 VIAFLAG
| FOUNDFLAG
|
1063 SELECTEDFLAG
| WARNFLAG
));
1066 sprintf (num
, "%d", pin_n
++);
1067 CreateNewPin (Element
, via
->X
, via
->Y
, via
->Thickness
,
1068 via
->Clearance
, via
->Mask
, via
->DrillingHole
,
1069 NULL
, num
, MaskFlags (via
->Flags
,
1070 VIAFLAG
| FOUNDFLAG
| SELECTEDFLAG
1076 /* get the component-side SM pads */
1077 group
= GetLayerGroupNumberByNumber (max_layer
+
1078 (SWAP_IDENT
? SOLDER_LAYER
:
1080 GROUP_LOOP (Buffer
->Data
, group
);
1085 sprintf (num
, "%d", pin_n
++);
1086 CreateNewPad (Element
, line
->Point1
.X
,
1087 line
->Point1
.Y
, line
->Point2
.X
,
1088 line
->Point2
.Y
, line
->Thickness
,
1090 line
->Thickness
+ line
->Clearance
, NULL
,
1091 line
->Number
? line
->Number
: num
,
1092 MakeFlags (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
));
1096 POLYGON_LOOP (layer
);
1098 int x1
, y1
, x2
, y2
, w
, h
, t
;
1100 if (! polygon_is_rectangle (polygon
))
1106 w
= polygon
->Points
[2].X
- polygon
->Points
[0].X
;
1107 h
= polygon
->Points
[1].Y
- polygon
->Points
[0].Y
;
1108 t
= (w
< h
) ? w
: h
;
1109 x1
= polygon
->Points
[0].X
+ t
/2;
1110 y1
= polygon
->Points
[0].Y
+ t
/2;
1114 sprintf (num
, "%d", pin_n
++);
1115 CreateNewPad (Element
,
1117 2 * Settings
.Keepaway
,
1118 t
+ Settings
.Keepaway
,
1120 MakeFlags (SQUAREFLAG
| (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
)));
1126 /* now get the opposite side pads */
1127 group
= GetLayerGroupNumberByNumber (max_layer
+
1128 (SWAP_IDENT
? COMPONENT_LAYER
:
1130 GROUP_LOOP (Buffer
->Data
, group
);
1132 bool warned
= false;
1136 sprintf (num
, "%d", pin_n
++);
1137 CreateNewPad (Element
, line
->Point1
.X
,
1138 line
->Point1
.Y
, line
->Point2
.X
,
1139 line
->Point2
.Y
, line
->Thickness
,
1141 line
->Thickness
+ line
->Clearance
, NULL
,
1142 line
->Number
? line
->Number
: num
,
1143 MakeFlags (SWAP_IDENT
? NOFLAG
: ONSOLDERFLAG
));
1144 if (!hasParts
&& !warned
)
1148 (_("Warning: All of the pads are on the opposite\n"
1149 "side from the component - that's probably not what\n"
1157 /* now add the silkscreen. NOTE: elements must have pads or pins too */
1158 LINE_LOOP (&Buffer
->Data
->SILKLAYER
);
1160 if (line
->Number
&& !NAMEONPCB_NAME (Element
))
1161 NAMEONPCB_NAME (Element
) = MyStrdup (line
->Number
,
1162 "ConvertBufferToElement");
1163 CreateNewLineInElement (Element
, line
->Point1
.X
,
1164 line
->Point1
.Y
, line
->Point2
.X
,
1165 line
->Point2
.Y
, line
->Thickness
);
1169 ARC_LOOP (&Buffer
->Data
->SILKLAYER
);
1171 CreateNewArcInElement (Element
, arc
->X
, arc
->Y
, arc
->Width
,
1172 arc
->Height
, arc
->StartAngle
, arc
->Delta
,
1179 DestroyObject (PCB
->Data
, ELEMENT_TYPE
, Element
, Element
, Element
);
1180 Message (_("There was nothing to convert!\n"
1181 "Elements must have some silk, pads or pins.\n"));
1185 Message (_("There were polygons that can't be made into pins!\n"
1186 "So they were not included in the element\n"));
1187 Element
->MarkX
= Buffer
->X
;
1188 Element
->MarkY
= Buffer
->Y
;
1190 SET_FLAG (ONSOLDERFLAG
, Element
);
1191 SetElementBoundingBox (PCB
->Data
, Element
, &PCB
->Font
);
1192 ClearBuffer (Buffer
);
1193 MoveObjectToBuffer (Buffer
->Data
, PCB
->Data
, ELEMENT_TYPE
, Element
, Element
,
1195 SetBufferBoundingBox (Buffer
);
1199 /* ---------------------------------------------------------------------------
1200 * load PCB into buffer
1201 * parse the file with enabled 'PCB mode' (see parser)
1202 * if successful, update some other stuff
1205 LoadLayoutToBuffer (BufferTypePtr Buffer
, char *Filename
)
1207 PCBTypePtr newPCB
= CreateNewPCB (false);
1209 /* new data isn't added to the undo list */
1210 if (!ParsePCB (newPCB
, Filename
))
1212 /* clear data area and replace pointer */
1213 ClearBuffer (Buffer
);
1214 SaveFree (Buffer
->Data
);
1215 Buffer
->Data
= newPCB
->Data
;
1216 newPCB
->Data
= NULL
;
1217 Buffer
->X
= newPCB
->CursorX
;
1218 Buffer
->Y
= newPCB
->CursorY
;
1220 Buffer
->Data
->pcb
= PCB
;
1224 /* release unused memory */
1226 Buffer
->Data
->pcb
= PCB
;
1230 /* ---------------------------------------------------------------------------
1231 * rotates the contents of the pastebuffer
1234 RotateBuffer (BufferTypePtr Buffer
, BYTE Number
)
1237 VIA_LOOP (Buffer
->Data
);
1239 r_delete_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
);
1240 ROTATE_VIA_LOWLEVEL (via
, Buffer
->X
, Buffer
->Y
, Number
);
1241 SetPinBoundingBox (via
);
1242 r_insert_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
, 0);
1247 ELEMENT_LOOP (Buffer
->Data
);
1249 RotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1254 /* all layer related objects */
1255 ALLLINE_LOOP (Buffer
->Data
);
1257 r_delete_entry (layer
->line_tree
, (BoxTypePtr
) line
);
1258 RotateLineLowLevel (line
, Buffer
->X
, Buffer
->Y
, Number
);
1259 r_insert_entry (layer
->line_tree
, (BoxTypePtr
) line
, 0);
1262 ALLARC_LOOP (Buffer
->Data
);
1264 r_delete_entry (layer
->arc_tree
, (BoxTypePtr
) arc
);
1265 RotateArcLowLevel (arc
, Buffer
->X
, Buffer
->Y
, Number
);
1266 r_insert_entry (layer
->arc_tree
, (BoxTypePtr
) arc
, 0);
1269 ALLTEXT_LOOP (Buffer
->Data
);
1271 r_delete_entry (layer
->text_tree
, (BoxTypePtr
) text
);
1272 RotateTextLowLevel (text
, Buffer
->X
, Buffer
->Y
, Number
);
1273 r_insert_entry (layer
->text_tree
, (BoxTypePtr
) text
, 0);
1276 ALLPOLYGON_LOOP (Buffer
->Data
);
1278 r_delete_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
);
1279 RotatePolygonLowLevel (polygon
, Buffer
->X
, Buffer
->Y
, Number
);
1280 r_insert_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
1284 /* finally the origin and the bounding box */
1285 ROTATE (Buffer
->X
, Buffer
->Y
, Buffer
->X
, Buffer
->Y
, Number
);
1286 RotateBoxLowLevel (&Buffer
->BoundingBox
, Buffer
->X
, Buffer
->Y
, Number
);
1290 free_rotate (int *x
, int *y
, int cx
, int cy
, double cosa
, double sina
)
1296 nx
= px
* cosa
+ py
* sina
;
1297 ny
= py
* cosa
- px
* sina
;
1304 FreeRotateElementLowLevel (DataTypePtr Data
, ElementTypePtr Element
,
1305 LocationType X
, LocationType Y
,
1306 double cosa
, double sina
, double Angle
)
1308 /* solder side objects need a different orientation */
1310 /* the text subroutine decides by itself if the direction
1311 * is to be corrected
1314 ELEMENTTEXT_LOOP (Element
);
1316 if (Data
&& Data
->name_tree
[n
])
1317 r_delete_entry (Data
->name_tree
[n
], (BoxType
*) text
);
1318 RotateTextLowLevel (text
, X
, Y
, Number
);
1322 ELEMENTLINE_LOOP (Element
);
1324 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, X
, Y
, cosa
, sina
);
1325 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, X
, Y
, cosa
, sina
);
1326 SetLineBoundingBox (line
);
1331 /* pre-delete the pins from the pin-tree before their coordinates change */
1333 r_delete_entry (Data
->pin_tree
, (BoxType
*) pin
);
1334 RestoreToPolygon (Data
, PIN_TYPE
, Element
, pin
);
1335 free_rotate (&pin
->X
, &pin
->Y
, X
, Y
, cosa
, sina
);
1336 SetPinBoundingBox (pin
);
1341 /* pre-delete the pads before their coordinates change */
1343 r_delete_entry (Data
->pad_tree
, (BoxType
*) pad
);
1344 RestoreToPolygon (Data
, PAD_TYPE
, Element
, pad
);
1345 free_rotate (&pad
->Point1
.X
, &pad
->Point1
.Y
, X
, Y
, cosa
, sina
);
1346 free_rotate (&pad
->Point2
.X
, &pad
->Point2
.Y
, X
, Y
, cosa
, sina
);
1347 SetLineBoundingBox ((LineType
*) pad
);
1352 free_rotate (&arc
->X
, &arc
->Y
, X
, Y
, cosa
, sina
);
1353 arc
->StartAngle
+= Angle
;
1354 arc
->StartAngle
%= 360;
1358 free_rotate (&Element
->MarkX
, &Element
->MarkY
, X
, Y
, cosa
, sina
);
1359 SetElementBoundingBox (Data
, Element
, &PCB
->Font
);
1360 ClearFromPolygon (Data
, ELEMENT_TYPE
, Element
, Element
);
1364 FreeRotateBuffer (BufferTypePtr Buffer
, double Angle
)
1368 cosa
= cos(Angle
* M_PI
/180.0);
1369 sina
= sin(Angle
* M_PI
/180.0);
1372 VIA_LOOP (Buffer
->Data
);
1374 r_delete_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
);
1375 free_rotate (&via
->X
, &via
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1376 SetPinBoundingBox (via
);
1377 r_insert_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
, 0);
1382 ELEMENT_LOOP (Buffer
->Data
);
1384 FreeRotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
1389 /* all layer related objects */
1390 ALLLINE_LOOP (Buffer
->Data
);
1392 r_delete_entry (layer
->line_tree
, (BoxTypePtr
) line
);
1393 free_rotate (&line
->Point1
.X
, &line
->Point1
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1394 free_rotate (&line
->Point2
.X
, &line
->Point2
.Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1395 SetLineBoundingBox (line
);
1396 r_insert_entry (layer
->line_tree
, (BoxTypePtr
) line
, 0);
1399 ALLARC_LOOP (Buffer
->Data
);
1401 r_delete_entry (layer
->arc_tree
, (BoxTypePtr
) arc
);
1402 free_rotate (&arc
->X
, &arc
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1403 arc
->StartAngle
+= Angle
;
1404 arc
->StartAngle
%= 360;
1405 r_insert_entry (layer
->arc_tree
, (BoxTypePtr
) arc
, 0);
1408 /* FIXME: rotate text */
1409 ALLPOLYGON_LOOP (Buffer
->Data
);
1411 r_delete_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
);
1412 POLYGONPOINT_LOOP (polygon
);
1414 free_rotate (&point
->X
, &point
->Y
, Buffer
->X
, Buffer
->Y
, cosa
, sina
);
1417 SetPolygonBoundingBox (polygon
);
1418 r_insert_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
1422 SetBufferBoundingBox (Buffer
);
1426 /* -------------------------------------------------------------------------- */
1428 static const char freerotatebuffer_syntax
[] =
1429 "FreeRotateBuffer(Angle)";
1431 static const char freerotatebuffer_help
[] =
1432 "Rotates the current paste buffer contents by the specified angle. The\n"
1433 "angle is given in degrees.\n";
1435 /* %start-doc actions FreeRotateBuffer
1437 Rotates the contents of the pastebuffer by an arbitrary angle.
1441 ActionFreeRotateBuffer(int argc
, char **argv
, int x
, int y
)
1443 HideCrosshair(false);
1444 FreeRotateBuffer(PASTEBUFFER
, strtod(argv
[0], 0));
1445 RestoreCrosshair(false);
1449 /* ---------------------------------------------------------------------------
1450 * initializes the buffers by allocating memory
1457 for (i
= 0; i
< MAX_BUFFER
; i
++)
1458 Buffers
[i
].Data
= CreateNewBuffer ();
1466 for (i
= 0; i
< MAX_BUFFER
; i
++)
1467 SwapBuffer (&Buffers
[i
]);
1468 SetCrosshairRangeToBuffer ();
1472 MirrorBuffer (BufferTypePtr Buffer
)
1476 if (Buffer
->Data
->ElementN
)
1478 Message (_("You can't mirror a buffer that has elements!\n"));
1481 for (i
= 0; i
< max_layer
+ 2; i
++)
1483 LayerTypePtr layer
= Buffer
->Data
->Layer
+ i
;
1486 Message (_("You can't mirror a buffer that has text!\n"));
1490 /* set buffer offset to 'mark' position */
1491 Buffer
->X
= SWAP_X (Buffer
->X
);
1492 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1493 VIA_LOOP (Buffer
->Data
);
1495 via
->X
= SWAP_X (via
->X
);
1496 via
->Y
= SWAP_Y (via
->Y
);
1499 ALLLINE_LOOP (Buffer
->Data
);
1501 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1502 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1503 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1504 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1507 ALLARC_LOOP (Buffer
->Data
);
1509 arc
->X
= SWAP_X (arc
->X
);
1510 arc
->Y
= SWAP_Y (arc
->Y
);
1511 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1512 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1513 SetArcBoundingBox (arc
);
1516 ALLPOLYGON_LOOP (Buffer
->Data
);
1518 POLYGONPOINT_LOOP (polygon
);
1520 point
->X
= SWAP_X (point
->X
);
1521 point
->Y
= SWAP_Y (point
->Y
);
1524 SetPolygonBoundingBox (polygon
);
1527 SetBufferBoundingBox (Buffer
);
1531 /* ---------------------------------------------------------------------------
1532 * flip components/tracks from one side to the other
1535 SwapBuffer (BufferTypePtr Buffer
)
1538 Cardinal sgroup
, cgroup
;
1541 ELEMENT_LOOP (Buffer
->Data
);
1543 r_delete_element (Buffer
->Data
, element
);
1544 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
1547 /* set buffer offset to 'mark' position */
1548 Buffer
->X
= SWAP_X (Buffer
->X
);
1549 Buffer
->Y
= SWAP_Y (Buffer
->Y
);
1550 VIA_LOOP (Buffer
->Data
);
1552 r_delete_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
);
1553 via
->X
= SWAP_X (via
->X
);
1554 via
->Y
= SWAP_Y (via
->Y
);
1555 SetPinBoundingBox (via
);
1556 r_insert_entry (Buffer
->Data
->via_tree
, (BoxTypePtr
) via
, 0);
1559 ALLLINE_LOOP (Buffer
->Data
);
1561 r_delete_entry (layer
->line_tree
, (BoxTypePtr
) line
);
1562 line
->Point1
.X
= SWAP_X (line
->Point1
.X
);
1563 line
->Point1
.Y
= SWAP_Y (line
->Point1
.Y
);
1564 line
->Point2
.X
= SWAP_X (line
->Point2
.X
);
1565 line
->Point2
.Y
= SWAP_Y (line
->Point2
.Y
);
1566 SetLineBoundingBox (line
);
1567 r_insert_entry (layer
->line_tree
, (BoxTypePtr
) line
, 0);
1570 ALLARC_LOOP (Buffer
->Data
);
1572 r_delete_entry (layer
->arc_tree
, (BoxTypePtr
) arc
);
1573 arc
->X
= SWAP_X (arc
->X
);
1574 arc
->Y
= SWAP_Y (arc
->Y
);
1575 arc
->StartAngle
= SWAP_ANGLE (arc
->StartAngle
);
1576 arc
->Delta
= SWAP_DELTA (arc
->Delta
);
1577 SetArcBoundingBox (arc
);
1578 r_insert_entry (layer
->arc_tree
, (BoxTypePtr
) arc
, 0);
1581 ALLPOLYGON_LOOP (Buffer
->Data
);
1583 r_delete_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
);
1584 POLYGONPOINT_LOOP (polygon
);
1586 point
->X
= SWAP_X (point
->X
);
1587 point
->Y
= SWAP_Y (point
->Y
);
1590 SetPolygonBoundingBox (polygon
);
1591 r_insert_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
1592 /* hmmm, how to handle clip */
1595 ALLTEXT_LOOP (Buffer
->Data
);
1597 r_delete_entry (layer
->text_tree
, (BoxTypePtr
) text
);
1598 text
->X
= SWAP_X (text
->X
);
1599 text
->Y
= SWAP_Y (text
->Y
);
1600 TOGGLE_FLAG (ONSOLDERFLAG
, text
);
1601 SetTextBoundingBox (&PCB
->Font
, text
);
1602 r_insert_entry (layer
->text_tree
, (BoxTypePtr
) text
, 0);
1605 /* swap silkscreen layers */
1606 swap
= Buffer
->Data
->Layer
[max_layer
+ SOLDER_LAYER
];
1607 Buffer
->Data
->Layer
[max_layer
+ SOLDER_LAYER
] =
1608 Buffer
->Data
->Layer
[max_layer
+ COMPONENT_LAYER
];
1609 Buffer
->Data
->Layer
[max_layer
+ COMPONENT_LAYER
] = swap
;
1611 /* swap layer groups when balanced */
1612 sgroup
= GetLayerGroupNumberByNumber (max_layer
+ SOLDER_LAYER
);
1613 cgroup
= GetLayerGroupNumberByNumber (max_layer
+ COMPONENT_LAYER
);
1614 if (PCB
->LayerGroups
.Number
[cgroup
] == PCB
->LayerGroups
.Number
[sgroup
])
1616 for (j
= k
= 0; j
< PCB
->LayerGroups
.Number
[sgroup
]; j
++)
1619 Cardinal cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1620 Cardinal snumber
= PCB
->LayerGroups
.Entries
[sgroup
][j
];
1622 if (snumber
>= max_layer
)
1624 swap
= Buffer
->Data
->Layer
[snumber
];
1626 while (cnumber
>= max_layer
)
1629 cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1631 Buffer
->Data
->Layer
[snumber
] = Buffer
->Data
->Layer
[cnumber
];
1632 Buffer
->Data
->Layer
[cnumber
] = swap
;
1634 /* move the thermal flags with the layers */
1635 ALLPIN_LOOP (Buffer
->Data
);
1637 t1
= TEST_THERM (snumber
, pin
);
1638 t2
= TEST_THERM (cnumber
, pin
);
1639 ASSIGN_THERM (snumber
, t2
, pin
);
1640 ASSIGN_THERM (cnumber
, t1
, pin
);
1643 VIA_LOOP (Buffer
->Data
);
1645 t1
= TEST_THERM (snumber
, via
);
1646 t2
= TEST_THERM (cnumber
, via
);
1647 ASSIGN_THERM (snumber
, t2
, via
);
1648 ASSIGN_THERM (cnumber
, t1
, via
);
1653 SetBufferBoundingBox (Buffer
);
1656 /* ----------------------------------------------------------------------
1657 * moves the passed object to the passed buffer and removes it
1658 * from its original place
1661 MoveObjectToBuffer (DataTypePtr Destination
, DataTypePtr Src
,
1662 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1664 /* setup local identifiers used by move operations */
1667 return (ObjectOperation (&MoveBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1670 /* ----------------------------------------------------------------------
1671 * Adds the passed object to the passed buffer
1674 CopyObjectToBuffer (DataTypePtr Destination
, DataTypePtr Src
,
1675 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1677 /* setup local identifiers used by Add operations */
1680 return (ObjectOperation (&AddBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1683 /* ---------------------------------------------------------------------- */
1685 HID_Action rotate_action_list
[] = {
1686 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer
,
1687 freerotatebuffer_syntax
, freerotatebuffer_help
},
1688 {"LoadFootprint", 0, LoadFootprint
,
1692 REGISTER_ACTIONS (rotate_action_list
)