pcb 4.1.1
An interactive printed circuit board layout editor.
|
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)