Fix node_label() function to work with self-intersection
[geda-pcb/gde.git] / src / buffer.c
blobfbd1735cf5e27448ed49c556f886b417b59a625c
1 /* $Id$ */
3 /*
4 * COPYRIGHT
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
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <stdlib.h>
37 #include <memory.h>
38 #include <math.h>
40 #include "global.h"
42 #include "buffer.h"
43 #include "copy.h"
44 #include "create.h"
45 #include "crosshair.h"
46 #include "data.h"
47 #include "error.h"
48 #include "mymem.h"
49 #include "mirror.h"
50 #include "misc.h"
51 #include "parse_l.h"
52 #include "polygon.h"
53 #include "rats.h"
54 #include "rotate.h"
55 #include "remove.h"
56 #include "rtree.h"
57 #include "search.h"
58 #include "select.h"
59 #include "set.h"
61 #ifdef HAVE_LIBDMALLOC
62 #include <dmalloc.h>
63 #endif
65 RCSID ("$Id$");
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 = {
94 AddLineToBuffer,
95 AddTextToBuffer,
96 AddPolygonToBuffer,
97 AddViaToBuffer,
98 AddElementToBuffer,
99 NULL,
100 NULL,
101 NULL,
102 NULL,
103 NULL,
104 AddArcToBuffer,
105 AddRatToBuffer
106 }, MoveBufferFunctions =
109 MoveLineToBuffer,
110 MoveTextToBuffer,
111 MovePolygonToBuffer,
112 MoveViaToBuffer,
113 MoveElementToBuffer,
114 NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
116 static int ExtraFlag = 0;
118 /* ---------------------------------------------------------------------------
119 * copies a via to paste buffer
121 static void *
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
132 static void *
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
144 static void *
145 AddLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
147 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");
157 return (line);
160 /* ---------------------------------------------------------------------------
161 * copies an arc to buffer
163 static void *
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
178 static void *
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
191 static void *
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);
200 return (polygon);
203 /* ---------------------------------------------------------------------------
204 * copies a element to buffer
206 static void *
207 AddElementToBuffer (ElementTypePtr Element)
209 ElementTypePtr element;
211 element = GetElementMemory (Dest);
212 CopyElementLowLevel (Dest, element, Element, False, 0, 0);
213 CLEAR_FLAG (ExtraFlag, element);
214 if (ExtraFlag)
216 ELEMENTTEXT_LOOP (element);
218 CLEAR_FLAG (ExtraFlag, text);
220 END_LOOP;
221 PIN_LOOP (element);
223 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, pin);
225 END_LOOP;
226 PAD_LOOP (element);
228 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, pad);
230 END_LOOP;
232 return (element);
235 /* ---------------------------------------------------------------------------
236 * moves a via to paste buffer without allocating memory for the name
238 static void *
239 MoveViaToBuffer (PinTypePtr Via)
241 PinTypePtr via;
243 RestoreToPolygon (Source, VIA_TYPE, Via, Via);
244 r_delete_entry (Source->via_tree, (BoxType *) Via);
245 via = GetViaMemory (Dest);
246 *via = *Via;
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],
252 (BoxType *) Via);
254 memset (&Source->Via[Source->ViaN], 0, sizeof (PinType));
255 if (!Dest->via_tree)
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);
259 return (via);
262 /* ---------------------------------------------------------------------------
263 * moves a rat-line to paste buffer
265 static void *
266 MoveRatToBuffer (RatTypePtr Rat)
268 RatTypePtr rat;
270 r_delete_entry (Source->rat_tree, &Rat->BoundingBox);
271 rat = GetRatMemory (Dest);
272 *rat = *Rat;
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,
278 &Rat->BoundingBox);
280 memset (&Source->Rat[Source->RatN], 0, sizeof (RatType));
281 if (!Dest->rat_tree)
282 Dest->rat_tree = r_create_tree (NULL, 0, 0);
283 r_insert_entry (Dest->rat_tree, &rat->BoundingBox, 0);
284 return (rat);
287 /* ---------------------------------------------------------------------------
288 * moves a line to buffer
290 static void *
291 MoveLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
293 LayerTypePtr lay;
294 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);
300 *line = *Line;
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],
307 (BoxTypePtr) Line);
309 memset (&Layer->Line[Layer->LineN], 0, sizeof (LineType));
310 if (!lay->line_tree)
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);
314 return (line);
317 /* ---------------------------------------------------------------------------
318 * moves an arc to buffer
320 static void *
321 MoveArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
323 LayerTypePtr lay;
324 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);
330 *arc = *Arc;
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],
337 (BoxTypePtr) Arc);
339 memset (&Layer->Arc[Layer->ArcN], 0, sizeof (ArcType));
340 if (!lay->arc_tree)
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);
344 return (arc);
347 /* ---------------------------------------------------------------------------
348 * moves a text to buffer without allocating memory for the name
350 static void *
351 MoveTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
353 TextTypePtr text;
354 LayerTypePtr lay;
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);
360 *text = *Text;
361 if (Text != &Layer->Text[--Layer->TextN])
363 *Text = Layer->Text[Layer->TextN];
364 r_substitute (Layer->text_tree, (BoxTypePtr) & Layer->Text[Layer->TextN],
365 (BoxTypePtr) Text);
367 memset (&Layer->Text[Layer->TextN], 0, sizeof (TextType));
368 if (!lay->text_tree)
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);
372 return (text);
375 /* ---------------------------------------------------------------------------
376 * moves a polygon to buffer. Doesn't allocate memory for the points
378 static void *
379 MovePolygonToBuffer (LayerTypePtr Layer, PolygonTypePtr Polygon)
381 LayerTypePtr lay;
382 PolygonTypePtr polygon;
384 r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
385 lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
386 polygon = GetPolygonMemory (lay);
387 *polygon = *Polygon;
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);
400 return (polygon);
403 /* ---------------------------------------------------------------------------
404 * moves a element to buffer without allocating memory for pins/names
406 static void *
407 MoveElementToBuffer (ElementTypePtr Element)
409 ElementTypePtr element;
410 int i;
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);
419 *element = *Element;
420 PIN_LOOP (element);
422 RestoreToPolygon(Source, PIN_TYPE, Element, pin);
423 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pin);
424 pin->Element = element;
426 END_LOOP;
427 PAD_LOOP (element);
429 RestoreToPolygon(Source, PAD_TYPE, Element, pad);
430 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pad);
431 pad->Element = element;
433 END_LOOP;
434 ELEMENTTEXT_LOOP (element);
436 text->Element = element;
438 END_LOOP;
439 SetElementBoundingBox (Dest, element, &PCB->Font);
441 * Now clear the from the polygons in the destination
443 PIN_LOOP (element);
445 ClearFromPolygon (Dest, PIN_TYPE, element, pin);
447 END_LOOP;
448 PAD_LOOP (element);
450 ClearFromPolygon (Dest, PAD_TYPE, element, pad);
452 END_LOOP;
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;
475 END_LOOP;
476 PIN_LOOP (Element);
478 pin->Element = Element;
480 END_LOOP;
481 PAD_LOOP (Element);
483 pad->Element = Element;
485 END_LOOP;
487 memset (&Source->Element[Source->ElementN], 0, sizeof (ElementType));
488 return (element);
491 /* ---------------------------------------------------------------------------
492 * calculates the bounding box of the buffer
494 void
495 SetBufferBoundingBox (BufferTypePtr Buffer)
497 BoxTypePtr box = GetDataBoundingBox (Buffer->Data);
499 if (box)
500 Buffer->BoundingBox = *box;
503 /* ---------------------------------------------------------------------------
504 * clears the contents of the paste buffer
506 void
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
520 void
521 AddSelectedToBuffer (BufferTypePtr Buffer, LocationType X, LocationType Y,
522 Boolean LeaveSelected)
524 /* switch crosshair off because adding objects to the pastebuffer
525 * may change the 'valid' area for the cursor
527 if (!LeaveSelected)
528 ExtraFlag = SELECTEDFLAG;
529 HideCrosshair (True);
530 Source = PCB->Data;
531 Dest = Buffer->Data;
532 SelectedOperation (&AddBufferFunctions, False, ALL_TYPES);
534 /* set origin to passed or current position */
535 if (X || Y)
537 Buffer->X = X;
538 Buffer->Y = Y;
540 else
542 Buffer->X = Crosshair.X;
543 Buffer->Y = Crosshair.Y;
545 RestoreCrosshair (True);
546 ExtraFlag = 0;
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
555 Boolean
556 LoadElementToBuffer (BufferTypePtr Buffer, char *Name, Boolean FromFile)
558 ElementTypePtr element;
560 ClearBuffer (Buffer);
561 if (FromFile)
563 if (!ParseElementFile (Buffer->Data, Name))
565 if (Settings.ShowSolderSide)
566 SwapBuffer (Buffer);
567 SetBufferBoundingBox (Buffer);
568 if (Buffer->Data->ElementN)
570 element = &(Buffer->Data->Element[0]);
571 Buffer->X = element->MarkX;
572 Buffer->Y = element->MarkY;
574 else
576 Buffer->X = 0;
577 Buffer->Y = 0;
579 return (True);
582 else
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);
598 return (True);
601 /* release memory which might have been acquired */
602 ClearBuffer (Buffer);
603 return (False);
607 /*---------------------------------------------------------------------------
608 * Searches for the given element by "footprint" name, and loads it
609 * into the buffer.
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
621 footprint. */
623 typedef struct {
624 char *footprint;
625 int footprint_allocated;
626 int menu_idx;
627 int entry_idx;
628 } FootprintHashEntry;
630 static FootprintHashEntry *footprint_hash = 0;
631 int footprint_hash_size = 0;
633 void
634 clear_footprint_hash ()
636 int i;
637 if (!footprint_hash)
638 return;
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
649 search order. */
650 static int
651 footprint_hash_cmp (const void *va, const void *vb)
653 int i;
654 FootprintHashEntry *a = (FootprintHashEntry *)va;
655 FootprintHashEntry *b = (FootprintHashEntry *)vb;
657 i = strcmp (a->footprint, b->footprint);
658 if (i == 0)
659 i = a->menu_idx - b->menu_idx;
660 if (i == 0)
661 i = a->entry_idx - b->entry_idx;
662 return i;
665 void
666 make_footprint_hash ()
668 int i, j;
669 char *fp;
670 int num_entries = 0;
672 clear_footprint_hash ();
674 for (i=0; i<Library.MenuN; i++)
675 for (j=0; j<Library.Menu[i].EntryN; j++)
676 num_entries ++;
677 footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
678 num_entries = 0;
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++)
686 #ifdef DEBUG
687 printf("In make_footprint_hash, looking for footprints in %s\n",
688 Library.Menu[i].directory);
689 #endif
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)
696 /* file */
698 #ifdef DEBUG
699 /* printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
700 #endif
701 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
703 if (!fp)
704 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
706 if (fp)
707 fp ++;
708 else
709 fp = Library.Menu[i].Entry[j].AllocatedMemory;
711 #ifdef DEBUG
712 /* printf(" ... found file footprint %s\n", fp); */
713 #endif
715 footprint_hash[num_entries].footprint = fp;
716 footprint_hash[num_entries].footprint_allocated = 0;
718 else
719 /* m4 */
721 fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
722 if (fp)
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, ']');
727 if (fp)
728 *fp = 0;
730 else
732 fp = Library.Menu[i].Entry[j].Description;
733 footprint_hash[num_entries].footprint = fp;
734 footprint_hash[num_entries].footprint_allocated = 0;
737 num_entries ++;
741 footprint_hash_size = num_entries;
742 qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
744 #ifdef DEBUG
745 printf(" found footprints: \n");
746 for (i=0; i<num_entries; i++)
747 printf("[%s]\n", footprint_hash[i].footprint);
748 #endif
752 FootprintHashEntry *
753 search_footprint_hash (const char *footprint)
755 int i, min, max, c;
757 /* Standard binary search */
759 min = -1;
760 max = footprint_hash_size;
762 while (max - min > 1)
764 i = (min+max)/2;
765 c = strcmp (footprint, footprint_hash[i].footprint);
766 if (c < 0)
767 max = i;
768 else if (c > 0)
769 min = i;
770 else
772 /* We want to return the first match, not just any match. */
773 while (i > 0
774 && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
775 i--;
776 return & footprint_hash[i];
779 return NULL;
782 /* Returns zero on success, non-zero on error. */
784 LoadFootprintByName (BufferTypePtr Buffer, char *Footprint)
786 int i;
787 FootprintHashEntry *fpe;
788 LibraryMenuType *menu;
789 LibraryEntryType *entry;
790 char *with_fp = NULL;
792 if (!footprint_hash)
793 make_footprint_hash ();
795 fpe = search_footprint_hash (Footprint);
796 if (!fpe)
798 with_fp = Concat (Footprint, ".fp", NULL);
799 fpe = search_footprint_hash (with_fp);
800 if (fpe)
801 Footprint = with_fp;
803 if (!fpe)
805 Message("Unable to load footprint %s\n", Footprint);
806 return 1;
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);
815 if (with_fp)
816 free (with_fp);
817 return i ? 0 : 1;
819 else
821 char *args;
823 args = Concat("'", EMPTY (entry->Template), "' '",
824 EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
825 i = LoadElementToBuffer (Buffer, args, False);
827 free (args);
828 if (with_fp)
829 free (with_fp);
830 return i ? 0 : 1;
833 #ifdef DEBUG
835 int j;
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);
850 else
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);
857 if (j == 10)
858 break;
862 #endif
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.
876 %end-doc */
879 LoadFootprint (int argc, char **argv, int x, int y)
881 char *name = ARG(0);
882 char *refdes = ARG(1);
883 char *value = ARG(2);
884 ElementTypePtr e;
886 if (!name)
887 AFAIL (loadfootprint);
889 if (LoadFootprintByName (PASTEBUFFER, name))
890 return 1;
892 if (PASTEBUFFER->Data->ElementN == 0)
894 Message("Footprint %s contains no elements", name);
895 return 1;
897 if (PASTEBUFFER->Data->ElementN > 1)
899 Message("Footprint %s contains multiple elements", name);
900 return 1;
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;
917 return 0;
920 /*---------------------------------------------------------------------------
922 * break buffer element into pieces
924 Boolean
925 SmashBufferElement (BufferTypePtr Buffer)
927 ElementTypePtr element;
928 Cardinal group;
929 LayerTypePtr clayer, slayer;
931 if (Buffer->Data->ElementN != 1)
933 Message (_("Error! Buffer doesn't contain a single element\n"));
934 return (False);
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 ());
945 if (line)
946 line->Number = MyStrdup (NAMEONPCB_NAME (element), "SmashBuffer");
948 END_LOOP;
949 ARC_LOOP (element);
951 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
952 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
953 arc->Delta, arc->Thickness, 0, NoFlags ());
955 END_LOOP;
956 PIN_LOOP (element);
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);
967 END_LOOP;
968 group =
969 GetLayerGroupNumberByNumber (max_layer +
970 (SWAP_IDENT ? SOLDER_LAYER :
971 COMPONENT_LAYER));
972 clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
973 group =
974 GetLayerGroupNumberByNumber (max_layer +
975 (SWAP_IDENT ? COMPONENT_LAYER :
976 SOLDER_LAYER));
977 slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
978 PAD_LOOP (element);
980 LineTypePtr line;
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 ());
985 if (line)
986 line->Number = MyStrdup (pad->Number, "SmashBuffer");
988 END_LOOP;
989 FreeElementMemory (element);
990 SaveFree (element);
991 return (True);
994 /*---------------------------------------------------------------------------
996 * see if a polygon is a rectangle. If so, canonicalize it.
999 static int
1000 polygon_is_rectangle (PolygonTypePtr poly)
1002 int i, best;
1003 PointType temp[4];
1004 if (poly->PointN != 4)
1005 return 0;
1006 best = 0;
1007 for (i=1; i<4; i++)
1008 if (poly->Points[i].X < poly->Points[best].X
1009 || poly->Points[i].Y < poly->Points[best].Y)
1010 best = i;
1011 for (i=0; i<4; i++)
1012 temp[i] = poly->Points[(i+best)%4];
1013 if (temp[0].X == temp[1].X)
1014 memcpy (poly->Points, temp, sizeof(temp));
1015 else
1017 /* reverse them */
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)
1027 return 1;
1028 return 0;
1031 /*---------------------------------------------------------------------------
1033 * convert buffer contents into an element
1035 Boolean
1036 ConvertBufferToElement (BufferTypePtr Buffer)
1038 ElementTypePtr Element;
1039 Cardinal group;
1040 Cardinal pin_n = 1;
1041 Boolean 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),
1050 False);
1051 if (!Element)
1052 return (False);
1053 VIA_LOOP (Buffer->Data);
1055 char num[8];
1056 if (via->Mask < via->Thickness)
1057 via->Mask = via->Thickness + 2 * MASKFRAME * 100; /* MASKFRAME is in mils */
1058 if (via->Name)
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));
1064 else
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
1071 | WARNFLAG));
1073 hasParts = True;
1075 END_LOOP;
1076 /* get the component-side SM pads */
1077 group = GetLayerGroupNumberByNumber (max_layer +
1078 (SWAP_IDENT ? SOLDER_LAYER :
1079 COMPONENT_LAYER));
1080 GROUP_LOOP (Buffer->Data, group);
1082 char num[8];
1083 LINE_LOOP (layer);
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,
1089 line->Clearance,
1090 line->Thickness + line->Clearance, NULL,
1091 line->Number ? line->Number : num,
1092 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG));
1093 hasParts = True;
1095 END_LOOP;
1096 POLYGON_LOOP (layer);
1098 int x1, y1, x2, y2, w, h, t;
1100 if (! polygon_is_rectangle (polygon))
1102 crooked = True;
1103 continue;
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;
1111 x2 = x1 + (w-t);
1112 y2 = y1 + (h-t);
1114 sprintf (num, "%d", pin_n++);
1115 CreateNewPad (Element,
1116 x1, y1, x2, y2, t,
1117 2 * Settings.Keepaway,
1118 t + Settings.Keepaway,
1119 NULL, num,
1120 MakeFlags (SQUAREFLAG | (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG)));
1121 hasParts = True;
1123 END_LOOP;
1125 END_LOOP;
1126 /* now get the opposite side pads */
1127 group = GetLayerGroupNumberByNumber (max_layer +
1128 (SWAP_IDENT ? COMPONENT_LAYER :
1129 SOLDER_LAYER));
1130 GROUP_LOOP (Buffer->Data, group);
1132 Boolean warned = False;
1133 char num[8];
1134 LINE_LOOP (layer);
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,
1140 line->Clearance,
1141 line->Thickness + line->Clearance, NULL,
1142 line->Number ? line->Number : num,
1143 MakeFlags (SWAP_IDENT ? NOFLAG : ONSOLDERFLAG));
1144 if (!hasParts && !warned)
1146 warned = True;
1147 Message
1148 (_("Warning: All of the pads are on the opposite\n"
1149 "side from the component - that's probably not what\n"
1150 "you wanted\n"));
1152 hasParts = True;
1154 END_LOOP;
1156 END_LOOP;
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);
1166 hasParts = True;
1168 END_LOOP;
1169 ARC_LOOP (&Buffer->Data->SILKLAYER);
1171 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
1172 arc->Height, arc->StartAngle, arc->Delta,
1173 arc->Thickness);
1174 hasParts = True;
1176 END_LOOP;
1177 if (!hasParts)
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"));
1182 return (False);
1184 if (crooked)
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;
1189 if (SWAP_IDENT)
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,
1194 Element);
1195 SetBufferBoundingBox (Buffer);
1196 return (True);
1199 /* ---------------------------------------------------------------------------
1200 * load PCB into buffer
1201 * parse the file with enabled 'PCB mode' (see parser)
1202 * if successful, update some other stuff
1204 Boolean
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;
1219 RemovePCB (newPCB);
1220 Buffer->Data->pcb = PCB;
1221 return (True);
1224 /* release unused memory */
1225 RemovePCB (newPCB);
1226 Buffer->Data->pcb = PCB;
1227 return (False);
1230 /* ---------------------------------------------------------------------------
1231 * rotates the contents of the pastebuffer
1233 void
1234 RotateBuffer (BufferTypePtr Buffer, BYTE Number)
1236 /* rotate vias */
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);
1244 END_LOOP;
1246 /* elements */
1247 ELEMENT_LOOP (Buffer->Data);
1249 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1250 Number);
1252 END_LOOP;
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);
1261 ENDALL_LOOP;
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);
1268 ENDALL_LOOP;
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);
1275 ENDALL_LOOP;
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);
1282 ENDALL_LOOP;
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);
1289 static void
1290 free_rotate (int *x, int *y, int cx, int cy, double cosa, double sina)
1292 double nx, ny;
1293 int px = *x - cx;
1294 int py = *y - cy;
1296 nx = px * cosa + py * sina;
1297 ny = py * cosa - px * sina;
1299 *x = nx + cx;
1300 *y = ny + cy;
1303 void
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
1313 #if 0
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);
1320 END_LOOP;
1321 #endif
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);
1328 END_LOOP;
1329 PIN_LOOP (Element);
1331 /* pre-delete the pins from the pin-tree before their coordinates change */
1332 if (Data)
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);
1338 END_LOOP;
1339 PAD_LOOP (Element);
1341 /* pre-delete the pads before their coordinates change */
1342 if (Data)
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);
1349 END_LOOP;
1350 ARC_LOOP (Element);
1352 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1353 arc->StartAngle += Angle;
1354 arc->StartAngle %= 360;
1356 END_LOOP;
1358 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1359 SetElementBoundingBox (Data, Element, &PCB->Font);
1360 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1363 void
1364 FreeRotateBuffer (BufferTypePtr Buffer, double Angle)
1366 double cosa, sina;
1368 cosa = cos(Angle * M_PI/180.0);
1369 sina = sin(Angle * M_PI/180.0);
1371 /* rotate vias */
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);
1379 END_LOOP;
1381 /* elements */
1382 ELEMENT_LOOP (Buffer->Data);
1384 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1385 cosa, sina, Angle);
1387 END_LOOP;
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);
1398 ENDALL_LOOP;
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);
1407 ENDALL_LOOP;
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);
1416 END_LOOP;
1417 SetPolygonBoundingBox (polygon);
1418 r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
1420 ENDALL_LOOP;
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.
1438 %end-doc */
1441 ActionFreeRotateBuffer(int argc, char **argv, int x, int y)
1443 HideCrosshair(False);
1444 FreeRotateBuffer(PASTEBUFFER, strtod(argv[0], 0));
1445 RestoreCrosshair(False);
1446 return 0;
1449 /* ---------------------------------------------------------------------------
1450 * initializes the buffers by allocating memory
1452 void
1453 InitBuffers (void)
1455 int i;
1457 for (i = 0; i < MAX_BUFFER; i++)
1458 Buffers[i].Data = CreateNewBuffer ();
1461 void
1462 SwapBuffers (void)
1464 int i;
1466 for (i = 0; i < MAX_BUFFER; i++)
1467 SwapBuffer (&Buffers[i]);
1468 SetCrosshairRangeToBuffer ();
1471 void
1472 MirrorBuffer (BufferTypePtr Buffer)
1474 int i;
1476 if (Buffer->Data->ElementN)
1478 Message (_("You can't mirror a buffer that has elements!\n"));
1479 return;
1481 for (i = 0; i < max_layer + 2; i++)
1483 LayerTypePtr layer = Buffer->Data->Layer + i;
1484 if (layer->TextN)
1486 Message (_("You can't mirror a buffer that has text!\n"));
1487 return;
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);
1498 END_LOOP;
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);
1506 ENDALL_LOOP;
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);
1515 ENDALL_LOOP;
1516 ALLPOLYGON_LOOP (Buffer->Data);
1518 POLYGONPOINT_LOOP (polygon);
1520 point->X = SWAP_X (point->X);
1521 point->Y = SWAP_Y (point->Y);
1523 END_LOOP;
1524 SetPolygonBoundingBox (polygon);
1526 ENDALL_LOOP;
1527 SetBufferBoundingBox (Buffer);
1531 /* ---------------------------------------------------------------------------
1532 * flip components/tracks from one side to the other
1534 static void
1535 SwapBuffer (BufferTypePtr Buffer)
1537 int j, k;
1538 Cardinal sgroup, cgroup;
1539 LayerType swap;
1541 ELEMENT_LOOP (Buffer->Data);
1543 r_delete_element (Buffer->Data, element);
1544 MirrorElementCoordinates (Buffer->Data, element, 0);
1546 END_LOOP;
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);
1558 END_LOOP;
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);
1569 ENDALL_LOOP;
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);
1580 ENDALL_LOOP;
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);
1589 END_LOOP;
1590 SetPolygonBoundingBox (polygon);
1591 r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
1592 /* hmmm, how to handle clip */
1594 ENDALL_LOOP;
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);
1604 ENDALL_LOOP;
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++)
1618 int t1, t2;
1619 Cardinal cnumber = PCB->LayerGroups.Entries[cgroup][k];
1620 Cardinal snumber = PCB->LayerGroups.Entries[sgroup][j];
1622 if (snumber >= max_layer)
1623 continue;
1624 swap = Buffer->Data->Layer[snumber];
1626 while (cnumber >= max_layer)
1628 k++;
1629 cnumber = PCB->LayerGroups.Entries[cgroup][k];
1631 Buffer->Data->Layer[snumber] = Buffer->Data->Layer[cnumber];
1632 Buffer->Data->Layer[cnumber] = swap;
1633 k++;
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);
1642 ENDALL_LOOP;
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);
1650 END_LOOP;
1653 SetBufferBoundingBox (Buffer);
1656 /* ----------------------------------------------------------------------
1657 * moves the passed object to the passed buffer and removes it
1658 * from its original place
1660 void *
1661 MoveObjectToBuffer (DataTypePtr Destination, DataTypePtr Src,
1662 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1664 /* setup local identifiers used by move operations */
1665 Dest = Destination;
1666 Source = Src;
1667 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1670 /* ----------------------------------------------------------------------
1671 * Adds the passed object to the passed buffer
1673 void *
1674 CopyObjectToBuffer (DataTypePtr Destination, DataTypePtr Src,
1675 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1677 /* setup local identifiers used by Add operations */
1678 Dest = Destination;
1679 Source = Src;
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,
1689 0,0}
1692 REGISTER_ACTIONS (rotate_action_list)