6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996, 2005 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
29 /* functions used by paste- and move/copy buffer
45 #include "crosshair.h"
61 #ifdef HAVE_LIBDMALLOC
67 /* ---------------------------------------------------------------------------
68 * some local prototypes
70 static void *AddViaToBuffer (PinTypePtr
);
71 static void *AddLineToBuffer (LayerTypePtr
, LineTypePtr
);
72 static void *AddArcToBuffer (LayerTypePtr
, ArcTypePtr
);
73 static void *AddRatToBuffer (RatTypePtr
);
74 static void *AddTextToBuffer (LayerTypePtr
, TextTypePtr
);
75 static void *AddPolygonToBuffer (LayerTypePtr
, PolygonTypePtr
);
76 static void *AddElementToBuffer (ElementTypePtr
);
77 static void *MoveViaToBuffer (PinTypePtr
);
78 static void *MoveLineToBuffer (LayerTypePtr
, LineTypePtr
);
79 static void *MoveArcToBuffer (LayerTypePtr
, ArcTypePtr
);
80 static void *MoveRatToBuffer (RatTypePtr
);
81 static void *MoveTextToBuffer (LayerTypePtr
, TextTypePtr
);
82 static void *MovePolygonToBuffer (LayerTypePtr
, PolygonTypePtr
);
83 static void *MoveElementToBuffer (ElementTypePtr
);
84 static void SwapBuffer (BufferTypePtr
);
86 /* ---------------------------------------------------------------------------
87 * some local identifiers
89 static DataTypePtr Dest
, Source
;
91 static ObjectFunctionType AddBufferFunctions
= {
104 }, MoveBufferFunctions
=
112 NULL
, NULL
, NULL
, NULL
, NULL
, MoveArcToBuffer
, MoveRatToBuffer
};
114 static int ExtraFlag
= 0;
116 /* ---------------------------------------------------------------------------
117 * copies a via to paste buffer
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
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
143 AddLineToBuffer (LayerTypePtr Layer
, 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");
158 /* ---------------------------------------------------------------------------
159 * copies an arc to buffer
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
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
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
);
201 /* ---------------------------------------------------------------------------
202 * copies a element to buffer
205 AddElementToBuffer (ElementTypePtr Element
)
207 ElementTypePtr element
;
209 element
= GetElementMemory (Dest
);
210 CopyElementLowLevel (Dest
, element
, Element
, False
, 0, 0);
211 CLEAR_FLAG (ExtraFlag
, element
);
214 ELEMENTTEXT_LOOP (element
);
216 CLEAR_FLAG (ExtraFlag
, text
);
221 CLEAR_FLAG (ExtraFlag
, pin
);
226 CLEAR_FLAG (ExtraFlag
, pad
);
233 /* ---------------------------------------------------------------------------
234 * moves a via to paste buffer without allocating memory for the name
237 MoveViaToBuffer (PinTypePtr Via
)
241 RestoreToPolygon (Source
, VIA_TYPE
, Via
, Via
);
242 r_delete_entry (Source
->via_tree
, (BoxType
*) Via
);
243 via
= GetViaMemory (Dest
);
245 *Via
= Source
->Via
[--Source
->ViaN
];
246 r_substitute (Source
->via_tree
, (BoxType
*) & Source
->Via
[Source
->ViaN
],
248 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, via
);
249 memset (&Source
->Via
[Source
->ViaN
], 0, sizeof (PinType
));
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
);
257 /* ---------------------------------------------------------------------------
258 * moves a rat-line to paste buffer
261 MoveRatToBuffer (RatTypePtr Rat
)
265 rat
= GetRatMemory (Dest
);
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
,
271 CLEAR_FLAG (FOUNDFLAG
, Rat
);
272 memset (&Source
->Rat
[Source
->RatN
], 0, sizeof (RatType
));
274 Dest
->rat_tree
= r_create_tree (NULL
, 0, 0);
275 r_insert_entry (Dest
->rat_tree
, &rat
->BoundingBox
, 0);
279 /* ---------------------------------------------------------------------------
280 * moves a line to buffer
283 MoveLineToBuffer (LayerTypePtr Layer
, 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
);
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
],
298 memset (&Layer
->Line
[Layer
->LineN
], 0, sizeof (LineType
));
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
);
306 /* ---------------------------------------------------------------------------
307 * moves an arc to buffer
310 MoveArcToBuffer (LayerTypePtr Layer
, 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
);
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
],
325 memset (&Layer
->Arc
[Layer
->ArcN
], 0, sizeof (ArcType
));
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
);
333 /* ---------------------------------------------------------------------------
334 * moves a text to buffer without allocating memory for the name
337 MoveTextToBuffer (LayerTypePtr Layer
, TextTypePtr Text
)
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
);
347 *Text
= Layer
->Text
[--Layer
->TextN
];
348 r_substitute (Layer
->text_tree
, (BoxTypePtr
) & Layer
->Text
[Layer
->TextN
],
350 memset (&Layer
->Text
[Layer
->TextN
], 0, sizeof (TextType
));
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
);
358 /* ---------------------------------------------------------------------------
359 * moves a polygon to buffer. Doesn't allocate memory for the points
362 MovePolygonToBuffer (LayerTypePtr Layer
, PolygonTypePtr Polygon
)
365 PolygonTypePtr polygon
;
367 r_delete_entry (Layer
->polygon_tree
, (BoxTypePtr
) Polygon
);
368 lay
= &Dest
->Layer
[GetLayerNumber (Source
, Layer
)];
369 polygon
= GetPolygonMemory (lay
);
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);
383 /* ---------------------------------------------------------------------------
384 * moves a element to buffer without allocating memory for pins/names
387 MoveElementToBuffer (ElementTypePtr Element
)
389 ElementTypePtr element
;
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
);
402 RestoreToPolygon(Source
, PIN_TYPE
, Element
, pin
);
403 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pin
);
404 pin
->Element
= element
;
409 RestoreToPolygon(Source
, PAD_TYPE
, Element
, pad
);
410 CLEAR_FLAG (WARNFLAG
| FOUNDFLAG
, pad
);
411 pad
->Element
= element
;
414 ELEMENTTEXT_LOOP (element
);
416 text
->Element
= element
;
419 SetElementBoundingBox (Dest
, element
, &PCB
->Font
);
421 * Now clear the from the polygons in the destination
425 ClearFromPolygon (Dest
, PIN_TYPE
, element
, pin
);
430 ClearFromPolygon (Dest
, PAD_TYPE
, element
, pad
);
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
;
457 pin
->Element
= Element
;
462 pad
->Element
= Element
;
469 /* ---------------------------------------------------------------------------
470 * calculates the bounding box of the buffer
473 SetBufferBoundingBox (BufferTypePtr Buffer
)
475 BoxTypePtr box
= GetDataBoundingBox (Buffer
->Data
);
478 Buffer
->BoundingBox
= *box
;
481 /* ---------------------------------------------------------------------------
482 * clears the contents of the paste buffer
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
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
506 ExtraFlag
= SELECTEDFLAG
;
507 HideCrosshair (True
);
510 SelectedOperation (&AddBufferFunctions
, False
, ALL_TYPES
);
512 /* set origin to passed or current position */
520 Buffer
->X
= Crosshair
.X
;
521 Buffer
->Y
= Crosshair
.Y
;
523 RestoreCrosshair (True
);
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
534 LoadElementToBuffer (BufferTypePtr Buffer
, char *Name
, Boolean FromFile
)
536 ElementTypePtr element
;
538 ClearBuffer (Buffer
);
541 if (!ParseElementFile (Buffer
->Data
, Name
))
543 if (Settings
.ShowSolderSide
)
545 SetBufferBoundingBox (Buffer
);
546 if (Buffer
->Data
->ElementN
)
548 element
= &(Buffer
->Data
->Element
[0]);
549 Buffer
->X
= element
->MarkX
;
550 Buffer
->Y
= element
->MarkY
;
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
);
579 /* release memory which might have been acquired */
580 ClearBuffer (Buffer
);
585 /*---------------------------------------------------------------------------
587 * break buffer element into pieces
590 SmashBufferElement (BufferTypePtr Buffer
)
592 ElementTypePtr element
;
594 LayerTypePtr clayer
, slayer
;
596 if (Buffer
->Data
->ElementN
!= 1)
598 Message (_("Error! Buffer doesn't contain a single element\n"));
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 ());
611 line
->Number
= MyStrdup (NAMEONPCB_NAME (element
), "SmashBuffer");
616 CreateNewArcOnLayer (&Buffer
->Data
->SILKLAYER
,
617 arc
->X
, arc
->Y
, arc
->Width
, arc
->Height
, arc
->StartAngle
,
618 arc
->Delta
, arc
->Thickness
, 0, NoFlags ());
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
);
634 GetLayerGroupNumberByNumber (max_layer
+
635 (SWAP_IDENT
? SOLDER_LAYER
:
637 clayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
639 GetLayerGroupNumberByNumber (max_layer
+
640 (SWAP_IDENT
? COMPONENT_LAYER
:
642 slayer
= &Buffer
->Data
->Layer
[PCB
->LayerGroups
.Entries
[group
][0]];
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 ());
651 line
->Number
= MyStrdup (pad
->Number
, "SmashBuffer");
654 FreeElementMemory (element
);
659 /*---------------------------------------------------------------------------
661 * see if a polygon is a rectangle. If so, canonicalize it.
665 polygon_is_rectangle (PolygonTypePtr poly
)
669 if (poly
->PointN
!= 4)
673 if (poly
->Points
[i
].X
< poly
->Points
[best
].X
674 || poly
->Points
[i
].Y
< poly
->Points
[best
].Y
)
677 temp
[i
] = poly
->Points
[(i
+best
)%4];
678 if (temp
[0].X
== temp
[1].X
)
679 memcpy (poly
->Points
, temp
, sizeof(temp
));
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
)
696 /*---------------------------------------------------------------------------
698 * convert buffer contents into an element
701 ConvertBufferToElement (BufferTypePtr Buffer
)
703 ElementTypePtr Element
;
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
),
718 VIA_LOOP (Buffer
->Data
);
721 if (via
->Mask
< via
->Thickness
)
722 via
->Mask
= via
->Thickness
+ 2 * MASKFRAME
* 100; /* MASKFRAME is in mils */
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
));
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
741 /* get the component-side SM pads */
742 group
= GetLayerGroupNumberByNumber (max_layer
+
743 (SWAP_IDENT
? SOLDER_LAYER
:
745 GROUP_LOOP (Buffer
->Data
, group
);
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
,
755 line
->Thickness
+ line
->Clearance
, NULL
,
756 line
->Number
? line
->Number
: num
,
757 MakeFlags (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
));
761 POLYGON_LOOP (layer
);
763 int x1
, y1
, x2
, y2
, w
, h
, t
;
765 if (! polygon_is_rectangle (polygon
))
771 w
= polygon
->Points
[2].X
- polygon
->Points
[0].X
;
772 h
= polygon
->Points
[1].Y
- polygon
->Points
[0].Y
;
774 x1
= polygon
->Points
[0].X
+ t
/2;
775 y1
= polygon
->Points
[0].Y
+ t
/2;
779 sprintf (num
, "%d", pin_n
++);
780 CreateNewPad (Element
,
782 2 * Settings
.Keepaway
,
783 t
+ Settings
.Keepaway
,
785 MakeFlags (SQUAREFLAG
| (SWAP_IDENT
? ONSOLDERFLAG
: NOFLAG
)));
791 /* now get the opposite side pads */
792 group
= GetLayerGroupNumberByNumber (max_layer
+
793 (SWAP_IDENT
? COMPONENT_LAYER
:
795 GROUP_LOOP (Buffer
->Data
, group
);
797 Boolean warned
= False
;
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
,
806 line
->Thickness
+ line
->Clearance
, NULL
,
807 line
->Number
? line
->Number
: num
,
808 MakeFlags (SWAP_IDENT
? NOFLAG
: ONSOLDERFLAG
));
809 if (!hasParts
&& !warned
)
813 (_("Warning: All of the pads are on the opposite\n"
814 "side from the component - that's probably not what\n"
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
);
834 ARC_LOOP (&Buffer
->Data
->SILKLAYER
);
836 CreateNewArcInElement (Element
, arc
->X
, arc
->Y
, arc
->Width
,
837 arc
->Height
, arc
->StartAngle
, arc
->Delta
,
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"));
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
;
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
,
860 SetBufferBoundingBox (Buffer
);
864 /* ---------------------------------------------------------------------------
865 * load PCB into buffer
866 * parse the file with enabled 'PCB mode' (see parser)
867 * if successful, update some other stuff
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
;
882 Buffer
->X
= newPCB
->CursorX
;
883 Buffer
->Y
= newPCB
->CursorY
;
885 Buffer
->Data
->pcb
= PCB
;
889 /* release unused memory */
891 Buffer
->Data
->pcb
= PCB
;
895 /* ---------------------------------------------------------------------------
896 * rotates the contents of the pastebuffer
899 RotateBuffer (BufferTypePtr Buffer
, BYTE Number
)
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);
912 ELEMENT_LOOP (Buffer
->Data
);
914 RotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
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);
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);
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);
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);
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
);
955 free_rotate (int *x
, int *y
, int cx
, int cy
, double cosa
, double sina
)
961 nx
= px
* cosa
+ py
* sina
;
962 ny
= py
* cosa
- px
* sina
;
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
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
);
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
);
996 /* pre-delete the pins from the pin-tree before their coordinates change */
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
);
1006 /* pre-delete the pads before their coordinates change */
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
);
1017 free_rotate (&arc
->X
, &arc
->Y
, X
, Y
, cosa
, sina
);
1018 arc
->StartAngle
+= Angle
;
1019 arc
->StartAngle
%= 360;
1023 free_rotate (&Element
->MarkX
, &Element
->MarkY
, X
, Y
, cosa
, sina
);
1024 SetElementBoundingBox (Data
, Element
, &PCB
->Font
);
1025 ClearFromPolygon (Data
, ELEMENT_TYPE
, Element
, Element
);
1029 FreeRotateBuffer (BufferTypePtr Buffer
, double Angle
)
1033 cosa
= cos(Angle
* M_PI
/180.0);
1034 sina
= sin(Angle
* M_PI
/180.0);
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);
1047 ELEMENT_LOOP (Buffer
->Data
);
1049 FreeRotateElementLowLevel (Buffer
->Data
, element
, Buffer
->X
, Buffer
->Y
,
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);
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);
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
);
1082 SetPolygonBoundingBox (polygon
);
1083 r_insert_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
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
);
1099 /* ---------------------------------------------------------------------------
1100 * initializes the buffers by allocating memory
1107 for (i
= 0; i
< MAX_BUFFER
; i
++)
1108 Buffers
[i
].Data
= CreateNewBuffer ();
1116 for (i
= 0; i
< MAX_BUFFER
; i
++)
1117 SwapBuffer (&Buffers
[i
]);
1118 SetCrosshairRangeToBuffer ();
1122 MirrorBuffer (BufferTypePtr Buffer
)
1126 if (Buffer
->Data
->ElementN
)
1128 Message (_("You can't mirror a buffer that has elements!\n"));
1131 for (i
= 0; i
< max_layer
+ 2; i
++)
1133 LayerTypePtr layer
= Buffer
->Data
->Layer
+ i
;
1136 Message (_("You can't mirror a buffer that has text!\n"));
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
);
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
);
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
);
1166 ALLPOLYGON_LOOP (Buffer
->Data
);
1168 POLYGONPOINT_LOOP (polygon
);
1170 point
->X
= SWAP_X (point
->X
);
1171 point
->Y
= SWAP_Y (point
->Y
);
1174 SetPolygonBoundingBox (polygon
);
1177 SetBufferBoundingBox (Buffer
);
1181 /* ---------------------------------------------------------------------------
1182 * flip components/tracks from one side to the other
1185 SwapBuffer (BufferTypePtr Buffer
)
1188 Cardinal sgroup
, cgroup
;
1191 ELEMENT_LOOP (Buffer
->Data
);
1193 r_delete_element (Buffer
->Data
, element
);
1194 MirrorElementCoordinates (Buffer
->Data
, element
, 0);
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);
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);
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);
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
);
1240 SetPolygonBoundingBox (polygon
);
1241 r_insert_entry (layer
->polygon_tree
, (BoxTypePtr
) polygon
, 0);
1242 /* hmmm, how to handle clip */
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);
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
++)
1269 Cardinal cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1270 Cardinal snumber
= PCB
->LayerGroups
.Entries
[sgroup
][j
];
1272 if (snumber
>= max_layer
)
1274 swap
= Buffer
->Data
->Layer
[snumber
];
1276 while (cnumber
>= max_layer
)
1279 cnumber
= PCB
->LayerGroups
.Entries
[cgroup
][k
];
1281 Buffer
->Data
->Layer
[snumber
] = Buffer
->Data
->Layer
[cnumber
];
1282 Buffer
->Data
->Layer
[cnumber
] = swap
;
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
);
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
);
1303 SetBufferBoundingBox (Buffer
);
1306 /* ----------------------------------------------------------------------
1307 * moves the passed object to the passed buffer and removes it
1308 * from its original place
1311 MoveObjectToBuffer (DataTypePtr Destination
, DataTypePtr Src
,
1312 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1314 /* setup local identifiers used by move operations */
1317 return (ObjectOperation (&MoveBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1320 /* ----------------------------------------------------------------------
1321 * Adds the passed object to the passed buffer
1324 CopyObjectToBuffer (DataTypePtr Destination
, DataTypePtr Src
,
1325 int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
)
1327 /* setup local identifiers used by Add operations */
1330 return (ObjectOperation (&AddBufferFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
));
1333 /* ---------------------------------------------------------------------- */
1335 HID_Action rotate_action_list
[] = {
1336 {"FreeRotateBuffer", 0, ActionFreeRotateBuffer
,
1340 REGISTER_ACTIONS (rotate_action_list
)