pcb 4.1.1
An interactive printed circuit board layout editor.

buffer.c

Go to the documentation of this file.
00001 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include <stdlib.h>
00039 #include <memory.h>
00040 #include <math.h>
00041 
00042 #include "global.h"
00043 
00044 #include "buffer.h"
00045 #include "copy.h"
00046 #include "create.h"
00047 #include "crosshair.h"
00048 #include "data.h"
00049 #include "error.h"
00050 #include "mymem.h"
00051 #include "mirror.h"
00052 #include "misc.h"
00053 #include "parse_l.h"
00054 #include "polygon.h"
00055 #include "rats.h"
00056 #include "rotate.h"
00057 #include "remove.h"
00058 #include "rtree.h"
00059 #include "search.h"
00060 #include "select.h"
00061 #include "set.h"
00062 
00063 #ifdef HAVE_LIBDMALLOC
00064 #include <dmalloc.h>
00065 #endif
00066 
00067 /* ---------------------------------------------------------------------------
00068  * some local prototypes
00069  */
00070 static void *AddViaToBuffer (PinType *);
00071 static void *AddLineToBuffer (LayerType *, LineType *);
00072 static void *AddArcToBuffer (LayerType *, ArcType *);
00073 static void *AddRatToBuffer (RatType *);
00074 static void *AddTextToBuffer (LayerType *, TextType *);
00075 static void *AddPolygonToBuffer (LayerType *, PolygonType *);
00076 static void *AddElementToBuffer (ElementType *);
00077 static void *MoveViaToBuffer (PinType *);
00078 static void *MoveLineToBuffer (LayerType *, LineType *);
00079 static void *MoveArcToBuffer (LayerType *, ArcType *);
00080 static void *MoveRatToBuffer (RatType *);
00081 static void *MoveTextToBuffer (LayerType *, TextType *);
00082 static void *MovePolygonToBuffer (LayerType *, PolygonType *);
00083 static void *MoveElementToBuffer (ElementType *);
00084 static void SwapBuffer (BufferType *);
00085 
00086 #define ARG(n) (argc > (n) ? argv[n] : 0)
00087 
00088 /* ---------------------------------------------------------------------------
00089  * some local identifiers
00090  */
00091 static DataType *Dest, *Source;
00092 
00093 static ObjectFunctionType AddBufferFunctions = {
00094   AddLineToBuffer,
00095   AddTextToBuffer,
00096   AddPolygonToBuffer,
00097   AddViaToBuffer,
00098   AddElementToBuffer,
00099   NULL,
00100   NULL,
00101   NULL,
00102   NULL,
00103   NULL,
00104   AddArcToBuffer,
00105   AddRatToBuffer
00106 }, MoveBufferFunctions =
00107 
00108 {
00109 MoveLineToBuffer,
00110     MoveTextToBuffer,
00111     MovePolygonToBuffer,
00112     MoveViaToBuffer,
00113     MoveElementToBuffer,
00114     NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
00115 
00116 static int ExtraFlag = 0;
00117 
00121 static void *
00122 AddViaToBuffer (PinType *Via)
00123 {
00124   return (CreateNewViaEx (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance,
00125                         Via->Mask, Via->DrillingHole, Via->Name,
00126                         MaskFlags (Via->Flags, NOCOPY_FLAGS | ExtraFlag), Via->BuriedFrom, Via->BuriedTo));
00127 }
00128 
00132 static void *
00133 AddRatToBuffer (RatType *Rat)
00134 {
00135   return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y,
00136                         Rat->Point2.X, Rat->Point2.Y, Rat->group1,
00137                         Rat->group2, Rat->Thickness,
00138                         MaskFlags (Rat->Flags, NOCOPY_FLAGS | ExtraFlag)));
00139 }
00140 
00144 static void *
00145 AddLineToBuffer (LayerType *Layer, LineType *Line)
00146 {
00147   LineType *line;
00148   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
00149 
00150   line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y,
00151                                Line->Point2.X, Line->Point2.Y,
00152                                Line->Thickness, Line->Clearance,
00153                                MaskFlags (Line->Flags,
00154                                           NOCOPY_FLAGS | ExtraFlag));
00155   if (line && Line->Number)
00156     line->Number = strdup (Line->Number);
00157   return (line);
00158 }
00159 
00163 static void *
00164 AddArcToBuffer (LayerType *Layer, ArcType *Arc)
00165 {
00166   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
00167 
00168   return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y,
00169                                Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta,
00170                                Arc->Thickness, Arc->Clearance,
00171                                MaskFlags (Arc->Flags,
00172                                           NOCOPY_FLAGS | ExtraFlag)));
00173 }
00174 
00178 static void *
00179 AddTextToBuffer (LayerType *Layer, TextType *Text)
00180 {
00181   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
00182 
00183   return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y,
00184                          Text->Direction, Text->Scale, Text->TextString,
00185                          MaskFlags (Text->Flags, ExtraFlag)));
00186 }
00187 
00191 static void *
00192 AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon)
00193 {
00194   LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
00195   PolygonType *polygon;
00196 
00197   polygon = CreateNewPolygon (layer, Polygon->Flags);
00198   CopyPolygonLowLevel (polygon, Polygon);
00199 
00200   /* Update the polygon r-tree. Unlike similarly named functions for
00201    * other objects, CreateNewPolygon does not do this as it creates a
00202    * skeleton polygon object, which won't have correct bounds.
00203    */
00204   if (!layer->polygon_tree)
00205     layer->polygon_tree = r_create_tree (NULL, 0, 0);
00206   r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
00207 
00208   CLEAR_FLAG (NOCOPY_FLAGS | ExtraFlag, polygon);
00209   return (polygon);
00210 }
00211 
00215 static void *
00216 AddElementToBuffer (ElementType *Element)
00217 {
00218   return CopyElementLowLevel (Dest, Element, false, 0, 0, NOCOPY_FLAGS | ExtraFlag);
00219 }
00220 
00225 static void *
00226 MoveViaToBuffer (PinType *via)
00227 {
00228   RestoreToPolygon (Source, VIA_TYPE, via, via);
00229 
00230   r_delete_entry (Source->via_tree, (BoxType *) via);
00231   Source->Via = g_list_remove (Source->Via, via);
00232   Source->ViaN --;
00233   Dest->Via = g_list_append (Dest->Via, via);
00234   Dest->ViaN ++;
00235 
00236   CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, via);
00237 
00238   if (!Dest->via_tree)
00239     Dest->via_tree = r_create_tree (NULL, 0, 0);
00240   r_insert_entry (Dest->via_tree, (BoxType *)via, 0);
00241   ClearFromPolygon (Dest, VIA_TYPE, via, via);
00242   return via;
00243 }
00244 
00248 static void *
00249 MoveRatToBuffer (RatType *rat)
00250 {
00251   r_delete_entry (Source->rat_tree, (BoxType *)rat);
00252 
00253   Source->Rat = g_list_remove (Source->Rat, rat);
00254   Source->RatN --;
00255   Dest->Rat = g_list_append (Dest->Rat, rat);
00256   Dest->RatN ++;
00257 
00258   CLEAR_FLAG (NOCOPY_FLAGS, rat);
00259 
00260   if (!Dest->rat_tree)
00261     Dest->rat_tree = r_create_tree (NULL, 0, 0);
00262   r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0);
00263   return rat;
00264 }
00265 
00269 static void *
00270 MoveLineToBuffer (LayerType *layer, LineType *line)
00271 {
00272   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
00273 
00274   RestoreToPolygon (Source, LINE_TYPE, layer, line);
00275   r_delete_entry (layer->line_tree, (BoxType *)line);
00276 
00277   layer->Line = g_list_remove (layer->Line, line);
00278   layer->LineN --;
00279   lay->Line = g_list_append (lay->Line, line);
00280   lay->LineN ++;
00281 
00282   CLEAR_FLAG (NOCOPY_FLAGS, line);
00283 
00284   if (!lay->line_tree)
00285     lay->line_tree = r_create_tree (NULL, 0, 0);
00286   r_insert_entry (lay->line_tree, (BoxType *)line, 0);
00287   ClearFromPolygon (Dest, LINE_TYPE, lay, line);
00288   return (line);
00289 }
00290 
00294 static void *
00295 MoveArcToBuffer (LayerType *layer, ArcType *arc)
00296 {
00297   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
00298 
00299   RestoreToPolygon (Source, ARC_TYPE, layer, arc);
00300   r_delete_entry (layer->arc_tree, (BoxType *)arc);
00301 
00302   layer->Arc = g_list_remove (layer->Arc, arc);
00303   layer->ArcN --;
00304   lay->Arc = g_list_append (lay->Arc, arc);
00305   lay->ArcN ++;
00306 
00307   CLEAR_FLAG (NOCOPY_FLAGS, arc);
00308 
00309   if (!lay->arc_tree)
00310     lay->arc_tree = r_create_tree (NULL, 0, 0);
00311   r_insert_entry (lay->arc_tree, (BoxType *)arc, 0);
00312   ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
00313   return (arc);
00314 }
00315 
00319 static void *
00320 MoveTextToBuffer (LayerType *layer, TextType *text)
00321 {
00322   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
00323 
00324   r_delete_entry (layer->text_tree, (BoxType *)text);
00325   RestoreToPolygon (Source, TEXT_TYPE, layer, text);
00326 
00327   layer->Text = g_list_remove (layer->Text, text);
00328   layer->TextN --;
00329   lay->Text = g_list_append (lay->Text, text);
00330   lay->TextN ++;
00331 
00332   if (!lay->text_tree)
00333     lay->text_tree = r_create_tree (NULL, 0, 0);
00334   r_insert_entry (lay->text_tree, (BoxType *)text, 0);
00335   ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
00336   return (text);
00337 }
00338 
00344 static void *
00345 MovePolygonToBuffer (LayerType *layer, PolygonType *polygon)
00346 {
00347   LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)];
00348 
00349   r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
00350 
00351   layer->Polygon = g_list_remove (layer->Polygon, polygon);
00352   layer->PolygonN --;
00353   lay->Polygon = g_list_append (lay->Polygon, polygon);
00354   lay->PolygonN ++;
00355 
00356   CLEAR_FLAG (NOCOPY_FLAGS, polygon);
00357 
00358   if (!lay->polygon_tree)
00359     lay->polygon_tree = r_create_tree (NULL, 0, 0);
00360   r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0);
00361   return (polygon);
00362 }
00363 
00368 static void *
00369 MoveElementToBuffer (ElementType *element)
00370 {
00371   /*
00372    * Delete the element from the source (remove it from trees,
00373    * restore to polygons)
00374    */
00375   r_delete_element (Source, element);
00376 
00377   Source->Element = g_list_remove (Source->Element, element);
00378   Source->ElementN --;
00379   Dest->Element = g_list_append (Dest->Element, element);
00380   Dest->ElementN ++;
00381 
00382   PIN_LOOP (element);
00383   {
00384     RestoreToPolygon(Source, PIN_TYPE, element, pin);
00385     CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin);
00386   }
00387   END_LOOP;
00388   PAD_LOOP (element);
00389   {
00390     RestoreToPolygon(Source, PAD_TYPE, element, pad);
00391     CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad);
00392   }
00393   END_LOOP;
00394   SetElementBoundingBox (Dest, element, &PCB->Font);
00395   /*
00396    * Now clear the from the polygons in the destination
00397    */
00398   PIN_LOOP (element);
00399   {
00400     ClearFromPolygon (Dest, PIN_TYPE, element, pin);
00401   }
00402   END_LOOP;
00403   PAD_LOOP (element);
00404   {
00405     ClearFromPolygon (Dest, PAD_TYPE, element, pad);
00406   }
00407   END_LOOP;
00408 
00409   return element;
00410 }
00411 
00415 void
00416 SetBufferBoundingBox (BufferType *Buffer)
00417 {
00418   BoxType *box = GetDataBoundingBox (Buffer->Data);
00419 
00420   if (box)
00421     Buffer->BoundingBox = *box;
00422 }
00423 
00427 void
00428 ClearBuffer (BufferType *Buffer)
00429 {
00430   if (Buffer && Buffer->Data)
00431     {
00432       FreeDataMemory (Buffer->Data);
00433       Buffer->Data->pcb = PCB;
00434     }
00435 }
00436 
00442 void
00443 AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected)
00444 {
00445   /* switch crosshair off because adding objects to the pastebuffer
00446    * may change the 'valid' area for the cursor
00447    */
00448   if (!LeaveSelected)
00449     ExtraFlag = SELECTEDFLAG;
00450   notify_crosshair_change (false);
00451   Source = PCB->Data;
00452   Dest = Buffer->Data;
00453   SelectedOperation (&AddBufferFunctions, false, ALL_TYPES);
00454 
00455   /* set origin to passed or current position */
00456   if (X || Y)
00457     {
00458       Buffer->X = X;
00459       Buffer->Y = Y;
00460     }
00461   else
00462     {
00463       Buffer->X = Crosshair.X;
00464       Buffer->Y = Crosshair.Y;
00465     }
00466   notify_crosshair_change (true);
00467   ExtraFlag = 0;
00468 }
00469 
00478 bool
00479 LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile)
00480 {
00481   ElementType *element;
00482 
00483   ClearBuffer (Buffer);
00484   if (FromFile)
00485     {
00486       if (!ParseElementFile (Buffer->Data, Name))
00487         {
00488           if (Settings.ShowBottomSide)
00489             SwapBuffer (Buffer);
00490           SetBufferBoundingBox (Buffer);
00491           if (Buffer->Data->ElementN)
00492             {
00493               element = Buffer->Data->Element->data;
00494               Buffer->X = element->MarkX;
00495               Buffer->Y = element->MarkY;
00496             }
00497           else
00498             {
00499               Buffer->X = 0;
00500               Buffer->Y = 0;
00501             }
00502           return (true);
00503         }
00504     }
00505   else
00506     {
00507       if (!ParseLibraryEntry (Buffer->Data, Name)
00508           && Buffer->Data->ElementN != 0)
00509         {
00510           element = Buffer->Data->Element->data;
00511 
00512           /* always add elements using top-side coordinates */
00513           if (Settings.ShowBottomSide)
00514             MirrorElementCoordinates (Buffer->Data, element, 0);
00515           SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
00516 
00517           /* set buffer offset to 'mark' position */
00518           Buffer->X = element->MarkX;
00519           Buffer->Y = element->MarkY;
00520           SetBufferBoundingBox (Buffer);
00521           return (true);
00522         }
00523     }
00524   /* release memory which might have been acquired */
00525   ClearBuffer (Buffer);
00526   return (false);
00527 }
00528 
00529 
00530 typedef struct {
00531   char *footprint;
00532   int footprint_allocated;
00533   int menu_idx;
00534   int entry_idx;
00535 } FootprintHashEntry;
00536 
00537 static FootprintHashEntry *footprint_hash = 0;
00538 int footprint_hash_size = 0;
00539 
00540 void
00541 clear_footprint_hash ()
00542 {
00543   int i;
00544   if (!footprint_hash)
00545     return;
00546   for (i=0; i<footprint_hash_size; i++)
00547     if (footprint_hash[i].footprint_allocated)
00548       free (footprint_hash[i].footprint);
00549   free (footprint_hash);
00550   footprint_hash = NULL;
00551   footprint_hash_size = 0;
00552 }
00553 
00560 static int
00561 footprint_hash_cmp (const void *va, const void *vb)
00562 {
00563   int i;
00564   FootprintHashEntry *a = (FootprintHashEntry *)va;
00565   FootprintHashEntry *b = (FootprintHashEntry *)vb;
00566 
00567   i = strcmp (a->footprint, b->footprint);
00568   if (i == 0)
00569     i = a->menu_idx - b->menu_idx;
00570   if (i == 0)
00571     i = a->entry_idx - b->entry_idx;
00572   return i;
00573 }
00574 
00575 void
00576 make_footprint_hash ()
00577 {
00578   int i, j;
00579   char *fp;
00580   int num_entries = 0;
00581 
00582   clear_footprint_hash ();
00583 
00584   for (i=0; i<Library.MenuN; i++)
00585     for (j=0; j<Library.Menu[i].EntryN; j++)
00586       num_entries ++;
00587   footprint_hash = (FootprintHashEntry *)malloc (num_entries * sizeof(FootprintHashEntry));
00588   num_entries = 0;
00589 
00590   /* There are two types of library entries.  The file-based types
00591      have a Template of (char *)-1 and the AllocatedMemory is the full
00592      path to the footprint file.  The m4 ones have the footprint name
00593      in brackets in the description.  */
00594   for (i=0; i<Library.MenuN; i++)
00595     {
00596 #ifdef DEBUG
00597   printf("In make_footprint_hash, looking for footprints in %s\n", 
00598          Library.Menu[i].directory);
00599 #endif
00600 
00601     for (j=0; j<Library.Menu[i].EntryN; j++)
00602         {
00603           footprint_hash[num_entries].menu_idx = i;
00604           footprint_hash[num_entries].entry_idx = j;
00605           if (Library.Menu[i].Entry[j].Template == (char *) -1) 
00606           /* file */
00607             {
00608 #ifdef DEBUG
00609 /*            printf(" ... Examining file %s\n", Library.Menu[i].Entry[j].AllocatedMemory); */
00610 #endif
00611               fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '/');
00612 
00613               if (!fp)
00614                 fp = strrchr (Library.Menu[i].Entry[j].AllocatedMemory, '\\');
00615 
00616               if (fp)
00617                 fp ++;
00618               else 
00619                 fp = Library.Menu[i].Entry[j].AllocatedMemory;
00620 
00621 #ifdef DEBUG
00622 /*            printf(" ... found file footprint %s\n",  fp); */
00623 #endif
00624                 
00625               footprint_hash[num_entries].footprint = fp;
00626               footprint_hash[num_entries].footprint_allocated = 0;
00627             }
00628           else 
00629           /* m4 */
00630             {
00631               fp = strrchr (Library.Menu[i].Entry[j].Description, '[');
00632               if (fp)
00633                 {
00634                   footprint_hash[num_entries].footprint = strdup (fp+1);
00635                   footprint_hash[num_entries].footprint_allocated = 1;
00636                   fp = strchr (footprint_hash[num_entries].footprint, ']');
00637                   if (fp)
00638                     *fp = 0;
00639                 }
00640               else
00641                 {
00642                   fp = Library.Menu[i].Entry[j].Description;
00643                   footprint_hash[num_entries].footprint = fp;
00644                   footprint_hash[num_entries].footprint_allocated = 0;
00645                 }
00646             }
00647           num_entries ++;
00648         }
00649     }
00650 
00651   footprint_hash_size = num_entries;
00652   qsort (footprint_hash, num_entries, sizeof(footprint_hash[0]), footprint_hash_cmp);
00653 /*
00654 #ifdef DEBUG
00655   printf("       found footprints:  \n");
00656   for (i=0; i<num_entries; i++)
00657     printf("[%s]\n", footprint_hash[i].footprint);
00658 #endif
00659 */
00660 }
00661 
00677 FootprintHashEntry *
00678 search_footprint_hash (const char *footprint)
00679 {
00680   int i, min, max, c;
00681 
00682   /* Standard binary search */
00683 
00684   min = -1;
00685   max = footprint_hash_size;
00686 
00687   while (max - min > 1)
00688     {
00689       i = (min+max)/2;
00690       c = strcmp (footprint, footprint_hash[i].footprint);
00691       if (c < 0)
00692         max = i;
00693       else if (c > 0)
00694         min = i;
00695       else
00696         {
00697           /* We want to return the first match, not just any match.  */
00698           while (i > 0
00699                  && strcmp (footprint, footprint_hash[i-1].footprint) == 0)
00700             i--;
00701           return & footprint_hash[i];
00702         }
00703     }
00704   return NULL;
00705 }
00706 
00712 int
00713 LoadFootprintByName (BufferType *Buffer, char *Footprint)
00714 {
00715   int i;
00716   FootprintHashEntry *fpe;
00717   LibraryMenuType *menu;
00718   LibraryEntryType *entry;
00719   char *with_fp = NULL;
00720 
00721   if (!footprint_hash)
00722     make_footprint_hash ();
00723 
00724   fpe = search_footprint_hash (Footprint);
00725   if (!fpe)
00726     {
00727       with_fp = Concat (Footprint, ".fp", NULL);
00728       fpe = search_footprint_hash (with_fp);
00729       if (fpe)
00730         Footprint = with_fp;
00731     }
00732   if (!fpe)
00733     {
00734       Message(_("Unable to load footprint %s\n"), Footprint);
00735       return 1;
00736     }
00737 
00738   menu = & Library.Menu[fpe->menu_idx];
00739   entry = & menu->Entry[fpe->entry_idx];
00740 
00741   if (entry->Template == (char *) -1)
00742     {
00743       i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true);
00744       if (with_fp)
00745         free (with_fp);
00746       return i ? 0 : 1;
00747     }
00748   else
00749     {
00750       char *args;
00751 
00752       args = Concat("'", EMPTY (entry->Template), "' '",
00753                     EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL);
00754       i = LoadElementToBuffer (Buffer, args, false);
00755 
00756       free (args);
00757       if (with_fp)
00758         free (with_fp);
00759       return i ? 0 : 1;
00760     }
00761 
00762 #ifdef DEBUG
00763   {
00764     int j;
00765     printf("Library path: %s\n", Settings.LibraryPath);
00766     printf("Library tree: %s\n", Settings.LibraryTree);
00767 
00768     printf("Library:\n");
00769     for (i=0; i<Library.MenuN; i++)
00770       {
00771         printf("  [%02d] Name: %s\n", i, Library.Menu[i].Name);
00772         printf("       Dir:  %s\n", Library.Menu[i].directory);
00773         printf("       Sty:  %s\n", Library.Menu[i].Style);
00774         for (j=0; j<Library.Menu[i].EntryN; j++)
00775           {
00776             printf("       [%02d] E: %s\n", j, Library.Menu[i].Entry[j].ListEntry);
00777             if (Library.Menu[i].Entry[j].Template == (char *) -1)
00778               printf("            A: %s\n", Library.Menu[i].Entry[j].AllocatedMemory);
00779             else
00780               {
00781                 printf("            T: %s\n", Library.Menu[i].Entry[j].Template);
00782                 printf("            P: %s\n", Library.Menu[i].Entry[j].Package);
00783                 printf("            V: %s\n", Library.Menu[i].Entry[j].Value);
00784                 printf("            D: %s\n", Library.Menu[i].Entry[j].Description);
00785               }
00786             if (j == 10)
00787               break;
00788           }
00789       }
00790   }
00791 #endif
00792 }
00793 
00794 
00795 static const char loadfootprint_syntax[] =
00796   N_("LoadFootprint(filename[,refdes,value])");
00797 
00798 static const char loadfootprint_help[] =
00799   N_("Loads a single footprint by name.");
00800 
00801 /* %start-doc actions LoadFootprint
00802 
00803 Loads a single footprint by name, rather than by reference or through
00804 the library.  If a refdes and value are specified, those are inserted
00805 into the footprint as well.  The footprint remains in the paste buffer.
00806 
00807 %end-doc */
00808 
00812 int
00813 LoadFootprint (int argc, char **argv, Coord x, Coord y)
00814 {
00815   char *name = ARG(0);
00816   char *refdes = ARG(1);
00817   char *value = ARG(2);
00818   ElementType *e;
00819 
00820   if (!name)
00821     AFAIL (loadfootprint);
00822 
00823   if (LoadFootprintByName (PASTEBUFFER, name))
00824     return 1;
00825 
00826   if (PASTEBUFFER->Data->ElementN == 0)
00827     {
00828       Message(_("Footprint %s contains no elements"), name);
00829       return 1;
00830     }
00831   if (PASTEBUFFER->Data->ElementN > 1)
00832     {
00833       Message(_("Footprint %s contains multiple elements"), name);
00834       return 1;
00835     }
00836 
00837   e = PASTEBUFFER->Data->Element->data;
00838 
00839   if (e->Name[0].TextString)
00840     free (e->Name[0].TextString);
00841   e->Name[0].TextString = strdup (name);
00842 
00843   if (e->Name[1].TextString)
00844     free (e->Name[1].TextString);
00845   e->Name[1].TextString = refdes ? strdup (refdes) : 0;
00846 
00847   if (e->Name[2].TextString)
00848     free (e->Name[2].TextString);
00849   e->Name[2].TextString = value ? strdup (value) : 0;
00850 
00851   return 0;
00852 }
00853 
00857 bool
00858 SmashBufferElement (BufferType *Buffer)
00859 {
00860   ElementType *element;
00861   Cardinal group;
00862   LayerType *top_layer, *bottom_layer;
00863 
00864   if (Buffer->Data->ElementN != 1)
00865     {
00866       Message (_("Error!  Buffer doesn't contain a single element\n"));
00867       return (false);
00868     }
00869   /*
00870    * At this point the buffer should contain just a single element.
00871    * Now we detach the single element from the buffer and then clear the
00872    * buffer, ready to receive the smashed elements.  As a result of detaching
00873    * it the single element is orphaned from the buffer and thus will not be
00874    * free()'d by FreeDataMemory (called via ClearBuffer).  This leaves it
00875    * around for us to smash bits off it.  It then becomes our responsibility,
00876    * however, to free the single element when we're finished with it.
00877    */
00878   element = Buffer->Data->Element->data;
00879   Buffer->Data->Element = NULL;
00880   Buffer->Data->ElementN = 0;
00881   ClearBuffer (Buffer);
00882   ELEMENTLINE_LOOP (element);
00883   {
00884     CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
00885                           line->Point1.X, line->Point1.Y,
00886                           line->Point2.X, line->Point2.Y,
00887                           line->Thickness, 0, NoFlags ());
00888     if (line)
00889       line->Number = STRDUP (NAMEONPCB_NAME (element));
00890   }
00891   END_LOOP;
00892   ARC_LOOP (element);
00893   {
00894     CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
00895                          arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
00896                          arc->Delta, arc->Thickness, 0, NoFlags ());
00897   }
00898   END_LOOP;
00899   PIN_LOOP (element);
00900   {
00901     FlagType f = NoFlags ();
00902     AddFlags (f, VIAFLAG);
00903     if (TEST_FLAG (HOLEFLAG, pin))
00904       AddFlags (f, HOLEFLAG);
00905 
00906     CreateNewVia (Buffer->Data, pin->X, pin->Y,
00907                   pin->Thickness, pin->Clearance, pin->Mask,
00908                   pin->DrillingHole, pin->Number, f);
00909   }
00910   END_LOOP;
00911   group = GetLayerGroupNumberBySide (SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE);
00912   top_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
00913   group = GetLayerGroupNumberBySide (SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE);
00914   bottom_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
00915   PAD_LOOP (element);
00916   {
00917     LineType *line;
00918     line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_layer : top_layer,
00919                                  pad->Point1.X, pad->Point1.Y,
00920                                  pad->Point2.X, pad->Point2.Y,
00921                                  pad->Thickness, pad->Clearance, NoFlags ());
00922     if (line)
00923       line->Number = STRDUP (pad->Number);
00924   }
00925   END_LOOP;
00926   FreeElementMemory (element);
00927   g_slice_free (ElementType, element);
00928   return (true);
00929 }
00930 
00937 static int
00938 polygon_is_rectangle (PolygonType *poly)
00939 {
00940   int i, best;
00941   PointType temp[4];
00942   if (poly->PointN != 4 || poly->HoleIndexN != 0)
00943     return 0;
00944   best = 0;
00945   for (i=1; i<4; i++)
00946     if (poly->Points[i].X < poly->Points[best].X
00947         || poly->Points[i].Y < poly->Points[best].Y)
00948       best = i;
00949   for (i=0; i<4; i++)
00950     temp[i] = poly->Points[(i+best)%4];
00951   if (temp[0].X == temp[1].X)
00952     memcpy (poly->Points, temp, sizeof(temp));
00953   else
00954     {
00955       /* reverse them */
00956       poly->Points[0] = temp[0];
00957       poly->Points[1] = temp[3];
00958       poly->Points[2] = temp[2];
00959       poly->Points[3] = temp[1];
00960     }
00961   if (poly->Points[0].X == poly->Points[1].X
00962       && poly->Points[1].Y == poly->Points[2].Y
00963       && poly->Points[2].X == poly->Points[3].X
00964       && poly->Points[3].Y == poly->Points[0].Y)
00965     return 1;
00966   return 0;
00967 }
00968 
00972 bool
00973 ConvertBufferToElement (BufferType *Buffer)
00974 {
00975   ElementType *Element;
00976   Cardinal group;
00977   Cardinal pin_n = 1;
00978   bool hasParts = false, crooked = false;
00979   int onsolder;
00980   bool warned = false;
00981 
00982   if (Buffer->Data->pcb == 0)
00983     Buffer->Data->pcb = PCB;
00984 
00985   Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (),
00986                               NULL, NULL, NULL, PASTEBUFFER->X,
00987                               PASTEBUFFER->Y, 0, 100,
00988                               MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
00989                               false);
00990   if (!Element)
00991     return (false);
00992   VIA_LOOP (Buffer->Data);
00993   {
00994     char num[8];
00995     if (via->Mask < via->Thickness)
00996       via->Mask = via->Thickness + 2 * MASKFRAME;
00997     if (via->Name)
00998       CreateNewPin (Element, via->X, via->Y, via->Thickness,
00999                     via->Clearance, via->Mask, via->DrillingHole,
01000                     NULL, via->Name, MaskFlags (via->Flags,
01001                                                 VIAFLAG | NOCOPY_FLAGS |
01002                                                 SELECTEDFLAG | WARNFLAG));
01003     else
01004       {
01005         sprintf (num, "%d", pin_n++);
01006         CreateNewPin (Element, via->X, via->Y, via->Thickness,
01007                       via->Clearance, via->Mask, via->DrillingHole,
01008                       NULL, num, MaskFlags (via->Flags,
01009                                             VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG
01010                                             | WARNFLAG));
01011       }
01012     hasParts = true;
01013   }
01014   END_LOOP;
01015 
01016   for (onsolder = 0; onsolder < 2; onsolder ++)
01017     {
01018       int side;
01019       int onsolderflag;
01020 
01021       if ((!onsolder) == (!SWAP_IDENT))
01022         {
01023           side = TOP_SIDE;
01024           onsolderflag = NOFLAG;
01025         }
01026       else
01027         {
01028           side = BOTTOM_SIDE;
01029           onsolderflag = ONSOLDERFLAG;
01030         }
01031 
01032 #define MAYBE_WARN() \
01033           if (onsolder && !hasParts && !warned) \
01034             { \
01035               warned = true; \
01036               Message \
01037                 (_("Warning: All of the pads are on the opposite\n" \
01038                    "side from the component - that's probably not what\n" \
01039                    "you wanted\n")); \
01040             } \
01041 
01042       /* get the component-side SM pads */
01043       group = GetLayerGroupNumberBySide (side);
01044       GROUP_LOOP (Buffer->Data, group);
01045       {
01046         char num[8];
01047         LINE_LOOP (layer);
01048         {
01049           sprintf (num, "%d", pin_n++);
01050           CreateNewPad (Element, line->Point1.X,
01051                         line->Point1.Y, line->Point2.X,
01052                         line->Point2.Y, line->Thickness,
01053                         line->Clearance,
01054                         line->Thickness + line->Clearance, NULL,
01055                         line->Number ? line->Number : num,
01056                         MakeFlags (onsolderflag));
01057           MAYBE_WARN();
01058           hasParts = true;
01059         }
01060         END_LOOP;
01061         POLYGON_LOOP (layer);
01062         {
01063           Coord x1, y1, x2, y2, w, h, t;
01064 
01065           if (! polygon_is_rectangle (polygon))
01066             {
01067               crooked = true;
01068               continue;
01069             }
01070 
01071           w = polygon->Points[2].X - polygon->Points[0].X;
01072           h = polygon->Points[1].Y - polygon->Points[0].Y;
01073           t = (w < h) ? w : h;
01074           x1 = polygon->Points[0].X + t/2;
01075           y1 = polygon->Points[0].Y + t/2;
01076           x2 = x1 + (w-t);
01077           y2 = y1 + (h-t);
01078 
01079           sprintf (num, "%d", pin_n++);
01080           CreateNewPad (Element,
01081                         x1, y1, x2, y2, t,
01082                         2 * Settings.Keepaway,
01083                         t + Settings.Keepaway,
01084                         NULL, num,
01085                         MakeFlags (SQUAREFLAG | onsolderflag));
01086           MAYBE_WARN();
01087           hasParts = true;
01088         }
01089         END_LOOP;
01090       }
01091       END_LOOP;
01092     }
01093 
01094   /* now add the silkscreen. NOTE: elements must have pads or pins too */
01095   LINE_LOOP (&Buffer->Data->SILKLAYER);
01096   {
01097     if (line->Number && !NAMEONPCB_NAME (Element))
01098       NAMEONPCB_NAME (Element) = strdup (line->Number);
01099     CreateNewLineInElement (Element, line->Point1.X,
01100                             line->Point1.Y, line->Point2.X,
01101                             line->Point2.Y, line->Thickness);
01102     hasParts = true;
01103   }
01104   END_LOOP;
01105   ARC_LOOP (&Buffer->Data->SILKLAYER);
01106   {
01107     CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
01108                            arc->Height, arc->StartAngle, arc->Delta,
01109                            arc->Thickness);
01110     hasParts = true;
01111   }
01112   END_LOOP;
01113   if (!hasParts)
01114     {
01115       DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
01116       Message (_("There was nothing to convert!\n"
01117                  "Elements must have some silk, pads or pins.\n"));
01118       return (false);
01119     }
01120   if (crooked)
01121      Message (_("There were polygons that can't be made into pins!\n"
01122                 "So they were not included in the element\n"));
01123   Element->MarkX = Buffer->X;
01124   Element->MarkY = Buffer->Y;
01125   if (SWAP_IDENT)
01126     SET_FLAG (ONSOLDERFLAG, Element);
01127   SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
01128   ClearBuffer (Buffer);
01129   MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
01130                       Element);
01131   SetBufferBoundingBox (Buffer);
01132   return (true);
01133 }
01134 
01141 bool
01142 LoadLayoutToBuffer (BufferType *Buffer, char *Filename)
01143 {
01144   PCBType *newPCB = CreateNewPCB ();
01145 
01146   /* new data isn't added to the undo list */
01147   if (!ParsePCB (newPCB, Filename))
01148     {
01149       /* clear data area and replace pointer */
01150       ClearBuffer (Buffer);
01151       free (Buffer->Data);
01152       Buffer->Data = newPCB->Data;
01153       newPCB->Data = NULL;
01154       Buffer->X = newPCB->CursorX;
01155       Buffer->Y = newPCB->CursorY;
01156       RemovePCB (newPCB);
01157       Buffer->Data->pcb = PCB;
01158       return (true);
01159     }
01160 
01161   /* release unused memory */
01162   RemovePCB (newPCB);
01163       Buffer->Data->pcb = PCB;
01164   return (false);
01165 }
01166 
01170 void
01171 RotateBuffer (BufferType *Buffer, BYTE Number)
01172 {
01173   /* rotate vias */
01174   VIA_LOOP (Buffer->Data);
01175   {
01176     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
01177     ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
01178     SetPinBoundingBox (via);
01179     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
01180   }
01181   END_LOOP;
01182 
01183   /* elements */
01184   ELEMENT_LOOP (Buffer->Data);
01185   {
01186     RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
01187                            Number);
01188   }
01189   END_LOOP;
01190 
01191   /* all layer related objects */
01192   ALLLINE_LOOP (Buffer->Data);
01193   {
01194     r_delete_entry (layer->line_tree, (BoxType *)line);
01195     RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
01196     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
01197   }
01198   ENDALL_LOOP;
01199   ALLARC_LOOP (Buffer->Data);
01200   {
01201     r_delete_entry (layer->arc_tree, (BoxType *)arc);
01202     RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
01203     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
01204   }
01205   ENDALL_LOOP;
01206   ALLTEXT_LOOP (Buffer->Data);
01207   {
01208     r_delete_entry (layer->text_tree, (BoxType *)text);
01209     RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
01210     r_insert_entry (layer->text_tree, (BoxType *)text, 0);
01211   }
01212   ENDALL_LOOP;
01213   ALLPOLYGON_LOOP (Buffer->Data);
01214   {
01215     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
01216     RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
01217     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
01218   }
01219   ENDALL_LOOP;
01220 
01221   /* finally the origin and the bounding box */
01222   ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
01223   RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
01224   crosshair_update_range();
01225 }
01226 
01227 static void
01228 free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina)
01229 {
01230   double nx, ny;
01231   Coord px = *x - cx;
01232   Coord py = *y - cy;
01233 
01234   nx = px * cosa + py * sina;
01235   ny = py * cosa - px * sina;
01236 
01237   *x = nx + cx;
01238   *y = ny + cy;
01239 }
01240 
01241 void
01242 FreeRotateElementLowLevel (DataType *Data, ElementType *Element,
01243                            Coord X, Coord Y,
01244                            double cosa, double sina, Angle angle)
01245 {
01246   /* solder side objects need a different orientation */
01247 
01248   /* the text subroutine decides by itself if the direction
01249    * is to be corrected
01250    */
01251 #if 0
01252   ELEMENTTEXT_LOOP (Element);
01253   {
01254     if (Data && Data->name_tree[n])
01255       r_delete_entry (Data->name_tree[n], (BoxType *)text);
01256     RotateTextLowLevel (text, X, Y, Number);
01257   }
01258   END_LOOP;
01259 #endif
01260   ELEMENTLINE_LOOP (Element);
01261   {
01262     free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
01263     free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
01264     SetLineBoundingBox (line);
01265   }
01266   END_LOOP;
01267   PIN_LOOP (Element);
01268   {
01269     /* pre-delete the pins from the pin-tree before their coordinates change */
01270     if (Data)
01271       r_delete_entry (Data->pin_tree, (BoxType *)pin);
01272     RestoreToPolygon (Data, PIN_TYPE, Element, pin);
01273     free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
01274     SetPinBoundingBox (pin);
01275   }
01276   END_LOOP;
01277   PAD_LOOP (Element);
01278   {
01279     /* pre-delete the pads before their coordinates change */
01280     if (Data)
01281       r_delete_entry (Data->pad_tree, (BoxType *)pad);
01282     RestoreToPolygon (Data, PAD_TYPE, Element, pad);
01283     free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
01284     free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
01285     SetLineBoundingBox ((LineType *) pad);
01286   }
01287   END_LOOP;
01288   ARC_LOOP (Element);
01289   {
01290     free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
01291     arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
01292   }
01293   END_LOOP;
01294 
01295   free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
01296   SetElementBoundingBox (Data, Element, &PCB->Font);
01297   ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
01298 }
01299 
01300 void
01301 FreeRotateBuffer (BufferType *Buffer, Angle angle)
01302 {
01303   double cosa, sina;
01304 
01305   cosa = cos(angle * M_PI/180.0);
01306   sina = sin(angle * M_PI/180.0);
01307 
01308   /* rotate vias */
01309   VIA_LOOP (Buffer->Data);
01310   {
01311     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
01312     free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
01313     SetPinBoundingBox (via);
01314     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
01315   }
01316   END_LOOP;
01317 
01318   /* elements */
01319   ELEMENT_LOOP (Buffer->Data);
01320   {
01321     FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
01322                                cosa, sina, angle);
01323   }
01324   END_LOOP;
01325 
01326   /* all layer related objects */
01327   ALLLINE_LOOP (Buffer->Data);
01328   {
01329     r_delete_entry (layer->line_tree, (BoxType *)line);
01330     free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
01331     free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
01332     SetLineBoundingBox (line);
01333     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
01334   }
01335   ENDALL_LOOP;
01336   ALLARC_LOOP (Buffer->Data);
01337   {
01338     r_delete_entry (layer->arc_tree, (BoxType *)arc);
01339     free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
01340     arc->StartAngle = NormalizeAngle (arc->StartAngle + angle);
01341     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
01342   }
01343   ENDALL_LOOP;
01344   /* FIXME: rotate text */
01345   ALLPOLYGON_LOOP (Buffer->Data);
01346   {
01347     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
01348     POLYGONPOINT_LOOP (polygon);
01349     {
01350       free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
01351     }
01352     END_LOOP;
01353     SetPolygonBoundingBox (polygon);
01354     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
01355   }
01356   ENDALL_LOOP;
01357 
01358   SetBufferBoundingBox (Buffer);
01359   crosshair_update_range();
01360 }
01361 
01362 
01363 /* -------------------------------------------------------------------------- */
01364 
01365 static const char freerotatebuffer_syntax[] =
01366   N_("FreeRotateBuffer([Angle])");
01367 
01368 static const char freerotatebuffer_help[] =
01369   N_("Rotates the current paste buffer contents by the specified angle.  The\n"
01370   "angle is given in degrees.  If no angle is given, the user is prompted\n"
01371   "for one.\n");
01372 
01373 /* %start-doc actions FreeRotateBuffer
01374    
01375 Rotates the contents of the pastebuffer by an arbitrary angle.  If no
01376 angle is given, the user is prompted for one.
01377 
01378 %end-doc */
01379 
01380 int
01381 ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y)
01382 {
01383   char *angle_s;
01384 
01385   if (argc < 1)
01386     angle_s = gui->prompt_for (_("Enter Rotation (degrees, CCW):"), "0");
01387   else
01388     angle_s = argv[0];
01389 
01390   notify_crosshair_change (false);
01391   FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0));
01392   notify_crosshair_change (true);
01393   return 0;
01394 }
01395 
01399 void
01400 InitBuffers (void)
01401 {
01402   int i;
01403 
01404   for (i = 0; i < MAX_BUFFER; i++)
01405     Buffers[i].Data = CreateNewBuffer ();
01406 }
01407 
01408 void
01409 UninitBuffers (void)
01410 {
01411   int i;
01412 
01413   for (i = 0; i < MAX_BUFFER; i++)
01414     {
01415       ClearBuffer (Buffers+i);
01416       free (Buffers[i].Data);
01417     }
01418 }
01419 
01420 void
01421 SwapBuffers (void)
01422 {
01423   int i;
01424 
01425   for (i = 0; i < MAX_BUFFER; i++)
01426     SwapBuffer (&Buffers[i]);
01427   crosshair_update_range();
01428 }
01429 
01430 void
01431 MirrorBuffer (BufferType *Buffer)
01432 {
01433   int i;
01434 
01435   if (Buffer->Data->ElementN)
01436     {
01437       Message (_("You can't mirror a buffer that has elements!\n"));
01438       return;
01439     }
01440   for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01441     {
01442       LayerType *layer = Buffer->Data->Layer + i;
01443       if (layer->TextN)
01444         {
01445           Message (_("You can't mirror a buffer that has text!\n"));
01446           return;
01447         }
01448     }
01449   /* set buffer offset to 'mark' position */
01450   Buffer->X = SWAP_X (Buffer->X);
01451   Buffer->Y = SWAP_Y (Buffer->Y);
01452   VIA_LOOP (Buffer->Data);
01453   {
01454     via->X = SWAP_X (via->X);
01455     via->Y = SWAP_Y (via->Y);
01456   }
01457   END_LOOP;
01458   ALLLINE_LOOP (Buffer->Data);
01459   {
01460     line->Point1.X = SWAP_X (line->Point1.X);
01461     line->Point1.Y = SWAP_Y (line->Point1.Y);
01462     line->Point2.X = SWAP_X (line->Point2.X);
01463     line->Point2.Y = SWAP_Y (line->Point2.Y);
01464   }
01465   ENDALL_LOOP;
01466   ALLARC_LOOP (Buffer->Data);
01467   {
01468     r_delete_entry(layer->arc_tree, (BoxType*)arc);
01469     arc->X = SWAP_X (arc->X);
01470     arc->Y = SWAP_Y (arc->Y);
01471     arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
01472     arc->Delta = SWAP_DELTA (arc->Delta);
01473     SetArcBoundingBox (arc);
01474     r_insert_entry(layer->arc_tree, (BoxType*)arc, 0);
01475   }
01476   ENDALL_LOOP;
01477   ALLPOLYGON_LOOP (Buffer->Data);
01478   {
01479     r_delete_entry(layer->polygon_tree, (BoxType*)polygon);
01480     POLYGONPOINT_LOOP (polygon);
01481     {
01482       point->X = SWAP_X (point->X);
01483       point->Y = SWAP_Y (point->Y);
01484     }
01485     END_LOOP;
01486     SetPolygonBoundingBox (polygon);
01487     r_insert_entry(layer->polygon_tree, (BoxType*)polygon, 0);
01488   }
01489   ENDALL_LOOP;
01490   SetBufferBoundingBox (Buffer);
01491   crosshair_update_range();
01492 }
01493 
01494 
01498 static void
01499 SwapBuffer (BufferType *Buffer)
01500 {
01501   int j, k;
01502   Cardinal top_group, bottom_group;
01503   LayerType swap;
01504 
01505   ELEMENT_LOOP (Buffer->Data);
01506   {
01507     r_delete_element (Buffer->Data, element);
01508     MirrorElementCoordinates (Buffer->Data, element, 0);
01509   }
01510   END_LOOP;
01511   /* set buffer offset to 'mark' position */
01512   Buffer->X = SWAP_X (Buffer->X);
01513   Buffer->Y = SWAP_Y (Buffer->Y);
01514   VIA_LOOP (Buffer->Data);
01515   {
01516     r_delete_entry (Buffer->Data->via_tree, (BoxType *)via);
01517     via->X = SWAP_X (via->X);
01518     via->Y = SWAP_Y (via->Y);
01519     SetPinBoundingBox (via);
01520     r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0);
01521   }
01522   END_LOOP;
01523   ALLLINE_LOOP (Buffer->Data);
01524   {
01525     r_delete_entry (layer->line_tree, (BoxType *)line);
01526     line->Point1.X = SWAP_X (line->Point1.X);
01527     line->Point1.Y = SWAP_Y (line->Point1.Y);
01528     line->Point2.X = SWAP_X (line->Point2.X);
01529     line->Point2.Y = SWAP_Y (line->Point2.Y);
01530     SetLineBoundingBox (line);
01531     r_insert_entry (layer->line_tree, (BoxType *)line, 0);
01532   }
01533   ENDALL_LOOP;
01534   ALLARC_LOOP (Buffer->Data);
01535   {
01536     r_delete_entry (layer->arc_tree, (BoxType *)arc);
01537     arc->X = SWAP_X (arc->X);
01538     arc->Y = SWAP_Y (arc->Y);
01539     arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
01540     arc->Delta = SWAP_DELTA (arc->Delta);
01541     SetArcBoundingBox (arc);
01542     r_insert_entry (layer->arc_tree, (BoxType *)arc, 0);
01543   }
01544   ENDALL_LOOP;
01545   ALLPOLYGON_LOOP (Buffer->Data);
01546   {
01547     r_delete_entry (layer->polygon_tree, (BoxType *)polygon);
01548     POLYGONPOINT_LOOP (polygon);
01549     {
01550       point->X = SWAP_X (point->X);
01551       point->Y = SWAP_Y (point->Y);
01552     }
01553     END_LOOP;
01554     SetPolygonBoundingBox (polygon);
01555     r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0);
01556     /* hmmm, how to handle clip */
01557   }
01558   ENDALL_LOOP;
01559   ALLTEXT_LOOP (Buffer->Data);
01560   {
01561     r_delete_entry (layer->text_tree, (BoxType *)text);
01562     text->X = SWAP_X (text->X);
01563     text->Y = SWAP_Y (text->Y);
01564     TOGGLE_FLAG (ONSOLDERFLAG, text);
01565     SetTextBoundingBox (&PCB->Font, text);
01566     r_insert_entry (layer->text_tree, (BoxType *)text, 0);
01567   }
01568   ENDALL_LOOP;
01569   /* swap silkscreen layers */
01570   swap = Buffer->Data->Layer[bottom_silk_layer];
01571   Buffer->Data->Layer[bottom_silk_layer] =
01572     Buffer->Data->Layer[top_silk_layer];
01573   Buffer->Data->Layer[top_silk_layer] = swap;
01574 
01575   /* swap layer groups when balanced */
01576   top_group = GetLayerGroupNumberBySide (TOP_SIDE);
01577   bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
01578   if (PCB->LayerGroups.Number[top_group] == PCB->LayerGroups.Number[bottom_group])
01579     {
01580       for (j = k = 0; j < PCB->LayerGroups.Number[bottom_group]; j++)
01581         {
01582           int t1, t2;
01583           Cardinal top_number = PCB->LayerGroups.Entries[top_group][k];
01584           Cardinal bottom_number = PCB->LayerGroups.Entries[bottom_group][j];
01585 
01586           if (bottom_number >= max_copper_layer)
01587             continue;
01588           swap = Buffer->Data->Layer[bottom_number];
01589 
01590           while (top_number >= max_copper_layer)
01591             {
01592               k++;
01593               top_number = PCB->LayerGroups.Entries[top_group][k];
01594             }
01595           Buffer->Data->Layer[bottom_number] = Buffer->Data->Layer[top_number];
01596           Buffer->Data->Layer[top_number] = swap;
01597           k++;
01598           /* move the thermal flags with the layers */
01599           ALLPIN_LOOP (Buffer->Data);
01600           {
01601             t1 = TEST_THERM (bottom_number, pin);
01602             t2 = TEST_THERM (top_number, pin);
01603             ASSIGN_THERM (bottom_number, t2, pin);
01604             ASSIGN_THERM (top_number, t1, pin);
01605           }
01606           ENDALL_LOOP;
01607           VIA_LOOP (Buffer->Data);
01608           {
01609             t1 = TEST_THERM (bottom_number, via);
01610             t2 = TEST_THERM (top_number, via);
01611             ASSIGN_THERM (bottom_number, t2, via);
01612             ASSIGN_THERM (top_number, t1, via);
01613           }
01614           END_LOOP;
01615         }
01616     }
01617   SetBufferBoundingBox (Buffer);
01618   crosshair_update_range();
01619 }
01620 
01625 void *
01626 MoveObjectToBuffer (DataType *Destination, DataType *Src,
01627                     int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01628 {
01629   /* setup local identifiers used by move operations */
01630   Dest = Destination;
01631   Source = Src;
01632   return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
01633 }
01634 
01638 void *
01639 CopyObjectToBuffer (DataType *Destination, DataType *Src,
01640                     int Type, void *Ptr1, void *Ptr2, void *Ptr3)
01641 {
01642   /* setup local identifiers used by Add operations */
01643   Dest = Destination;
01644   Source = Src;
01645   return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
01646 }
01647 
01648 /* ---------------------------------------------------------------------- */
01649 
01650 HID_Action rotate_action_list[] = {
01651   {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
01652    freerotatebuffer_syntax, freerotatebuffer_help},
01653   {"LoadFootprint", 0, LoadFootprint,
01654    loadfootprint_syntax, loadfootprint_help}
01655 };
01656 
01657 REGISTER_ACTIONS (rotate_action_list)