6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 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
30 /* functions used to rotate pins, elements ...
41 #include "crosshair.h"
49 #include "rubberband.h"
55 #ifdef HAVE_LIBDMALLOC
64 /* ---------------------------------------------------------------------------
65 * some local prototypes
67 static void *RotateText (LayerTypePtr
, TextTypePtr
);
68 static void *RotateArc (LayerTypePtr
, ArcTypePtr
);
69 static void *RotateElement (ElementTypePtr
);
70 static void *RotateElementName (ElementTypePtr
);
71 static void *RotateLinePoint (LayerTypePtr
, LineTypePtr
, PointTypePtr
);
73 /* ----------------------------------------------------------------------
74 * some local identifiers
76 static LocationType CenterX
, /* center of rotation */
78 static BYTE Number
; /* number of rotations */
79 static ObjectFunctionType RotateFunctions
= {
94 /* ---------------------------------------------------------------------------
95 * rotates a point in 90 degree steps
98 RotatePointLowLevel (PointTypePtr Point
, LocationType X
, LocationType Y
,
101 ROTATE (Point
->X
, Point
->Y
, X
, Y
, Number
);
104 /* ---------------------------------------------------------------------------
105 * rotates a line in 90 degree steps
108 RotateLineLowLevel (LineTypePtr Line
, LocationType X
, LocationType Y
,
111 ROTATE (Line
->Point1
.X
, Line
->Point1
.Y
, X
, Y
, Number
);
112 ROTATE (Line
->Point2
.X
, Line
->Point2
.Y
, X
, Y
, Number
);
113 /* keep horizontal, vertical Point2 > Point1 */
114 if (Line
->Point1
.X
== Line
->Point2
.X
)
116 if (Line
->Point1
.Y
> Line
->Point2
.Y
)
120 Line
->Point1
.Y
= Line
->Point2
.Y
;
124 else if (Line
->Point1
.Y
== Line
->Point2
.Y
)
126 if (Line
->Point1
.X
> Line
->Point2
.X
)
130 Line
->Point1
.X
= Line
->Point2
.X
;
134 /* instead of rotating the bounding box, the call updates both end points too */
135 SetLineBoundingBox (Line
);
138 /* ---------------------------------------------------------------------------
139 * rotates a text in 90 degree steps
140 * only the bounding box is rotated, text rotation itself
141 * is done by the drawing routines
144 RotateTextLowLevel (TextTypePtr Text
, LocationType X
, LocationType Y
,
149 number
= TEST_FLAG (ONSOLDERFLAG
, Text
) ? (4 - Number
) & 3 : Number
;
150 RotateBoxLowLevel (&Text
->BoundingBox
, X
, Y
, Number
);
151 ROTATE (Text
->X
, Text
->Y
, X
, Y
, Number
);
153 /* set new direction, 0..3,
154 * 0-> to the right, 1-> straight up,
155 * 2-> to the left, 3-> straight down
157 Text
->Direction
= ((Text
->Direction
+ number
) & 0x03);
160 /* ---------------------------------------------------------------------------
161 * rotates a polygon in 90 degree steps
164 RotatePolygonLowLevel (PolygonTypePtr Polygon
,
165 LocationType X
, LocationType Y
, BYTE Number
)
167 POLYGONPOINT_LOOP (Polygon
);
169 ROTATE (point
->X
, point
->Y
, X
, Y
, Number
);
172 RotateBoxLowLevel (&Polygon
->BoundingBox
, X
, Y
, Number
);
175 /* ---------------------------------------------------------------------------
176 * rotates a text object and redraws it
179 RotateText (LayerTypePtr Layer
, TextTypePtr Text
)
181 EraseText (Layer
, Text
);
182 RestoreToPolygon (PCB
->Data
, TEXT_TYPE
, Layer
, Text
);
183 r_delete_entry (Layer
->text_tree
, (BoxTypePtr
) Text
);
184 RotateTextLowLevel (Text
, CenterX
, CenterY
, Number
);
185 r_insert_entry (Layer
->text_tree
, (BoxTypePtr
) Text
, 0);
186 ClearFromPolygon (PCB
->Data
, TEXT_TYPE
, Layer
, Text
);
187 DrawText (Layer
, Text
, 0);
192 /* ---------------------------------------------------------------------------
196 RotateArcLowLevel (ArcTypePtr Arc
, LocationType X
, LocationType Y
,
201 /* add Number*90 degrees to the startangle and check for overflow */
202 Arc
->StartAngle
= (Arc
->StartAngle
+ Number
* 90) % 360;
203 ROTATE (Arc
->X
, Arc
->Y
, X
, Y
, Number
);
205 /* now change width and height */
206 if (Number
== 1 || Number
== 3)
209 Arc
->Width
= Arc
->Height
;
212 RotateBoxLowLevel (&Arc
->BoundingBox
, X
, Y
, Number
);
215 /* ---------------------------------------------------------------------------
216 * rotate an element in 90 degree steps
219 RotateElementLowLevel (DataTypePtr Data
, ElementTypePtr Element
,
220 LocationType X
, LocationType Y
, BYTE Number
)
222 /* solder side objects need a different orientation */
224 /* the text subroutine decides by itself if the direction
227 ELEMENTTEXT_LOOP (Element
);
229 if (Data
&& Data
->name_tree
[n
])
230 r_delete_entry (Data
->name_tree
[n
], (BoxType
*) text
);
231 RotateTextLowLevel (text
, X
, Y
, Number
);
234 ELEMENTLINE_LOOP (Element
);
236 RotateLineLowLevel (line
, X
, Y
, Number
);
241 /* pre-delete the pins from the pin-tree before their coordinates change */
243 r_delete_entry (Data
->pin_tree
, (BoxType
*) pin
);
244 RestoreToPolygon (Data
, PIN_TYPE
, Element
, pin
);
245 ROTATE_PIN_LOWLEVEL (pin
, X
, Y
, Number
);
250 /* pre-delete the pads before their coordinates change */
252 r_delete_entry (Data
->pad_tree
, (BoxType
*) pad
);
253 RestoreToPolygon (Data
, PAD_TYPE
, Element
, pad
);
254 ROTATE_PAD_LOWLEVEL (pad
, X
, Y
, Number
);
259 RotateArcLowLevel (arc
, X
, Y
, Number
);
262 ROTATE (Element
->MarkX
, Element
->MarkY
, X
, Y
, Number
);
263 /* SetElementBoundingBox reenters the rtree data */
264 SetElementBoundingBox (Data
, Element
, &PCB
->Font
);
265 ClearFromPolygon (Data
, ELEMENT_TYPE
, Element
, Element
);
268 /* ---------------------------------------------------------------------------
269 * rotates a line's point
272 RotateLinePoint (LayerTypePtr Layer
, LineTypePtr Line
, PointTypePtr Point
)
277 RestoreToPolygon (PCB
->Data
, LINE_TYPE
, Layer
, Line
);
278 r_delete_entry (Layer
->line_tree
, (BoxTypePtr
) Line
);
281 r_delete_entry (PCB
->Data
->rat_tree
, (BoxTypePtr
) Line
);
282 RotatePointLowLevel (Point
, CenterX
, CenterY
, Number
);
283 SetLineBoundingBox (Line
);
286 r_insert_entry (Layer
->line_tree
, (BoxTypePtr
) Line
, 0);
287 ClearFromPolygon (PCB
->Data
, LINE_TYPE
, Layer
, Line
);
288 DrawLine (Layer
, Line
, 0);
292 r_insert_entry (PCB
->Data
->rat_tree
, (BoxTypePtr
) Line
, 0);
293 DrawRat ((RatTypePtr
) Line
, 0);
299 /* ---------------------------------------------------------------------------
303 RotateArc (LayerTypePtr Layer
, ArcTypePtr Arc
)
306 r_delete_entry (Layer
->arc_tree
, (BoxTypePtr
) Arc
);
307 RotateArcLowLevel (Arc
, CenterX
, CenterY
, Number
);
308 r_insert_entry (Layer
->arc_tree
, (BoxTypePtr
) Arc
, 0);
309 DrawArc (Layer
, Arc
, 0);
314 /* ---------------------------------------------------------------------------
318 RotateElement (ElementTypePtr Element
)
320 EraseElement (Element
);
321 RotateElementLowLevel (PCB
->Data
, Element
, CenterX
, CenterY
, Number
);
322 DrawElement (Element
, 0);
327 /* ----------------------------------------------------------------------
328 * rotates the name of an element
331 RotateElementName (ElementTypePtr Element
)
333 EraseElementName (Element
);
334 ELEMENTTEXT_LOOP (Element
);
336 r_delete_entry (PCB
->Data
->name_tree
[n
], (BoxType
*) text
);
337 RotateTextLowLevel (text
, CenterX
, CenterY
, Number
);
338 r_insert_entry (PCB
->Data
->name_tree
[n
], (BoxType
*) text
, 0);
341 DrawElementName (Element
, 0);
346 /* ---------------------------------------------------------------------------
347 * rotates a box in 90 degree steps
350 RotateBoxLowLevel (BoxTypePtr Box
, LocationType X
, LocationType Y
,
353 LocationType x1
= Box
->X1
, y1
= Box
->Y1
, x2
= Box
->X2
, y2
= Box
->Y2
;
355 ROTATE (x1
, y1
, X
, Y
, Number
);
356 ROTATE (x2
, y2
, X
, Y
, Number
);
357 Box
->X1
= MIN (x1
, x2
);
358 Box
->Y1
= MIN (y1
, y2
);
359 Box
->X2
= MAX (x1
, x2
);
360 Box
->Y2
= MAX (y1
, y2
);
363 /* ----------------------------------------------------------------------
364 * rotates an objects at the cursor position as identified by its ID
365 * the center of rotation is determined by the current cursor location
368 RotateObject (int Type
, void *Ptr1
, void *Ptr2
, void *Ptr3
,
369 LocationType X
, LocationType Y
, BYTE Steps
)
371 RubberbandTypePtr ptr
;
373 Boolean changed
= False
;
375 /* setup default global identifiers */
380 /* move all the rubberband lines... and reset the counter */
381 ptr
= Crosshair
.AttachedObject
.Rubberband
;
382 while (Crosshair
.AttachedObject
.RubberbandN
)
385 CLEAR_FLAG (RUBBERENDFLAG
, ptr
->Line
);
386 AddObjectToRotateUndoList (LINEPOINT_TYPE
, ptr
->Layer
, ptr
->Line
,
387 ptr
->MovedPoint
, CenterX
, CenterY
, Steps
);
388 EraseLine (ptr
->Line
);
391 RestoreToPolygon (PCB
->Data
, LINE_TYPE
, ptr
->Layer
, ptr
->Line
);
392 r_delete_entry (ptr
->Layer
->line_tree
, (BoxType
*) ptr
->Line
);
395 r_delete_entry (PCB
->Data
->rat_tree
, (BoxType
*) ptr
->Line
);
396 RotatePointLowLevel (ptr
->MovedPoint
, CenterX
, CenterY
, Steps
);
397 SetLineBoundingBox (ptr
->Line
);
400 r_insert_entry (ptr
->Layer
->line_tree
, (BoxType
*) ptr
->Line
, 0);
401 ClearFromPolygon (PCB
->Data
, LINE_TYPE
, ptr
->Layer
, ptr
->Line
);
402 DrawLine (ptr
->Layer
, ptr
->Line
, 0);
406 r_insert_entry (PCB
->Data
->rat_tree
, (BoxType
*) ptr
->Line
, 0);
407 DrawRat ((RatTypePtr
) ptr
->Line
, 0);
409 Crosshair
.AttachedObject
.RubberbandN
--;
412 AddObjectToRotateUndoList (Type
, Ptr1
, Ptr2
, Ptr3
, CenterX
, CenterY
,
414 ptr2
= ObjectOperation (&RotateFunctions
, Type
, Ptr1
, Ptr2
, Ptr3
);
415 changed
|= (ptr2
!= NULL
);
419 IncrementUndoSerialNumber ();
425 RotateScreenObject (LocationType X
, LocationType Y
, BYTE Steps
)
428 void *ptr1
, *ptr2
, *ptr3
;
429 if ((type
= SearchScreen (X
, Y
, ROTATE_TYPES
, &ptr1
, &ptr2
,
432 if (TEST_FLAG (LOCKFLAG
, (ArcTypePtr
) ptr2
))
434 Message (_("Sorry, the object is locked\n"));
437 Crosshair
.AttachedObject
.RubberbandN
= 0;
438 if (TEST_FLAG (RUBBERBANDFLAG
, PCB
))
439 LookupRubberbandLines (type
, ptr1
, ptr2
, ptr3
);
440 if (type
== ELEMENT_TYPE
)
441 LookupRatLines (type
, ptr1
, ptr2
, ptr3
);
442 RotateObject (type
, ptr1
, ptr2
, ptr3
, X
, Y
, Steps
);
443 SetChangedFlag (True
);