(no commit message)
[geda-pcb/pcjc2.git] / src / rotate.c
blobfb23ba135bf8e7f013bdb32c76f21ad7738e278a
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
28 /* functions used to rotate pins, elements ...
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include <stdlib.h>
37 #include "global.h"
39 #include "crosshair.h"
40 #include "data.h"
41 #include "draw.h"
42 #include "error.h"
43 #include "misc.h"
44 #include "polygon.h"
45 #include "rotate.h"
46 #include "rtree.h"
47 #include "rubberband.h"
48 #include "search.h"
49 #include "select.h"
50 #include "set.h"
51 #include "undo.h"
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
57 /* ---------------------------------------------------------------------------
58 * some local prototypes
60 static void *RotateText (LayerType *, TextType *);
61 static void *RotateArc (LayerType *, ArcType *);
62 static void *RotateElement (ElementType *);
63 static void *RotateElementName (ElementType *);
64 static void *RotateLinePoint (LayerType *, LineType *, PointType *);
66 /* ----------------------------------------------------------------------
67 * some local identifiers
69 static Coord CenterX, CenterY; /* center of rotation */
70 static unsigned Number; /* number of rotations */
71 static ObjectFunctionType RotateFunctions = {
72 NULL,
73 RotateText,
74 NULL,
75 NULL,
76 RotateElement,
77 RotateElementName,
78 NULL,
79 NULL,
80 RotateLinePoint,
81 NULL,
82 RotateArc,
83 NULL
86 /* ---------------------------------------------------------------------------
87 * rotates a point in 90 degree steps
89 void
90 RotatePointLowLevel (PointType *Point, Coord X, Coord Y, unsigned Number)
92 ROTATE (Point->X, Point->Y, X, Y, Number);
95 /* ---------------------------------------------------------------------------
96 * rotates a line in 90 degree steps
98 void
99 RotateLineLowLevel (LineType *Line, Coord X, Coord Y, unsigned Number)
101 ROTATE (Line->Point1.X, Line->Point1.Y, X, Y, Number);
102 ROTATE (Line->Point2.X, Line->Point2.Y, X, Y, Number);
103 /* keep horizontal, vertical Point2 > Point1 */
104 if (Line->Point1.X == Line->Point2.X)
106 if (Line->Point1.Y > Line->Point2.Y)
108 Coord t;
109 t = Line->Point1.Y;
110 Line->Point1.Y = Line->Point2.Y;
111 Line->Point2.Y = t;
114 else if (Line->Point1.Y == Line->Point2.Y)
116 if (Line->Point1.X > Line->Point2.X)
118 Coord t;
119 t = Line->Point1.X;
120 Line->Point1.X = Line->Point2.X;
121 Line->Point2.X = t;
124 /* instead of rotating the bounding box, the call updates both end points too */
125 SetLineBoundingBox (Line);
128 /* ---------------------------------------------------------------------------
129 * rotates a text in 90 degree steps
130 * only the bounding box is rotated, text rotation itself
131 * is done by the drawing routines
133 void
134 RotateTextLowLevel (TextType *Text, Coord X, Coord Y, unsigned Number)
136 BYTE number;
138 number = TEST_FLAG (ONSOLDERFLAG, Text) ? (4 - Number) & 3 : Number;
139 RotateBoxLowLevel (&Text->BoundingBox, X, Y, Number);
140 ROTATE (Text->X, Text->Y, X, Y, Number);
142 /* set new direction, 0..3,
143 * 0-> to the right, 1-> straight up,
144 * 2-> to the left, 3-> straight down
146 Text->Direction = ((Text->Direction + number) & 0x03);
149 /* ---------------------------------------------------------------------------
150 * rotates a polygon in 90 degree steps
152 void
153 RotatePolygonLowLevel (PolygonType *Polygon, Coord X, Coord Y, unsigned Number)
155 POLYGONPOINT_LOOP (Polygon);
157 ROTATE (point->X, point->Y, X, Y, Number);
159 END_LOOP;
160 RotateBoxLowLevel (&Polygon->BoundingBox, X, Y, Number);
163 /* ---------------------------------------------------------------------------
164 * rotates a text object and redraws it
166 static void *
167 RotateText (LayerType *Layer, TextType *Text)
169 EraseText (Layer, Text);
170 RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
171 r_delete_entry (Layer->text_tree, (BoxType *) Text);
172 RotateTextLowLevel (Text, CenterX, CenterY, Number);
173 r_insert_entry (Layer->text_tree, (BoxType *) Text, 0);
174 ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
175 DrawText (Layer, Text);
176 Draw ();
177 return (Text);
180 /* ---------------------------------------------------------------------------
181 * rotates an arc
183 void
184 RotateArcLowLevel (ArcType *Arc, Coord X, Coord Y, unsigned Number)
186 Coord save;
188 /* add Number*90 degrees (i.e., Number quarter-turns) */
189 Arc->StartAngle = NormalizeAngle (Arc->StartAngle + Number * 90);
190 ROTATE (Arc->X, Arc->Y, X, Y, Number);
192 /* now change width and height */
193 if (Number == 1 || Number == 3)
195 save = Arc->Width;
196 Arc->Width = Arc->Height;
197 Arc->Height = save;
199 RotateBoxLowLevel (&Arc->BoundingBox, X, Y, Number);
200 ROTATE (Arc->Point1.X, Arc->Point1.Y, X, Y, Number);
201 ROTATE (Arc->Point2.X, Arc->Point2.Y, X, Y, Number);
204 /* ---------------------------------------------------------------------------
205 * rotate an element in 90 degree steps
207 void
208 RotateElementLowLevel (DataType *Data, ElementType *Element,
209 Coord X, Coord Y, unsigned Number)
211 /* solder side objects need a different orientation */
213 /* the text subroutine decides by itself if the direction
214 * is to be corrected
216 ELEMENTTEXT_LOOP (Element);
218 if (Data && Data->name_tree[n])
219 r_delete_entry (Data->name_tree[n], (BoxType *) text);
220 RotateTextLowLevel (text, X, Y, Number);
222 END_LOOP;
223 ELEMENTLINE_LOOP (Element);
225 RotateLineLowLevel (line, X, Y, Number);
227 END_LOOP;
228 PIN_LOOP (Element);
230 /* pre-delete the pins from the pin-tree before their coordinates change */
231 if (Data)
232 r_delete_entry (Data->pin_tree, (BoxType *) pin);
233 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
234 ROTATE_PIN_LOWLEVEL (pin, X, Y, Number);
236 END_LOOP;
237 PAD_LOOP (Element);
239 /* pre-delete the pads before their coordinates change */
240 if (Data)
241 r_delete_entry (Data->pad_tree, (BoxType *) pad);
242 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
243 ROTATE_PAD_LOWLEVEL (pad, X, Y, Number);
245 END_LOOP;
246 ARC_LOOP (Element);
248 RotateArcLowLevel (arc, X, Y, Number);
250 END_LOOP;
251 ROTATE (Element->MarkX, Element->MarkY, X, Y, Number);
252 /* SetElementBoundingBox reenters the rtree data */
253 SetElementBoundingBox (Data, Element, &PCB->Font);
254 ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
257 /* ---------------------------------------------------------------------------
258 * rotates a line's point
260 static void *
261 RotateLinePoint (LayerType *Layer, LineType *Line, PointType *Point)
263 EraseLine (Line);
264 if (Layer)
266 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
267 r_delete_entry (Layer->line_tree, (BoxType *) Line);
269 else
270 r_delete_entry (PCB->Data->rat_tree, (BoxType *) Line);
271 RotatePointLowLevel (Point, CenterX, CenterY, Number);
272 SetLineBoundingBox (Line);
273 if (Layer)
275 r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
276 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
277 DrawLine (Layer, Line);
279 else
281 r_insert_entry (PCB->Data->rat_tree, (BoxType *) Line, 0);
282 DrawRat ((RatType *) Line);
284 Draw ();
285 return (Line);
288 /* ---------------------------------------------------------------------------
289 * rotates an arc
291 static void *
292 RotateArc (LayerType *Layer, ArcType *Arc)
294 EraseArc (Arc);
295 r_delete_entry (Layer->arc_tree, (BoxType *) Arc);
296 RotateArcLowLevel (Arc, CenterX, CenterY, Number);
297 r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0);
298 DrawArc (Layer, Arc);
299 Draw ();
300 return (Arc);
303 /* ---------------------------------------------------------------------------
304 * rotates an element
306 static void *
307 RotateElement (ElementType *Element)
309 EraseElement (Element);
310 RotateElementLowLevel (PCB->Data, Element, CenterX, CenterY, Number);
311 DrawElement (Element);
312 Draw ();
313 return (Element);
316 /* ----------------------------------------------------------------------
317 * rotates the name of an element
319 static void *
320 RotateElementName (ElementType *Element)
322 EraseElementName (Element);
323 ELEMENTTEXT_LOOP (Element);
325 r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text);
326 RotateTextLowLevel (text, CenterX, CenterY, Number);
327 r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0);
329 END_LOOP;
330 DrawElementName (Element);
331 Draw ();
332 return (Element);
335 /* ---------------------------------------------------------------------------
336 * rotates a box in 90 degree steps
338 void
339 RotateBoxLowLevel (BoxType *Box, Coord X, Coord Y, unsigned Number)
341 Coord x1 = Box->X1, y1 = Box->Y1, x2 = Box->X2, y2 = Box->Y2;
343 ROTATE (x1, y1, X, Y, Number);
344 ROTATE (x2, y2, X, Y, Number);
345 Box->X1 = MIN (x1, x2);
346 Box->Y1 = MIN (y1, y2);
347 Box->X2 = MAX (x1, x2);
348 Box->Y2 = MAX (y1, y2);
351 /* ----------------------------------------------------------------------
352 * rotates an objects at the cursor position as identified by its ID
353 * the center of rotation is determined by the current cursor location
355 void *
356 RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
357 Coord X, Coord Y, unsigned Steps)
359 RubberbandType *ptr;
360 void *ptr2;
361 bool changed = false;
363 /* setup default global identifiers */
364 Number = Steps;
365 CenterX = X;
366 CenterY = Y;
368 /* move all the rubberband lines... and reset the counter */
369 ptr = Crosshair.AttachedObject.Rubberband;
370 while (Crosshair.AttachedObject.RubberbandN)
372 changed = true;
373 CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
374 AddObjectToRotateUndoList (LINEPOINT_TYPE, ptr->Layer, ptr->Line,
375 ptr->MovedPoint, CenterX, CenterY, Steps);
376 EraseLine (ptr->Line);
377 if (ptr->Layer)
379 RestoreToPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
380 r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
382 else
383 r_delete_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line);
384 RotatePointLowLevel (ptr->MovedPoint, CenterX, CenterY, Steps);
385 SetLineBoundingBox (ptr->Line);
386 if (ptr->Layer)
388 r_insert_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line, 0);
389 ClearFromPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
390 DrawLine (ptr->Layer, ptr->Line);
392 else
394 r_insert_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line, 0);
395 DrawRat ((RatType *) ptr->Line);
397 Crosshair.AttachedObject.RubberbandN--;
398 ptr++;
400 AddObjectToRotateUndoList (Type, Ptr1, Ptr2, Ptr3, CenterX, CenterY,
401 Number);
402 ptr2 = ObjectOperation (&RotateFunctions, Type, Ptr1, Ptr2, Ptr3);
403 changed |= (ptr2 != NULL);
404 if (changed)
406 Draw ();
407 IncrementUndoSerialNumber ();
409 return (ptr2);
412 void
413 RotateScreenObject (Coord X, Coord Y, unsigned Steps)
415 int type;
416 void *ptr1, *ptr2, *ptr3;
417 if ((type = SearchScreen (X, Y, ROTATE_TYPES, &ptr1, &ptr2,
418 &ptr3)) != NO_TYPE)
420 if (TEST_FLAG (LOCKFLAG, (ArcType *) ptr2))
422 Message (_("Sorry, the object is locked\n"));
423 return;
425 Crosshair.AttachedObject.RubberbandN = 0;
426 if (TEST_FLAG (RUBBERBANDFLAG, PCB))
427 LookupRubberbandLines (type, ptr1, ptr2, ptr3);
428 if (type == ELEMENT_TYPE)
429 LookupRatLines (type, ptr1, ptr2, ptr3);
430 RotateObject (type, ptr1, ptr2, ptr3, X, Y, Steps);
431 SetChangedFlag (true);