Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / buffer.c
blob8acbfce8f3f31b0f168a41269c96b0d126adfff2
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used by paste- and move/copy buffer
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
36 #include <stdlib.h>
37 #include <memory.h>
38 #include <math.h>
40 #include "global.h"
42 #include "buffer.h"
43 #include "copy.h"
44 #include "create.h"
45 #include "crosshair.h"
46 #include "data.h"
47 #include "error.h"
48 #include "mymem.h"
49 #include "mirror.h"
50 #include "misc.h"
51 #include "parse_l.h"
52 #include "polygon.h"
53 #include "rats.h"
54 #include "rotate.h"
55 #include "remove.h"
56 #include "rtree.h"
57 #include "search.h"
58 #include "select.h"
59 #include "set.h"
61 #ifdef HAVE_LIBDMALLOC
62 #include <dmalloc.h>
63 #endif
65 RCSID ("$Id$");
67 /* ---------------------------------------------------------------------------
68 * some local prototypes
70 static void *AddViaToBuffer (PinTypePtr);
71 static void *AddLineToBuffer (LayerTypePtr, LineTypePtr);
72 static void *AddArcToBuffer (LayerTypePtr, ArcTypePtr);
73 static void *AddRatToBuffer (RatTypePtr);
74 static void *AddTextToBuffer (LayerTypePtr, TextTypePtr);
75 static void *AddPolygonToBuffer (LayerTypePtr, PolygonTypePtr);
76 static void *AddElementToBuffer (ElementTypePtr);
77 static void *MoveViaToBuffer (PinTypePtr);
78 static void *MoveLineToBuffer (LayerTypePtr, LineTypePtr);
79 static void *MoveArcToBuffer (LayerTypePtr, ArcTypePtr);
80 static void *MoveRatToBuffer (RatTypePtr);
81 static void *MoveTextToBuffer (LayerTypePtr, TextTypePtr);
82 static void *MovePolygonToBuffer (LayerTypePtr, PolygonTypePtr);
83 static void *MoveElementToBuffer (ElementTypePtr);
84 static void SwapBuffer (BufferTypePtr);
86 /* ---------------------------------------------------------------------------
87 * some local identifiers
89 static DataTypePtr Dest, Source;
91 static ObjectFunctionType AddBufferFunctions = {
92 AddLineToBuffer,
93 AddTextToBuffer,
94 AddPolygonToBuffer,
95 AddViaToBuffer,
96 AddElementToBuffer,
97 NULL,
98 NULL,
99 NULL,
100 NULL,
101 NULL,
102 AddArcToBuffer,
103 AddRatToBuffer
104 }, MoveBufferFunctions =
107 MoveLineToBuffer,
108 MoveTextToBuffer,
109 MovePolygonToBuffer,
110 MoveViaToBuffer,
111 MoveElementToBuffer,
112 NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer};
114 static int ExtraFlag = 0;
116 /* ---------------------------------------------------------------------------
117 * copies a via to paste buffer
119 static void *
120 AddViaToBuffer (PinTypePtr Via)
122 return (CreateNewVia (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance,
123 Via->Mask, Via->DrillingHole, Via->Name,
124 MaskFlags (Via->Flags, FOUNDFLAG | ExtraFlag)));
127 /* ---------------------------------------------------------------------------
128 * copies a rat-line to paste buffer
130 static void *
131 AddRatToBuffer (RatTypePtr Rat)
133 return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y,
134 Rat->Point2.X, Rat->Point2.Y, Rat->group1,
135 Rat->group2, Rat->Thickness,
136 MaskFlags (Rat->Flags, FOUNDFLAG | ExtraFlag)));
139 /* ---------------------------------------------------------------------------
140 * copies a line to buffer
142 static void *
143 AddLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
145 LineTypePtr line;
146 LayerTypePtr layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
148 line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y,
149 Line->Point2.X, Line->Point2.Y,
150 Line->Thickness, Line->Clearance,
151 MaskFlags (Line->Flags,
152 FOUNDFLAG | ExtraFlag));
153 if (line && Line->Number)
154 line->Number = MyStrdup (Line->Number, "AddLineToBuffer");
155 return (line);
158 /* ---------------------------------------------------------------------------
159 * copies an arc to buffer
161 static void *
162 AddArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
164 LayerTypePtr layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
166 return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y,
167 Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta,
168 Arc->Thickness, Arc->Clearance,
169 MaskFlags (Arc->Flags,
170 FOUNDFLAG | ExtraFlag)));
173 /* ---------------------------------------------------------------------------
174 * copies a text to buffer
176 static void *
177 AddTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
179 LayerTypePtr layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
181 return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y,
182 Text->Direction, Text->Scale, Text->TextString,
183 MaskFlags (Text->Flags, ExtraFlag)));
186 /* ---------------------------------------------------------------------------
187 * copies a polygon to buffer
189 static void *
190 AddPolygonToBuffer (LayerTypePtr Layer, PolygonTypePtr Polygon)
192 LayerTypePtr layer = &Dest->Layer[GetLayerNumber (Source, Layer)];
193 PolygonTypePtr polygon;
195 polygon = GetPolygonMemory (layer);
196 CopyPolygonLowLevel (polygon, Polygon);
197 CLEAR_FLAG (FOUNDFLAG | ExtraFlag, polygon);
198 return (polygon);
201 /* ---------------------------------------------------------------------------
202 * copies a element to buffer
204 static void *
205 AddElementToBuffer (ElementTypePtr Element)
207 ElementTypePtr element;
209 element = GetElementMemory (Dest);
210 CopyElementLowLevel (Dest, element, Element, False, 0, 0);
211 CLEAR_FLAG (ExtraFlag, element);
212 if (ExtraFlag)
214 ELEMENTTEXT_LOOP (element);
216 CLEAR_FLAG (ExtraFlag, text);
218 END_LOOP;
219 PIN_LOOP (element);
221 CLEAR_FLAG (ExtraFlag, pin);
223 END_LOOP;
224 PAD_LOOP (element);
226 CLEAR_FLAG (ExtraFlag, pad);
228 END_LOOP;
230 return (element);
233 /* ---------------------------------------------------------------------------
234 * moves a via to paste buffer without allocating memory for the name
236 static void *
237 MoveViaToBuffer (PinTypePtr Via)
239 PinTypePtr via;
241 RestoreToPolygon (Source, VIA_TYPE, Via, Via);
242 r_delete_entry (Source->via_tree, (BoxType *) Via);
243 via = GetViaMemory (Dest);
244 *via = *Via;
245 *Via = Source->Via[--Source->ViaN];
246 r_substitute (Source->via_tree, (BoxType *) & Source->Via[Source->ViaN],
247 (BoxType *) Via);
248 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, via);
249 memset (&Source->Via[Source->ViaN], 0, sizeof (PinType));
250 if (!Dest->via_tree)
251 Dest->via_tree = r_create_tree (NULL, 0, 0);
252 r_insert_entry (Dest->via_tree, (BoxType *) via, 0);
253 ClearFromPolygon (Dest, VIA_TYPE, via, via);
254 return (via);
257 /* ---------------------------------------------------------------------------
258 * moves a rat-line to paste buffer
260 static void *
261 MoveRatToBuffer (RatTypePtr Rat)
263 RatTypePtr rat;
265 rat = GetRatMemory (Dest);
266 *rat = *Rat;
267 r_delete_entry (Source->rat_tree, &Rat->BoundingBox);
268 *Rat = Source->Rat[--Source->RatN];
269 r_substitute (Source->rat_tree, &Source->Rat[Source->RatN].BoundingBox,
270 &Rat->BoundingBox);
271 CLEAR_FLAG (FOUNDFLAG, Rat);
272 memset (&Source->Rat[Source->RatN], 0, sizeof (RatType));
273 if (!Dest->rat_tree)
274 Dest->rat_tree = r_create_tree (NULL, 0, 0);
275 r_insert_entry (Dest->rat_tree, &rat->BoundingBox, 0);
276 return (rat);
279 /* ---------------------------------------------------------------------------
280 * moves a line to buffer
282 static void *
283 MoveLineToBuffer (LayerTypePtr Layer, LineTypePtr Line)
285 LayerTypePtr lay;
286 LineTypePtr line;
288 RestoreToPolygon (Source, LINE_TYPE, Layer, Line);
289 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
290 lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
291 line = GetLineMemory (lay);
292 *line = *Line;
293 CLEAR_FLAG (FOUNDFLAG, line);
294 /* line pointers being shuffled */
295 *Line = Layer->Line[--Layer->LineN];
296 r_substitute (Layer->line_tree, (BoxTypePtr) & Layer->Line[Layer->LineN],
297 (BoxTypePtr) Line);
298 memset (&Layer->Line[Layer->LineN], 0, sizeof (LineType));
299 if (!lay->line_tree)
300 lay->line_tree = r_create_tree (NULL, 0, 0);
301 r_insert_entry (lay->line_tree, (BoxTypePtr) line, 0);
302 ClearFromPolygon (Dest, LINE_TYPE, lay, line);
303 return (line);
306 /* ---------------------------------------------------------------------------
307 * moves an arc to buffer
309 static void *
310 MoveArcToBuffer (LayerTypePtr Layer, ArcTypePtr Arc)
312 LayerTypePtr lay;
313 ArcTypePtr arc;
315 RestoreToPolygon (Source, ARC_TYPE, Layer, Arc);
316 r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
317 lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
318 arc = GetArcMemory (lay);
319 *arc = *Arc;
320 CLEAR_FLAG (FOUNDFLAG, arc);
321 /* arc pointers being shuffled */
322 *Arc = Layer->Arc[--Layer->ArcN];
323 r_substitute (Layer->arc_tree, (BoxTypePtr) & Layer->Arc[Layer->ArcN],
324 (BoxTypePtr) Arc);
325 memset (&Layer->Arc[Layer->ArcN], 0, sizeof (ArcType));
326 if (!lay->arc_tree)
327 lay->arc_tree = r_create_tree (NULL, 0, 0);
328 r_insert_entry (lay->arc_tree, (BoxTypePtr) arc, 0);
329 ClearFromPolygon (Dest, ARC_TYPE, lay, arc);
330 return (arc);
333 /* ---------------------------------------------------------------------------
334 * moves a text to buffer without allocating memory for the name
336 static void *
337 MoveTextToBuffer (LayerTypePtr Layer, TextTypePtr Text)
339 TextTypePtr text;
340 LayerTypePtr lay;
342 r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
343 RestoreToPolygon (Source, TEXT_TYPE, Layer, Text);
344 lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
345 text = GetTextMemory (lay);
346 *text = *Text;
347 *Text = Layer->Text[--Layer->TextN];
348 r_substitute (Layer->text_tree, (BoxTypePtr) & Layer->Text[Layer->TextN],
349 (BoxTypePtr) Text);
350 memset (&Layer->Text[Layer->TextN], 0, sizeof (TextType));
351 if (!lay->text_tree)
352 lay->text_tree = r_create_tree (NULL, 0, 0);
353 r_insert_entry (lay->text_tree, (BoxTypePtr) text, 0);
354 ClearFromPolygon (Dest, TEXT_TYPE, lay, text);
355 return (text);
358 /* ---------------------------------------------------------------------------
359 * moves a polygon to buffer. Doesn't allocate memory for the points
361 static void *
362 MovePolygonToBuffer (LayerTypePtr Layer, PolygonTypePtr Polygon)
364 LayerTypePtr lay;
365 PolygonTypePtr polygon;
367 r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
368 lay = &Dest->Layer[GetLayerNumber (Source, Layer)];
369 polygon = GetPolygonMemory (lay);
370 *polygon = *Polygon;
371 CLEAR_FLAG (FOUNDFLAG, polygon);
372 *Polygon = Layer->Polygon[--Layer->PolygonN];
373 r_substitute (Layer->polygon_tree,
374 (BoxTypePtr) & Layer->Polygon[Layer->PolygonN],
375 (BoxTypePtr) Polygon);
376 memset (&Layer->Polygon[Layer->PolygonN], 0, sizeof (PolygonType));
377 if (!lay->polygon_tree)
378 lay->polygon_tree = r_create_tree (NULL, 0, 0);
379 r_insert_entry (lay->polygon_tree, (BoxTypePtr) polygon, 0);
380 return (polygon);
383 /* ---------------------------------------------------------------------------
384 * moves a element to buffer without allocating memory for pins/names
386 static void *
387 MoveElementToBuffer (ElementTypePtr Element)
389 ElementTypePtr element;
390 int i;
393 * Two steps at once: Delete the element from the source (remove it
394 * from trees, restore to polygons) and simultaneously adjust its
395 * component pointers to the new storage in Dest
397 r_delete_element (Source, Element);
398 element = GetElementMemory (Dest);
399 *element = *Element;
400 PIN_LOOP (element);
402 RestoreToPolygon(Source, PIN_TYPE, Element, pin);
403 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pin);
404 pin->Element = element;
406 END_LOOP;
407 PAD_LOOP (element);
409 RestoreToPolygon(Source, PAD_TYPE, Element, pad);
410 CLEAR_FLAG (WARNFLAG | FOUNDFLAG, pad);
411 pad->Element = element;
413 END_LOOP;
414 ELEMENTTEXT_LOOP (element);
416 text->Element = element;
418 END_LOOP;
419 SetElementBoundingBox (Dest, element, &PCB->Font);
421 * Now clear the from the polygons in the destination
423 PIN_LOOP (element);
425 ClearFromPolygon (Dest, PIN_TYPE, element, pin);
427 END_LOOP;
428 PAD_LOOP (element);
430 ClearFromPolygon (Dest, PAD_TYPE, element, pad);
432 END_LOOP;
435 * Now compact the Source's Element array by moving the last element
436 * to the hole created by the removal above. Then make a pass adjusting
437 * *its* component pointers. Confusingly, this element (which is of no
438 * particular relation to this removal) becomes `Element' while the
439 * original Element is now in `element'.
441 *Element = Source->Element[--Source->ElementN];
442 memset (&Source->Element[Source->ElementN], 0, sizeof (ElementType));
443 r_substitute (Source->element_tree,
444 (BoxType *) & Source->Element[Source->ElementN],
445 (BoxType *) Element);
446 for (i = 0; i < MAX_ELEMENTNAMES; i++)
447 r_substitute (Source->name_tree[i],
448 (BoxType *) & Source->Element[Source->ElementN].Name[i],
449 (BoxType *) & Element->Name[i]);
450 ELEMENTTEXT_LOOP (Element);
452 text->Element = Element;
454 END_LOOP;
455 PIN_LOOP (Element);
457 pin->Element = Element;
459 END_LOOP;
460 PAD_LOOP (Element);
462 pad->Element = Element;
464 END_LOOP;
466 return (element);
469 /* ---------------------------------------------------------------------------
470 * calculates the bounding box of the buffer
472 void
473 SetBufferBoundingBox (BufferTypePtr Buffer)
475 BoxTypePtr box = GetDataBoundingBox (Buffer->Data);
477 if (box)
478 Buffer->BoundingBox = *box;
481 /* ---------------------------------------------------------------------------
482 * clears the contents of the paste buffer
484 void
485 ClearBuffer (BufferTypePtr Buffer)
487 if (Buffer && Buffer->Data)
489 FreeDataMemory (Buffer->Data);
490 Buffer->Data->pcb = PCB;
494 /* ----------------------------------------------------------------------
495 * copies all selected and visible objects to the paste buffer
496 * returns True if any objects have been removed
498 void
499 AddSelectedToBuffer (BufferTypePtr Buffer, LocationType X, LocationType Y,
500 Boolean LeaveSelected)
502 /* switch crosshair off because adding objects to the pastebuffer
503 * may change the 'valid' area for the cursor
505 if (!LeaveSelected)
506 ExtraFlag = SELECTEDFLAG;
507 HideCrosshair (True);
508 Source = PCB->Data;
509 Dest = Buffer->Data;
510 SelectedOperation (&AddBufferFunctions, False, ALL_TYPES);
512 /* set origin to passed or current position */
513 if (X || Y)
515 Buffer->X = X;
516 Buffer->Y = Y;
518 else
520 Buffer->X = Crosshair.X;
521 Buffer->Y = Crosshair.Y;
523 RestoreCrosshair (True);
524 ExtraFlag = 0;
527 /* ---------------------------------------------------------------------------
528 * loads element data from file/library into buffer
529 * parse the file with disabled 'PCB mode' (see parser)
530 * returns False on error
531 * if successful, update some other stuff and reposition the pastebuffer
533 Boolean
534 LoadElementToBuffer (BufferTypePtr Buffer, char *Name, Boolean FromFile)
536 ElementTypePtr element;
538 ClearBuffer (Buffer);
539 if (FromFile)
541 if (!ParseElementFile (Buffer->Data, Name))
543 if (Settings.ShowSolderSide)
544 SwapBuffer (Buffer);
545 SetBufferBoundingBox (Buffer);
546 if (Buffer->Data->ElementN)
548 element = &(Buffer->Data->Element[0]);
549 Buffer->X = element->MarkX;
550 Buffer->Y = element->MarkY;
552 else
554 Buffer->X = 0;
555 Buffer->Y = 0;
557 return (True);
560 else
562 if (!ParseLibraryEntry (Buffer->Data, Name)
563 && Buffer->Data->ElementN != 0)
565 element = &(Buffer->Data->Element[0]);
567 /* always add elements using top-side coordinates */
568 if (Settings.ShowSolderSide)
569 MirrorElementCoordinates (Buffer->Data, element, 0);
570 SetElementBoundingBox (Buffer->Data, element, &PCB->Font);
572 /* set buffer offset to 'mark' position */
573 Buffer->X = element->MarkX;
574 Buffer->Y = element->MarkY;
575 SetBufferBoundingBox (Buffer);
576 return (True);
579 /* release memory which might have been acquired */
580 ClearBuffer (Buffer);
581 return (False);
585 /*---------------------------------------------------------------------------
587 * break buffer element into pieces
589 Boolean
590 SmashBufferElement (BufferTypePtr Buffer)
592 ElementTypePtr element;
593 Cardinal group;
594 LayerTypePtr clayer, slayer;
596 if (Buffer->Data->ElementN != 1)
598 Message (_("Error! Buffer doesn't contain a single element\n"));
599 return (False);
601 element = &Buffer->Data->Element[0];
602 Buffer->Data->ElementN = 0;
603 ClearBuffer (Buffer);
604 ELEMENTLINE_LOOP (element);
606 CreateNewLineOnLayer (&Buffer->Data->SILKLAYER,
607 line->Point1.X, line->Point1.Y,
608 line->Point2.X, line->Point2.Y,
609 line->Thickness, 0, NoFlags ());
610 if (line)
611 line->Number = MyStrdup (NAMEONPCB_NAME (element), "SmashBuffer");
613 END_LOOP;
614 ARC_LOOP (element);
616 CreateNewArcOnLayer (&Buffer->Data->SILKLAYER,
617 arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle,
618 arc->Delta, arc->Thickness, 0, NoFlags ());
620 END_LOOP;
621 PIN_LOOP (element);
623 FlagType f = NoFlags ();
624 AddFlags (f, VIAFLAG);
625 if (TEST_FLAG (HOLEFLAG, pin))
626 AddFlags (f, HOLEFLAG);
628 CreateNewVia (Buffer->Data, pin->X, pin->Y,
629 pin->Thickness, pin->Clearance, pin->Mask,
630 pin->DrillingHole, pin->Number, f);
632 END_LOOP;
633 group =
634 GetLayerGroupNumberByNumber (max_layer +
635 (SWAP_IDENT ? SOLDER_LAYER :
636 COMPONENT_LAYER));
637 clayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
638 group =
639 GetLayerGroupNumberByNumber (max_layer +
640 (SWAP_IDENT ? COMPONENT_LAYER :
641 SOLDER_LAYER));
642 slayer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]];
643 PAD_LOOP (element);
645 LineTypePtr line;
646 line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? slayer : clayer,
647 pad->Point1.X, pad->Point1.Y,
648 pad->Point2.X, pad->Point2.Y,
649 pad->Thickness, pad->Clearance, NoFlags ());
650 if (line)
651 line->Number = MyStrdup (pad->Number, "SmashBuffer");
653 END_LOOP;
654 FreeElementMemory (element);
655 SaveFree (element);
656 return (True);
659 /*---------------------------------------------------------------------------
661 * see if a polygon is a rectangle. If so, canonicalize it.
664 static int
665 polygon_is_rectangle (PolygonTypePtr poly)
667 int i, best;
668 PointType temp[4];
669 if (poly->PointN != 4)
670 return 0;
671 best = 0;
672 for (i=1; i<4; i++)
673 if (poly->Points[i].X < poly->Points[best].X
674 || poly->Points[i].Y < poly->Points[best].Y)
675 best = i;
676 for (i=0; i<4; i++)
677 temp[i] = poly->Points[(i+best)%4];
678 if (temp[0].X == temp[1].X)
679 memcpy (poly->Points, temp, sizeof(temp));
680 else
682 /* reverse them */
683 poly->Points[0] = temp[0];
684 poly->Points[1] = temp[3];
685 poly->Points[2] = temp[2];
686 poly->Points[3] = temp[1];
688 if (poly->Points[0].X == poly->Points[1].X
689 && poly->Points[1].Y == poly->Points[2].Y
690 && poly->Points[2].X == poly->Points[3].X
691 && poly->Points[3].Y == poly->Points[0].Y)
692 return 1;
693 return 0;
696 /*---------------------------------------------------------------------------
698 * convert buffer contents into an element
700 Boolean
701 ConvertBufferToElement (BufferTypePtr Buffer)
703 ElementTypePtr Element;
704 Cardinal group;
705 Cardinal pin_n = 1;
706 Boolean hasParts = False, crooked = False;
708 if (Buffer->Data->pcb == 0)
709 Buffer->Data->pcb = PCB;
711 Element = CreateNewElement (PCB->Data, NULL, &PCB->Font, NoFlags (),
712 NULL, NULL, NULL, PASTEBUFFER->X,
713 PASTEBUFFER->Y, 0, 100,
714 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG),
715 False);
716 if (!Element)
717 return (False);
718 VIA_LOOP (Buffer->Data);
720 char num[8];
721 if (via->Mask < via->Thickness)
722 via->Mask = via->Thickness + 2 * MASKFRAME * 100; /* MASKFRAME is in mils */
723 if (via->Name)
724 CreateNewPin (Element, via->X, via->Y, via->Thickness,
725 via->Clearance, via->Mask, via->DrillingHole,
726 NULL, via->Name, MaskFlags (via->Flags,
727 VIAFLAG | FOUNDFLAG |
728 SELECTEDFLAG | WARNFLAG));
729 else
731 sprintf (num, "%d", pin_n++);
732 CreateNewPin (Element, via->X, via->Y, via->Thickness,
733 via->Clearance, via->Mask, via->DrillingHole,
734 NULL, num, MaskFlags (via->Flags,
735 VIAFLAG | FOUNDFLAG | SELECTEDFLAG
736 | WARNFLAG));
738 hasParts = True;
740 END_LOOP;
741 /* get the component-side SM pads */
742 group = GetLayerGroupNumberByNumber (max_layer +
743 (SWAP_IDENT ? SOLDER_LAYER :
744 COMPONENT_LAYER));
745 GROUP_LOOP (Buffer->Data, group);
747 char num[8];
748 LINE_LOOP (layer);
750 sprintf (num, "%d", pin_n++);
751 CreateNewPad (Element, line->Point1.X,
752 line->Point1.Y, line->Point2.X,
753 line->Point2.Y, line->Thickness,
754 line->Clearance,
755 line->Thickness + line->Clearance, NULL,
756 line->Number ? line->Number : num,
757 MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG));
758 hasParts = True;
760 END_LOOP;
761 POLYGON_LOOP (layer);
763 int x1, y1, x2, y2, w, h, t;
765 if (! polygon_is_rectangle (polygon))
767 crooked = True;
768 continue;
771 w = polygon->Points[2].X - polygon->Points[0].X;
772 h = polygon->Points[1].Y - polygon->Points[0].Y;
773 t = (w < h) ? w : h;
774 x1 = polygon->Points[0].X + t/2;
775 y1 = polygon->Points[0].Y + t/2;
776 x2 = x1 + (w-t);
777 y2 = y1 + (h-t);
779 sprintf (num, "%d", pin_n++);
780 CreateNewPad (Element,
781 x1, y1, x2, y2, t,
782 2 * Settings.Keepaway,
783 t + Settings.Keepaway,
784 NULL, num,
785 MakeFlags (SQUAREFLAG | (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG)));
786 hasParts = True;
788 END_LOOP;
790 END_LOOP;
791 /* now get the opposite side pads */
792 group = GetLayerGroupNumberByNumber (max_layer +
793 (SWAP_IDENT ? COMPONENT_LAYER :
794 SOLDER_LAYER));
795 GROUP_LOOP (Buffer->Data, group);
797 Boolean warned = False;
798 char num[8];
799 LINE_LOOP (layer);
801 sprintf (num, "%d", pin_n++);
802 CreateNewPad (Element, line->Point1.X,
803 line->Point1.Y, line->Point2.X,
804 line->Point2.Y, line->Thickness,
805 line->Clearance,
806 line->Thickness + line->Clearance, NULL,
807 line->Number ? line->Number : num,
808 MakeFlags (SWAP_IDENT ? NOFLAG : ONSOLDERFLAG));
809 if (!hasParts && !warned)
811 warned = True;
812 Message
813 (_("Warning: All of the pads are on the opposite\n"
814 "side from the component - that's probably not what\n"
815 "you wanted\n"));
817 hasParts = True;
819 END_LOOP;
821 END_LOOP;
822 /* now add the silkscreen. NOTE: elements must have pads or pins too */
823 LINE_LOOP (&Buffer->Data->SILKLAYER);
825 if (line->Number && !NAMEONPCB_NAME (Element))
826 NAMEONPCB_NAME (Element) = MyStrdup (line->Number,
827 "ConvertBufferToElement");
828 CreateNewLineInElement (Element, line->Point1.X,
829 line->Point1.Y, line->Point2.X,
830 line->Point2.Y, line->Thickness);
831 hasParts = True;
833 END_LOOP;
834 ARC_LOOP (&Buffer->Data->SILKLAYER);
836 CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width,
837 arc->Height, arc->StartAngle, arc->Delta,
838 arc->Thickness);
839 hasParts = True;
841 END_LOOP;
842 if (!hasParts)
844 DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element);
845 Message (_("There was nothing to convert!\n"
846 "Elements must have some silk, pads or pins.\n"));
847 return (False);
849 if (crooked)
850 Message (_("There were polygons that can't be made into pins!\n"
851 "So they were not included in the element\n"));
852 Element->MarkX = Buffer->X;
853 Element->MarkY = Buffer->Y;
854 if (SWAP_IDENT)
855 SET_FLAG (ONSOLDERFLAG, Element);
856 SetElementBoundingBox (PCB->Data, Element, &PCB->Font);
857 ClearBuffer (Buffer);
858 MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element,
859 Element);
860 SetBufferBoundingBox (Buffer);
861 return (True);
864 /* ---------------------------------------------------------------------------
865 * load PCB into buffer
866 * parse the file with enabled 'PCB mode' (see parser)
867 * if successful, update some other stuff
869 Boolean
870 LoadLayoutToBuffer (BufferTypePtr Buffer, char *Filename)
872 PCBTypePtr newPCB = CreateNewPCB (False);
874 /* new data isn't added to the undo list */
875 if (!ParsePCB (newPCB, Filename))
877 /* clear data area and replace pointer */
878 ClearBuffer (Buffer);
879 SaveFree (Buffer->Data);
880 Buffer->Data = newPCB->Data;
881 newPCB->Data = NULL;
882 Buffer->X = newPCB->CursorX;
883 Buffer->Y = newPCB->CursorY;
884 RemovePCB (newPCB);
885 Buffer->Data->pcb = PCB;
886 return (True);
889 /* release unused memory */
890 RemovePCB (newPCB);
891 Buffer->Data->pcb = PCB;
892 return (False);
895 /* ---------------------------------------------------------------------------
896 * rotates the contents of the pastebuffer
898 void
899 RotateBuffer (BufferTypePtr Buffer, BYTE Number)
901 /* rotate vias */
902 VIA_LOOP (Buffer->Data);
904 r_delete_entry (Buffer->Data->via_tree, (BoxTypePtr) via);
905 ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number);
906 SetPinBoundingBox (via);
907 r_insert_entry (Buffer->Data->via_tree, (BoxTypePtr) via, 0);
909 END_LOOP;
911 /* elements */
912 ELEMENT_LOOP (Buffer->Data);
914 RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
915 Number);
917 END_LOOP;
919 /* all layer related objects */
920 ALLLINE_LOOP (Buffer->Data);
922 r_delete_entry (layer->line_tree, (BoxTypePtr) line);
923 RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number);
924 r_insert_entry (layer->line_tree, (BoxTypePtr) line, 0);
926 ENDALL_LOOP;
927 ALLARC_LOOP (Buffer->Data);
929 r_delete_entry (layer->arc_tree, (BoxTypePtr) arc);
930 RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number);
931 r_insert_entry (layer->arc_tree, (BoxTypePtr) arc, 0);
933 ENDALL_LOOP;
934 ALLTEXT_LOOP (Buffer->Data);
936 r_delete_entry (layer->text_tree, (BoxTypePtr) text);
937 RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number);
938 r_insert_entry (layer->text_tree, (BoxTypePtr) text, 0);
940 ENDALL_LOOP;
941 ALLPOLYGON_LOOP (Buffer->Data);
943 r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
944 RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number);
945 r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
947 ENDALL_LOOP;
949 /* finally the origin and the bounding box */
950 ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number);
951 RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number);
954 static void
955 free_rotate (int *x, int *y, int cx, int cy, double cosa, double sina)
957 double nx, ny;
958 int px = *x - cx;
959 int py = *y - cy;
961 nx = px * cosa + py * sina;
962 ny = py * cosa - px * sina;
964 *x = nx + cx;
965 *y = ny + cy;
968 void
969 FreeRotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
970 LocationType X, LocationType Y,
971 double cosa, double sina, double Angle)
973 /* solder side objects need a different orientation */
975 /* the text subroutine decides by itself if the direction
976 * is to be corrected
978 #if 0
979 ELEMENTTEXT_LOOP (Element);
981 if (Data && Data->name_tree[n])
982 r_delete_entry (Data->name_tree[n], (BoxType *) text);
983 RotateTextLowLevel (text, X, Y, Number);
985 END_LOOP;
986 #endif
987 ELEMENTLINE_LOOP (Element);
989 free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina);
990 free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina);
991 SetLineBoundingBox (line);
993 END_LOOP;
994 PIN_LOOP (Element);
996 /* pre-delete the pins from the pin-tree before their coordinates change */
997 if (Data)
998 r_delete_entry (Data->pin_tree, (BoxType *) pin);
999 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
1000 free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina);
1001 SetPinBoundingBox (pin);
1003 END_LOOP;
1004 PAD_LOOP (Element);
1006 /* pre-delete the pads before their coordinates change */
1007 if (Data)
1008 r_delete_entry (Data->pad_tree, (BoxType *) pad);
1009 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
1010 free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina);
1011 free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina);
1012 SetLineBoundingBox ((LineType *) pad);
1014 END_LOOP;
1015 ARC_LOOP (Element);
1017 free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina);
1018 arc->StartAngle += Angle;
1019 arc->StartAngle %= 360;
1021 END_LOOP;
1023 free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina);
1024 SetElementBoundingBox (Data, Element, &PCB->Font);
1025 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
1028 void
1029 FreeRotateBuffer (BufferTypePtr Buffer, double Angle)
1031 double cosa, sina;
1033 cosa = cos(Angle * M_PI/180.0);
1034 sina = sin(Angle * M_PI/180.0);
1036 /* rotate vias */
1037 VIA_LOOP (Buffer->Data);
1039 r_delete_entry (Buffer->Data->via_tree, (BoxTypePtr) via);
1040 free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina);
1041 SetPinBoundingBox (via);
1042 r_insert_entry (Buffer->Data->via_tree, (BoxTypePtr) via, 0);
1044 END_LOOP;
1046 /* elements */
1047 ELEMENT_LOOP (Buffer->Data);
1049 FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y,
1050 cosa, sina, Angle);
1052 END_LOOP;
1054 /* all layer related objects */
1055 ALLLINE_LOOP (Buffer->Data);
1057 r_delete_entry (layer->line_tree, (BoxTypePtr) line);
1058 free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina);
1059 free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina);
1060 SetLineBoundingBox (line);
1061 r_insert_entry (layer->line_tree, (BoxTypePtr) line, 0);
1063 ENDALL_LOOP;
1064 ALLARC_LOOP (Buffer->Data);
1066 r_delete_entry (layer->arc_tree, (BoxTypePtr) arc);
1067 free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina);
1068 arc->StartAngle += Angle;
1069 arc->StartAngle %= 360;
1070 r_insert_entry (layer->arc_tree, (BoxTypePtr) arc, 0);
1072 ENDALL_LOOP;
1073 /* FIXME: rotate text */
1074 ALLPOLYGON_LOOP (Buffer->Data);
1076 r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
1077 POLYGONPOINT_LOOP (polygon);
1079 free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina);
1081 END_LOOP;
1082 SetPolygonBoundingBox (polygon);
1083 r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
1085 ENDALL_LOOP;
1087 SetBufferBoundingBox (Buffer);
1091 ActionFreeRotateBuffer(int argc, char **argv, int x, int y)
1093 HideCrosshair(False);
1094 FreeRotateBuffer(PASTEBUFFER, strtod(argv[0], 0));
1095 RestoreCrosshair(False);
1096 return 0;
1099 /* ---------------------------------------------------------------------------
1100 * initializes the buffers by allocating memory
1102 void
1103 InitBuffers (void)
1105 int i;
1107 for (i = 0; i < MAX_BUFFER; i++)
1108 Buffers[i].Data = CreateNewBuffer ();
1111 void
1112 SwapBuffers (void)
1114 int i;
1116 for (i = 0; i < MAX_BUFFER; i++)
1117 SwapBuffer (&Buffers[i]);
1118 SetCrosshairRangeToBuffer ();
1121 void
1122 MirrorBuffer (BufferTypePtr Buffer)
1124 int i;
1126 if (Buffer->Data->ElementN)
1128 Message (_("You can't mirror a buffer that has elements!\n"));
1129 return;
1131 for (i = 0; i < max_layer + 2; i++)
1133 LayerTypePtr layer = Buffer->Data->Layer + i;
1134 if (layer->TextN)
1136 Message (_("You can't mirror a buffer that has text!\n"));
1137 return;
1140 /* set buffer offset to 'mark' position */
1141 Buffer->X = SWAP_X (Buffer->X);
1142 Buffer->Y = SWAP_Y (Buffer->Y);
1143 VIA_LOOP (Buffer->Data);
1145 via->X = SWAP_X (via->X);
1146 via->Y = SWAP_Y (via->Y);
1148 END_LOOP;
1149 ALLLINE_LOOP (Buffer->Data);
1151 line->Point1.X = SWAP_X (line->Point1.X);
1152 line->Point1.Y = SWAP_Y (line->Point1.Y);
1153 line->Point2.X = SWAP_X (line->Point2.X);
1154 line->Point2.Y = SWAP_Y (line->Point2.Y);
1156 ENDALL_LOOP;
1157 ALLARC_LOOP (Buffer->Data);
1159 arc->X = SWAP_X (arc->X);
1160 arc->Y = SWAP_Y (arc->Y);
1161 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1162 arc->Delta = SWAP_DELTA (arc->Delta);
1163 SetArcBoundingBox (arc);
1165 ENDALL_LOOP;
1166 ALLPOLYGON_LOOP (Buffer->Data);
1168 POLYGONPOINT_LOOP (polygon);
1170 point->X = SWAP_X (point->X);
1171 point->Y = SWAP_Y (point->Y);
1173 END_LOOP;
1174 SetPolygonBoundingBox (polygon);
1176 ENDALL_LOOP;
1177 SetBufferBoundingBox (Buffer);
1181 /* ---------------------------------------------------------------------------
1182 * flip components/tracks from one side to the other
1184 static void
1185 SwapBuffer (BufferTypePtr Buffer)
1187 int j, k;
1188 Cardinal sgroup, cgroup;
1189 LayerType swap;
1191 ELEMENT_LOOP (Buffer->Data);
1193 r_delete_element (Buffer->Data, element);
1194 MirrorElementCoordinates (Buffer->Data, element, 0);
1196 END_LOOP;
1197 /* set buffer offset to 'mark' position */
1198 Buffer->X = SWAP_X (Buffer->X);
1199 Buffer->Y = SWAP_Y (Buffer->Y);
1200 VIA_LOOP (Buffer->Data);
1202 r_delete_entry (Buffer->Data->via_tree, (BoxTypePtr) via);
1203 via->X = SWAP_X (via->X);
1204 via->Y = SWAP_Y (via->Y);
1205 SetPinBoundingBox (via);
1206 r_insert_entry (Buffer->Data->via_tree, (BoxTypePtr) via, 0);
1208 END_LOOP;
1209 ALLLINE_LOOP (Buffer->Data);
1211 r_delete_entry (layer->line_tree, (BoxTypePtr) line);
1212 line->Point1.X = SWAP_X (line->Point1.X);
1213 line->Point1.Y = SWAP_Y (line->Point1.Y);
1214 line->Point2.X = SWAP_X (line->Point2.X);
1215 line->Point2.Y = SWAP_Y (line->Point2.Y);
1216 SetLineBoundingBox (line);
1217 r_insert_entry (layer->line_tree, (BoxTypePtr) line, 0);
1219 ENDALL_LOOP;
1220 ALLARC_LOOP (Buffer->Data);
1222 r_delete_entry (layer->arc_tree, (BoxTypePtr) arc);
1223 arc->X = SWAP_X (arc->X);
1224 arc->Y = SWAP_Y (arc->Y);
1225 arc->StartAngle = SWAP_ANGLE (arc->StartAngle);
1226 arc->Delta = SWAP_DELTA (arc->Delta);
1227 SetArcBoundingBox (arc);
1228 r_insert_entry (layer->arc_tree, (BoxTypePtr) arc, 0);
1230 ENDALL_LOOP;
1231 ALLPOLYGON_LOOP (Buffer->Data);
1233 r_delete_entry (layer->polygon_tree, (BoxTypePtr) polygon);
1234 POLYGONPOINT_LOOP (polygon);
1236 point->X = SWAP_X (point->X);
1237 point->Y = SWAP_Y (point->Y);
1239 END_LOOP;
1240 SetPolygonBoundingBox (polygon);
1241 r_insert_entry (layer->polygon_tree, (BoxTypePtr) polygon, 0);
1242 /* hmmm, how to handle clip */
1244 ENDALL_LOOP;
1245 ALLTEXT_LOOP (Buffer->Data);
1247 r_delete_entry (layer->text_tree, (BoxTypePtr) text);
1248 text->X = SWAP_X (text->X);
1249 text->Y = SWAP_Y (text->Y);
1250 TOGGLE_FLAG (ONSOLDERFLAG, text);
1251 SetTextBoundingBox (&PCB->Font, text);
1252 r_insert_entry (layer->text_tree, (BoxTypePtr) text, 0);
1254 ENDALL_LOOP;
1255 /* swap silkscreen layers */
1256 swap = Buffer->Data->Layer[max_layer + SOLDER_LAYER];
1257 Buffer->Data->Layer[max_layer + SOLDER_LAYER] =
1258 Buffer->Data->Layer[max_layer + COMPONENT_LAYER];
1259 Buffer->Data->Layer[max_layer + COMPONENT_LAYER] = swap;
1261 /* swap layer groups when balanced */
1262 sgroup = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
1263 cgroup = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
1264 if (PCB->LayerGroups.Number[cgroup] == PCB->LayerGroups.Number[sgroup])
1266 for (j = k = 0; j < PCB->LayerGroups.Number[sgroup]; j++)
1268 int t1, t2;
1269 Cardinal cnumber = PCB->LayerGroups.Entries[cgroup][k];
1270 Cardinal snumber = PCB->LayerGroups.Entries[sgroup][j];
1272 if (snumber >= max_layer)
1273 continue;
1274 swap = Buffer->Data->Layer[snumber];
1276 while (cnumber >= max_layer)
1278 k++;
1279 cnumber = PCB->LayerGroups.Entries[cgroup][k];
1281 Buffer->Data->Layer[snumber] = Buffer->Data->Layer[cnumber];
1282 Buffer->Data->Layer[cnumber] = swap;
1283 k++;
1284 /* move the thermal flags with the layers */
1285 ALLPIN_LOOP (Buffer->Data);
1287 t1 = TEST_THERM (snumber, pin);
1288 t2 = TEST_THERM (cnumber, pin);
1289 ASSIGN_THERM (snumber, t2, pin);
1290 ASSIGN_THERM (cnumber, t1, pin);
1292 ENDALL_LOOP;
1293 VIA_LOOP (Buffer->Data);
1295 t1 = TEST_THERM (snumber, via);
1296 t2 = TEST_THERM (cnumber, via);
1297 ASSIGN_THERM (snumber, t2, via);
1298 ASSIGN_THERM (cnumber, t1, via);
1300 END_LOOP;
1303 SetBufferBoundingBox (Buffer);
1306 /* ----------------------------------------------------------------------
1307 * moves the passed object to the passed buffer and removes it
1308 * from its original place
1310 void *
1311 MoveObjectToBuffer (DataTypePtr Destination, DataTypePtr Src,
1312 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1314 /* setup local identifiers used by move operations */
1315 Dest = Destination;
1316 Source = Src;
1317 return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1320 /* ----------------------------------------------------------------------
1321 * Adds the passed object to the passed buffer
1323 void *
1324 CopyObjectToBuffer (DataTypePtr Destination, DataTypePtr Src,
1325 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
1327 /* setup local identifiers used by Add operations */
1328 Dest = Destination;
1329 Source = Src;
1330 return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3));
1333 /* ---------------------------------------------------------------------- */
1335 HID_Action rotate_action_list[] = {
1336 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer,
1337 0,0}
1340 REGISTER_ACTIONS (rotate_action_list)