36
41
#include "crosshair.h"
40
46
#include "polygon.h"
41
47
#include "rotate.h"
49
#include "rubberband.h"
42
50
#include "search.h"
43
51
#include "select.h"
55
#ifdef HAVE_LIBDMALLOC
59
RCSID("$Id: rotate.c,v 1.12 2005/01/03 12:57:00 danmc Exp $");
46
64
/* ---------------------------------------------------------------------------
47
65
* some local prototypes
49
static void *RotateText(LayerTypePtr, TextTypePtr);
50
static void *RotateArc(LayerTypePtr, ArcTypePtr);
51
static void *RotateElement(ElementTypePtr);
52
static void *RotateElementName(ElementTypePtr);
53
static void *RotateLinePoint(LayerTypePtr, LineTypePtr, PointTypePtr);
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);
55
73
/* ----------------------------------------------------------------------
56
74
* some local identifiers
58
static Position CenterX, /* center of rotation */
60
static BYTE Number; /* number of rotations */
61
static ObjectFunctionType RotateFunctions = {
76
static LocationType CenterX, /* center of rotation */
78
static BYTE Number; /* number of rotations */
79
static ObjectFunctionType RotateFunctions = {
75
94
/* ---------------------------------------------------------------------------
76
95
* rotates a point in 90 degree steps
78
void RotatePointLowLevel(PointTypePtr Point, Position X, Position Y, BYTE Number)
98
RotatePointLowLevel (PointTypePtr Point, LocationType X, LocationType Y, BYTE Number)
80
ROTATE(Point->X, Point->Y, X, Y, Number);
100
ROTATE (Point->X, Point->Y, X, Y, Number);
83
103
/* ---------------------------------------------------------------------------
84
104
* rotates a line in 90 degree steps
86
void RotateLineLowLevel(LineTypePtr Line, Position X, Position Y, BYTE Number)
107
RotateLineLowLevel (LineTypePtr Line, LocationType X, LocationType Y, BYTE Number)
88
ROTATE(Line->Point1.X, Line->Point1.Y, X, Y, Number);
89
ROTATE(Line->Point2.X, Line->Point2.Y, X, Y, Number);
109
ROTATE (Line->Point1.X, Line->Point1.Y, X, Y, Number);
110
ROTATE (Line->Point2.X, Line->Point2.Y, X, Y, Number);
111
/* keep horizontal, vertical Point2 > Point1 */
112
if (Line->Point1.X == Line->Point2.X)
114
if (Line->Point1.Y > Line->Point2.Y)
118
Line->Point1.Y = Line->Point2.Y;
122
else if (Line->Point1.Y == Line->Point2.Y)
124
if (Line->Point1.X > Line->Point2.X)
128
Line->Point1.X = Line->Point2.X;
132
/* instead of rotating the bounding box, the call updates both end points too */
133
SetLineBoundingBox (Line);
93
136
/* ---------------------------------------------------------------------------
95
138
* only the bounding box is rotated, text rotation itself
96
139
* is done by the drawing routines
98
void RotateTextLowLevel(TextTypePtr Text, Position X, Position Y, BYTE Number)
142
RotateTextLowLevel (TextTypePtr Text, LocationType X, LocationType Y, BYTE Number)
102
number = TEST_FLAG(ONSOLDERFLAG, Text) ? (4 - Number) & 3 : Number;
103
RotateBoxLowLevel(&Text->BoundingBox, X, Y, Number);
104
ROTATE(Text->X, Text->Y, X, Y, Number);
106
/* set new direction, 0..3,
107
* 0-> to the right, 1-> straight up,
108
* 2-> to the left, 3-> straight down
110
Text->Direction = ((Text->Direction + number) & 0x03);
146
number = TEST_FLAG (ONSOLDERFLAG, Text) ? (4 - Number) & 3 : Number;
147
RotateBoxLowLevel (&Text->BoundingBox, X, Y, Number);
148
ROTATE (Text->X, Text->Y, X, Y, Number);
150
/* set new direction, 0..3,
151
* 0-> to the right, 1-> straight up,
152
* 2-> to the left, 3-> straight down
154
Text->Direction = ((Text->Direction + number) & 0x03);
113
157
/* ---------------------------------------------------------------------------
114
158
* rotates a polygon in 90 degree steps
116
void RotatePolygonLowLevel(PolygonTypePtr Polygon,
117
Position X, Position Y, BYTE Number)
161
RotatePolygonLowLevel (PolygonTypePtr Polygon,
162
LocationType X, LocationType Y, BYTE Number)
119
POLYGONPOINT_LOOP(Polygon,
120
ROTATE(point->X, point->Y, X, Y, Number);
122
RotateBoxLowLevel(&Polygon->BoundingBox, X, Y, Number);
164
POLYGONPOINT_LOOP (Polygon);
166
ROTATE (point->X, point->Y, X, Y, Number);
169
RotateBoxLowLevel (&Polygon->BoundingBox, X, Y, Number);
125
172
/* ---------------------------------------------------------------------------
126
173
* rotates a text object and redraws it
128
static void *RotateText(LayerTypePtr Layer, TextTypePtr Text)
176
RotateText (LayerTypePtr Layer, TextTypePtr Text)
131
RotateTextLowLevel(Text, CenterX, CenterY, Number);
132
DrawText(Layer, Text, 0);
179
r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
180
RotateTextLowLevel (Text, CenterX, CenterY, Number);
181
r_insert_entry (Layer->text_tree, (BoxTypePtr) Text, 0);
182
DrawText (Layer, Text, 0);
137
187
/* ---------------------------------------------------------------------------
140
void RotateArcLowLevel(ArcTypePtr Arc,
141
Position X, Position Y,
191
RotateArcLowLevel (ArcTypePtr Arc, LocationType X, LocationType Y, BYTE Number)
146
/* add Number*90 degrees to the startangle and check for overflow */
147
Arc->StartAngle = (Arc->StartAngle +Number*90) % 360;
148
ROTATE(Arc->X, Arc->Y, X, Y, Number);
150
/* now change width and height */
151
if (Number == 1 || Number == 3)
154
Arc->Width = Arc->Height;
157
SetArcBoundingBox(Arc);
195
/* add Number*90 degrees to the startangle and check for overflow */
196
Arc->StartAngle = (Arc->StartAngle + Number * 90) % 360;
197
ROTATE (Arc->X, Arc->Y, X, Y, Number);
199
/* now change width and height */
200
if (Number == 1 || Number == 3)
203
Arc->Width = Arc->Height;
206
RotateBoxLowLevel (&Arc->BoundingBox, X, Y, Number);
160
209
/* ---------------------------------------------------------------------------
161
210
* rotate an element in 90 degree steps
163
void RotateElementLowLevel(ElementTypePtr Element,
164
Position X, Position Y,
213
RotateElementLowLevel (DataTypePtr Data, ElementTypePtr Element,
214
LocationType X, LocationType Y, BYTE Number)
167
Boolean OnLayout = False;
169
ELEMENT_LOOP(PCB->Data,
170
if (element == Element)
173
/* solder side objects need a different orientation */
175
/* the text subroutine decides by itself if the direction
178
ELEMENTTEXT_LOOP(Element, RotateTextLowLevel(text, X, Y, Number));
179
ELEMENTLINE_LOOP(Element, RotateLineLowLevel(line, X, Y, Number););
181
ROTATE_PIN_LOWLEVEL(pin, X, Y, Number);
183
UpdatePIPFlags(pin, Element, NULL, NULL, True);
185
PAD_LOOP(Element, ROTATE_PAD_LOWLEVEL(pad, X, Y, Number););
186
ARC_LOOP(Element, RotateArcLowLevel(arc, X, Y, Number););
187
ROTATE(Element->MarkX, Element->MarkY, X, Y, Number);
188
RotateBoxLowLevel(&Element->BoundingBox, X, Y, Number);
216
/* solder side objects need a different orientation */
218
/* the text subroutine decides by itself if the direction
221
ELEMENTTEXT_LOOP (Element);
223
if (Data->name_tree[n])
224
r_delete_entry (Data->name_tree[n], (BoxType *) text);
225
RotateTextLowLevel (text, X, Y, Number);
228
ELEMENTLINE_LOOP (Element);
230
RotateLineLowLevel (line, X, Y, Number);
235
/* pre-delete the pins from the pin-tree before their coordinates change */
237
r_delete_entry (PCB->Data->pin_tree, (BoxType *) pin);
238
ROTATE_PIN_LOWLEVEL (pin, X, Y, Number);
239
if (PCB->Data == Data)
240
UpdatePIPFlags (pin, Element, NULL, True);
245
/* pre-delete the pads before their coordinates change */
247
r_delete_entry (PCB->Data->pad_tree, (BoxType *) pad);
248
ROTATE_PAD_LOWLEVEL (pad, X, Y, Number);
253
RotateArcLowLevel (arc, X, Y, Number);
256
ROTATE (Element->MarkX, Element->MarkY, X, Y, Number);
257
/* SetElementBoundingBox reenters the pins/pads into their trees */
258
SetElementBoundingBox (Data, Element, &PCB->Font);
191
261
/* ---------------------------------------------------------------------------
192
262
* rotates a line's point
194
static void *RotateLinePoint(LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
265
RotateLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
197
RotatePointLowLevel(Point, CenterX, CenterY, Number);
198
DrawLine(Layer, Line, 0);
269
r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
271
r_delete_entry (PCB->Data->rat_tree, (BoxTypePtr) Line);
272
RotatePointLowLevel (Point, CenterX, CenterY, Number);
273
SetLineBoundingBox (Line);
276
r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
277
DrawLine (Layer, Line, 0);
281
r_insert_entry (PCB->Data->rat_tree, (BoxTypePtr) Line, 0);
282
DrawRat ((RatTypePtr)Line, 0);
203
288
/* ---------------------------------------------------------------------------
206
static void *RotateArc(LayerTypePtr Layer, ArcTypePtr Arc)
292
RotateArc (LayerTypePtr Layer, ArcTypePtr Arc)
209
RotateArcLowLevel(Arc, CenterX, CenterY, Number);
210
DrawArc(Layer, Arc, 0);
295
r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
296
RotateArcLowLevel (Arc, CenterX, CenterY, Number);
297
r_insert_entry (Layer->arc_tree, (BoxTypePtr) Arc, 0);
298
DrawArc (Layer, Arc, 0);
215
303
/* ---------------------------------------------------------------------------
216
304
* rotates an element
218
static void *RotateElement(ElementTypePtr Element)
307
RotateElement (ElementTypePtr Element)
220
EraseElement(Element);
221
RotateElementLowLevel(Element, CenterX, CenterY, Number);
222
DrawElement(Element, 0);
309
EraseElement (Element);
310
RotateElementLowLevel (PCB->Data, Element, CenterX, CenterY, Number);
311
DrawElement (Element, 0);
227
316
/* ----------------------------------------------------------------------
228
317
* rotates the name of an element
230
static void *RotateElementName(ElementTypePtr Element)
320
RotateElementName (ElementTypePtr Element)
232
EraseElementName(Element);
233
ELEMENTTEXT_LOOP(Element, RotateTextLowLevel(text,CenterX,CenterY,Number));
234
DrawElementName(Element, 0);
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);
330
DrawElementName (Element, 0);
239
335
/* ---------------------------------------------------------------------------
240
336
* rotates a box in 90 degree steps
242
void RotateBoxLowLevel(BoxTypePtr Box,
243
Position X, Position Y, BYTE Number)
339
RotateBoxLowLevel (BoxTypePtr Box, LocationType X, LocationType Y, BYTE Number)
245
Position x1 = Box->X1,
341
LocationType x1 = Box->X1, y1 = Box->Y1, x2 = Box->X2, y2 = Box->Y2;
250
ROTATE(x1, y1, X, Y, Number);
251
ROTATE(x2, y2, X, Y, Number);
252
Box->X1 = MIN(x1, x2);
253
Box->Y1 = MIN(y1, y2);
254
Box->X2 = MAX(x1, x2);
255
Box->Y2 = MAX(y1, 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);
258
351
/* ----------------------------------------------------------------------
259
352
* rotates an objects at the cursor position as identified by its ID
260
353
* the center of rotation is determined by the current cursor location
262
void *RotateObject(int Type, void *Ptr1, void *Ptr2, void *Ptr3,
263
Position X, Position Y, BYTE Steps)
265
RubberbandTypePtr ptr;
267
Boolean changed = False;
269
/* setup default global identifiers */
274
/* move all the rubberband lines... and reset the counter */
275
ptr = Crosshair.AttachedObject.Rubberband;
276
while (Crosshair.AttachedObject.RubberbandN)
279
ptr->Line->Flags &= ~RUBBERENDFLAG;
280
AddObjectToRotateUndoList(LINEPOINT_TYPE, ptr->Layer, ptr->Line, ptr->MovedPoint,
281
CenterX, CenterY, Steps);
282
EraseLine(ptr->Line);
283
RotatePointLowLevel(ptr->MovedPoint, CenterX, CenterY, Steps);
284
DrawLine(ptr->Layer, ptr->Line, 0);
285
Crosshair.AttachedObject.RubberbandN--;
288
AddObjectToRotateUndoList(Type, Ptr1, Ptr2, Ptr3, CenterX, CenterY, Number);
289
ptr2 = ObjectOperation(&RotateFunctions, Type, Ptr1, Ptr2, Ptr3);
290
changed |= (ptr2 != NULL);
294
IncrementUndoSerialNumber();
356
RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
357
LocationType X, LocationType Y, BYTE Steps)
359
RubberbandTypePtr ptr;
361
Boolean changed = False;
363
/* setup default global identifiers */
368
/* move all the rubberband lines... and reset the counter */
369
ptr = Crosshair.AttachedObject.Rubberband;
370
while (Crosshair.AttachedObject.RubberbandN)
373
ptr->Line->Flags &= ~RUBBERENDFLAG;
374
AddObjectToRotateUndoList (LINEPOINT_TYPE, ptr->Layer, ptr->Line,
375
ptr->MovedPoint, CenterX, CenterY, Steps);
376
EraseLine (ptr->Line);
378
r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
380
r_delete_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line);
381
RotatePointLowLevel (ptr->MovedPoint, CenterX, CenterY, Steps);
382
SetLineBoundingBox (ptr->Line);
385
r_insert_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line, 0);
386
DrawLine (ptr->Layer, ptr->Line, 0);
390
r_insert_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line, 0);
391
DrawRat ((RatTypePtr) ptr->Line, 0);
393
Crosshair.AttachedObject.RubberbandN--;
396
AddObjectToRotateUndoList (Type, Ptr1, Ptr2, Ptr3, CenterX, CenterY,
398
ptr2 = ObjectOperation (&RotateFunctions, Type, Ptr1, Ptr2, Ptr3);
399
changed |= (ptr2 != NULL);
403
IncrementUndoSerialNumber ();
409
RotateScreenObject (LocationType X, LocationType Y, BYTE Steps)
412
void *ptr1, *ptr2, *ptr3;
413
if ((type = SearchScreen (X, Y, ROTATE_TYPES, &ptr1, &ptr2,
416
if (TEST_FLAG (LOCKFLAG, (ArcTypePtr) ptr2))
418
Message ("Sorry that object is locked\n");
421
Crosshair.AttachedObject.RubberbandN = 0;
422
if (TEST_FLAG (RUBBERBANDFLAG, PCB))
423
LookupRubberbandLines (type, ptr1, ptr2, ptr3);
424
if (type == ELEMENT_TYPE)
425
LookupRatLines (type, ptr1, ptr2, ptr3);
426
RotateObject (type, ptr1, ptr2, ptr3, X, Y, Steps);
427
SetChangedFlag (True);