Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / rotate.c
blob9e195819acff789d61bc823d0f388f135a607696
1 /* $Id$ */
3 /*
4 * COPYRIGHT
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 ...
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include <stdlib.h>
39 #include "global.h"
41 #include "crosshair.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "misc.h"
46 #include "polygon.h"
47 #include "rotate.h"
48 #include "rtree.h"
49 #include "rubberband.h"
50 #include "search.h"
51 #include "select.h"
52 #include "set.h"
53 #include "undo.h"
55 #ifdef HAVE_LIBDMALLOC
56 #include <dmalloc.h>
57 #endif
59 RCSID ("$Id$");
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 */
77 CenterY;
78 static BYTE Number; /* number of rotations */
79 static ObjectFunctionType RotateFunctions = {
80 NULL,
81 RotateText,
82 NULL,
83 NULL,
84 RotateElement,
85 RotateElementName,
86 NULL,
87 NULL,
88 RotateLinePoint,
89 NULL,
90 RotateArc,
91 NULL
94 /* ---------------------------------------------------------------------------
95 * rotates a point in 90 degree steps
97 void
98 RotatePointLowLevel (PointTypePtr Point, LocationType X, LocationType Y,
99 BYTE Number)
101 ROTATE (Point->X, Point->Y, X, Y, Number);
104 /* ---------------------------------------------------------------------------
105 * rotates a line in 90 degree steps
107 void
108 RotateLineLowLevel (LineTypePtr Line, LocationType X, LocationType Y,
109 BYTE Number)
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)
118 LocationType t;
119 t = Line->Point1.Y;
120 Line->Point1.Y = Line->Point2.Y;
121 Line->Point2.Y = t;
124 else if (Line->Point1.Y == Line->Point2.Y)
126 if (Line->Point1.X > Line->Point2.X)
128 LocationType t;
129 t = Line->Point1.X;
130 Line->Point1.X = Line->Point2.X;
131 Line->Point2.X = t;
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
143 void
144 RotateTextLowLevel (TextTypePtr Text, LocationType X, LocationType Y,
145 BYTE Number)
147 BYTE number;
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
163 void
164 RotatePolygonLowLevel (PolygonTypePtr Polygon,
165 LocationType X, LocationType Y, BYTE Number)
167 POLYGONPOINT_LOOP (Polygon);
169 ROTATE (point->X, point->Y, X, Y, Number);
171 END_LOOP;
172 RotateBoxLowLevel (&Polygon->BoundingBox, X, Y, Number);
175 /* ---------------------------------------------------------------------------
176 * rotates a text object and redraws it
178 static void *
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);
188 Draw ();
189 return (Text);
192 /* ---------------------------------------------------------------------------
193 * rotates an arc
195 void
196 RotateArcLowLevel (ArcTypePtr Arc, LocationType X, LocationType Y,
197 BYTE Number)
199 BDimension save;
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)
208 save = Arc->Width;
209 Arc->Width = Arc->Height;
210 Arc->Height = save;
212 RotateBoxLowLevel (&Arc->BoundingBox, X, Y, Number);
215 /* ---------------------------------------------------------------------------
216 * rotate an element in 90 degree steps
218 void
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
225 * is to be corrected
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);
233 END_LOOP;
234 ELEMENTLINE_LOOP (Element);
236 RotateLineLowLevel (line, X, Y, Number);
238 END_LOOP;
239 PIN_LOOP (Element);
241 /* pre-delete the pins from the pin-tree before their coordinates change */
242 if (Data)
243 r_delete_entry (Data->pin_tree, (BoxType *) pin);
244 RestoreToPolygon (Data, PIN_TYPE, Element, pin);
245 ROTATE_PIN_LOWLEVEL (pin, X, Y, Number);
247 END_LOOP;
248 PAD_LOOP (Element);
250 /* pre-delete the pads before their coordinates change */
251 if (Data)
252 r_delete_entry (Data->pad_tree, (BoxType *) pad);
253 RestoreToPolygon (Data, PAD_TYPE, Element, pad);
254 ROTATE_PAD_LOWLEVEL (pad, X, Y, Number);
256 END_LOOP;
257 ARC_LOOP (Element);
259 RotateArcLowLevel (arc, X, Y, Number);
261 END_LOOP;
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
271 static void *
272 RotateLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
274 EraseLine (Line);
275 if (Layer)
277 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
278 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
280 else
281 r_delete_entry (PCB->Data->rat_tree, (BoxTypePtr) Line);
282 RotatePointLowLevel (Point, CenterX, CenterY, Number);
283 SetLineBoundingBox (Line);
284 if (Layer)
286 r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
287 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
288 DrawLine (Layer, Line, 0);
290 else
292 r_insert_entry (PCB->Data->rat_tree, (BoxTypePtr) Line, 0);
293 DrawRat ((RatTypePtr) Line, 0);
295 Draw ();
296 return (Line);
299 /* ---------------------------------------------------------------------------
300 * rotates an arc
302 static void *
303 RotateArc (LayerTypePtr Layer, ArcTypePtr Arc)
305 EraseArc (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);
310 Draw ();
311 return (Arc);
314 /* ---------------------------------------------------------------------------
315 * rotates an element
317 static void *
318 RotateElement (ElementTypePtr Element)
320 EraseElement (Element);
321 RotateElementLowLevel (PCB->Data, Element, CenterX, CenterY, Number);
322 DrawElement (Element, 0);
323 Draw ();
324 return (Element);
327 /* ----------------------------------------------------------------------
328 * rotates the name of an element
330 static void *
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);
340 END_LOOP;
341 DrawElementName (Element, 0);
342 Draw ();
343 return (Element);
346 /* ---------------------------------------------------------------------------
347 * rotates a box in 90 degree steps
349 void
350 RotateBoxLowLevel (BoxTypePtr Box, LocationType X, LocationType Y,
351 BYTE Number)
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
367 void *
368 RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
369 LocationType X, LocationType Y, BYTE Steps)
371 RubberbandTypePtr ptr;
372 void *ptr2;
373 bool changed = false;
375 /* setup default global identifiers */
376 Number = Steps;
377 CenterX = X;
378 CenterY = Y;
380 /* move all the rubberband lines... and reset the counter */
381 ptr = Crosshair.AttachedObject.Rubberband;
382 while (Crosshair.AttachedObject.RubberbandN)
384 changed = true;
385 CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
386 AddObjectToRotateUndoList (LINEPOINT_TYPE, ptr->Layer, ptr->Line,
387 ptr->MovedPoint, CenterX, CenterY, Steps);
388 EraseLine (ptr->Line);
389 if (ptr->Layer)
391 RestoreToPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
392 r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
394 else
395 r_delete_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line);
396 RotatePointLowLevel (ptr->MovedPoint, CenterX, CenterY, Steps);
397 SetLineBoundingBox (ptr->Line);
398 if (ptr->Layer)
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);
404 else
406 r_insert_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line, 0);
407 DrawRat ((RatTypePtr) ptr->Line, 0);
409 Crosshair.AttachedObject.RubberbandN--;
410 ptr++;
412 AddObjectToRotateUndoList (Type, Ptr1, Ptr2, Ptr3, CenterX, CenterY,
413 Number);
414 ptr2 = ObjectOperation (&RotateFunctions, Type, Ptr1, Ptr2, Ptr3);
415 changed |= (ptr2 != NULL);
416 if (changed)
418 Draw ();
419 IncrementUndoSerialNumber ();
421 return (ptr2);
424 void
425 RotateScreenObject (LocationType X, LocationType Y, BYTE Steps)
427 int type;
428 void *ptr1, *ptr2, *ptr3;
429 if ((type = SearchScreen (X, Y, ROTATE_TYPES, &ptr1, &ptr2,
430 &ptr3)) != NO_TYPE)
432 if (TEST_FLAG (LOCKFLAG, (ArcTypePtr) ptr2))
434 Message (_("Sorry, the object is locked\n"));
435 return;
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);