pcb 4.1.1
An interactive printed circuit board layout editor.

rotate.c

Go to the documentation of this file.
00001 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #include <stdlib.h>
00041 
00042 #include "global.h"
00043 
00044 #include "crosshair.h"
00045 #include "data.h"
00046 #include "draw.h"
00047 #include "error.h"
00048 #include "misc.h"
00049 #include "polygon.h"
00050 #include "rotate.h"
00051 #include "rtree.h"
00052 #include "rubberband.h"
00053 #include "search.h"
00054 #include "select.h"
00055 #include "set.h"
00056 #include "undo.h"
00057 
00058 #ifdef HAVE_LIBDMALLOC
00059 #include <dmalloc.h>
00060 #endif
00061 
00062 /* ---------------------------------------------------------------------------
00063  * some local prototypes
00064  */
00065 static void *RotateText (LayerType *, TextType *);
00066 static void *RotateArc (LayerType *, ArcType *);
00067 static void *RotateElement (ElementType *);
00068 static void *RotateElementName (ElementType *);
00069 static void *RotateLinePoint (LayerType *, LineType *, PointType *);
00070 
00071 /* ----------------------------------------------------------------------
00072  * some local identifiers
00073  */
00074 static Coord CenterX, CenterY;  /* center of rotation */
00075 static unsigned Number;         /* number of rotations */
00076 static ObjectFunctionType RotateFunctions = {
00077   NULL,
00078   RotateText,
00079   NULL,
00080   NULL,
00081   RotateElement,
00082   RotateElementName,
00083   NULL,
00084   NULL,
00085   RotateLinePoint,
00086   NULL,
00087   RotateArc,
00088   NULL
00089 };
00090 
00094 void
00095 RotatePointLowLevel (PointType *Point, Coord X, Coord Y, unsigned Number)
00096 {
00097   ROTATE (Point->X, Point->Y, X, Y, Number);
00098 }
00099 
00103 void
00104 RotateLineLowLevel (LineType *Line, Coord X, Coord Y, unsigned Number)
00105 {
00106   ROTATE (Line->Point1.X, Line->Point1.Y, X, Y, Number);
00107   ROTATE (Line->Point2.X, Line->Point2.Y, X, Y, Number);
00108   /* keep horizontal, vertical Point2 > Point1 */
00109   if (Line->Point1.X == Line->Point2.X)
00110     {
00111       if (Line->Point1.Y > Line->Point2.Y)
00112         {
00113           Coord t;
00114           t = Line->Point1.Y;
00115           Line->Point1.Y = Line->Point2.Y;
00116           Line->Point2.Y = t;
00117         }
00118     }
00119   else if (Line->Point1.Y == Line->Point2.Y)
00120     {
00121       if (Line->Point1.X > Line->Point2.X)
00122         {
00123           Coord t;
00124           t = Line->Point1.X;
00125           Line->Point1.X = Line->Point2.X;
00126           Line->Point2.X = t;
00127         }
00128     }
00129   /* instead of rotating the bounding box, the call updates both end points too */
00130   SetLineBoundingBox (Line);
00131 }
00132 
00139 void
00140 RotateTextLowLevel (TextType *Text, Coord X, Coord Y, unsigned Number)
00141 {
00142   BYTE number;
00143 
00144   number = TEST_FLAG (ONSOLDERFLAG, Text) ? (4 - Number) & 3 : Number;
00145   RotateBoxLowLevel (&Text->BoundingBox, X, Y, Number);
00146   ROTATE (Text->X, Text->Y, X, Y, Number);
00147 
00148   /* set new direction, 0..3,
00149    * 0-> to the right, 1-> straight up,
00150    * 2-> to the left, 3-> straight down
00151    */
00152   Text->Direction = ((Text->Direction + number) & 0x03);
00153 }
00154 
00158 void
00159 RotatePolygonLowLevel (PolygonType *Polygon, Coord X, Coord Y, unsigned Number)
00160 {
00161   POLYGONPOINT_LOOP (Polygon);
00162   {
00163     ROTATE (point->X, point->Y, X, Y, Number);
00164   }
00165   END_LOOP;
00166   RotateBoxLowLevel (&Polygon->BoundingBox, X, Y, Number);
00167 }
00168 
00172 static void *
00173 RotateText (LayerType *Layer, TextType *Text)
00174 {
00175   EraseText (Layer, Text);
00176   RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
00177   r_delete_entry (Layer->text_tree, (BoxType *) Text);
00178   RotateTextLowLevel (Text, CenterX, CenterY, Number);
00179   r_insert_entry (Layer->text_tree, (BoxType *) Text, 0);
00180   ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text);
00181   DrawText (Layer, Text);
00182   Draw ();
00183   return (Text);
00184 }
00185 
00189 void
00190 RotateArcLowLevel (ArcType *Arc, Coord X, Coord Y, unsigned Number)
00191 {
00192   Coord save;
00193 
00194   /* add Number*90 degrees (i.e., Number quarter-turns) */
00195   Arc->StartAngle = NormalizeAngle (Arc->StartAngle + Number * 90);
00196   ROTATE (Arc->X, Arc->Y, X, Y, Number);
00197 
00198   /* now change width and height */
00199   if (Number == 1 || Number == 3)
00200     {
00201       save = Arc->Width;
00202       Arc->Width = Arc->Height;
00203       Arc->Height = save;
00204     }
00205   RotateBoxLowLevel (&Arc->BoundingBox, X, Y, Number);
00206   ROTATE (Arc->Point1.X, Arc->Point1.Y, X, Y, Number);
00207   ROTATE (Arc->Point2.X, Arc->Point2.Y, X, Y, Number);
00208 }
00209 
00213 void
00214 RotateElementLowLevel (DataType *Data, ElementType *Element,
00215                        Coord X, Coord Y, unsigned Number)
00216 {
00217   /* solder side objects need a different orientation */
00218 
00219   /* the text subroutine decides by itself if the direction
00220    * is to be corrected
00221    */
00222   ELEMENTTEXT_LOOP (Element);
00223   {
00224     if (Data && Data->name_tree[n])
00225       r_delete_entry (Data->name_tree[n], (BoxType *) text);
00226     RotateTextLowLevel (text, X, Y, Number);
00227   }
00228   END_LOOP;
00229   ELEMENTLINE_LOOP (Element);
00230   {
00231     RotateLineLowLevel (line, X, Y, Number);
00232   }
00233   END_LOOP;
00234   PIN_LOOP (Element);
00235   {
00236     /* pre-delete the pins from the pin-tree before their coordinates change */
00237     if (Data)
00238       r_delete_entry (Data->pin_tree, (BoxType *) pin);
00239     RestoreToPolygon (Data, PIN_TYPE, Element, pin);
00240     ROTATE_PIN_LOWLEVEL (pin, X, Y, Number);
00241   }
00242   END_LOOP;
00243   PAD_LOOP (Element);
00244   {
00245     /* pre-delete the pads before their coordinates change */
00246     if (Data)
00247       r_delete_entry (Data->pad_tree, (BoxType *) pad);
00248     RestoreToPolygon (Data, PAD_TYPE, Element, pad);
00249     ROTATE_PAD_LOWLEVEL (pad, X, Y, Number);
00250   }
00251   END_LOOP;
00252   ARC_LOOP (Element);
00253   {
00254     RotateArcLowLevel (arc, X, Y, Number);
00255   }
00256   END_LOOP;
00257   ROTATE (Element->MarkX, Element->MarkY, X, Y, Number);
00258   /* SetElementBoundingBox reenters the rtree data */
00259   SetElementBoundingBox (Data, Element, &PCB->Font);
00260   ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element);
00261 }
00262 
00266 static void *
00267 RotateLinePoint (LayerType *Layer, LineType *Line, PointType *Point)
00268 {
00269   EraseLine (Line);
00270   if (Layer)
00271     {
00272       RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00273       r_delete_entry (Layer->line_tree, (BoxType *) Line);
00274     }
00275   else
00276     r_delete_entry (PCB->Data->rat_tree, (BoxType *) Line);
00277   RotatePointLowLevel (Point, CenterX, CenterY, Number);
00278   SetLineBoundingBox (Line);
00279   if (Layer)
00280     {
00281       r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
00282       ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00283       DrawLine (Layer, Line);
00284     }
00285   else
00286     {
00287       r_insert_entry (PCB->Data->rat_tree, (BoxType *) Line, 0);
00288       DrawRat ((RatType *) Line);
00289     }
00290   Draw ();
00291   return (Line);
00292 }
00293 
00297 static void *
00298 RotateArc (LayerType *Layer, ArcType *Arc)
00299 {
00300   EraseArc (Arc);
00301   r_delete_entry (Layer->arc_tree, (BoxType *) Arc);
00302   RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
00303   RotateArcLowLevel (Arc, CenterX, CenterY, Number);
00304   r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0);
00305   ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc);
00306 
00307   DrawArc (Layer, Arc);
00308   Draw ();
00309   return (Arc);
00310 }
00311 
00315 static void *
00316 RotateElement (ElementType *Element)
00317 {
00318   EraseElement (Element);
00319   RotateElementLowLevel (PCB->Data, Element, CenterX, CenterY, Number);
00320   DrawElement (Element);
00321   Draw ();
00322   return (Element);
00323 }
00324 
00328 static void *
00329 RotateElementName (ElementType *Element)
00330 {
00331   EraseElementName (Element);
00332   ELEMENTTEXT_LOOP (Element);
00333   {
00334     r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text);
00335     RotateTextLowLevel (text, CenterX, CenterY, Number);
00336     r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0);
00337   }
00338   END_LOOP;
00339   DrawElementName (Element);
00340   Draw ();
00341   return (Element);
00342 }
00343 
00347 void
00348 RotateBoxLowLevel (BoxType *Box, Coord X, Coord Y, unsigned Number)
00349 {
00350   Coord x1 = Box->X1, y1 = Box->Y1, x2 = Box->X2, y2 = Box->Y2;
00351 
00352   ROTATE (x1, y1, X, Y, Number);
00353   ROTATE (x2, y2, X, Y, Number);
00354   Box->X1 = MIN (x1, x2);
00355   Box->Y1 = MIN (y1, y2);
00356   Box->X2 = MAX (x1, x2);
00357   Box->Y2 = MAX (y1, y2);
00358 }
00359 
00366 void *
00367 RotateObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3,
00368               Coord X, Coord Y, unsigned Steps)
00369 {
00370   RubberbandType *ptr;
00371   void *ptr2;
00372   bool changed = false;
00373 
00374   /* setup default  global identifiers */
00375   Number = Steps;
00376   CenterX = X;
00377   CenterY = Y;
00378 
00379   /* move all the rubberband lines... and reset the counter */
00380   ptr = Crosshair.AttachedObject.Rubberband;
00381   while (Crosshair.AttachedObject.RubberbandN)
00382     {
00383       changed = true;
00384       CLEAR_FLAG (RUBBERENDFLAG, ptr->Line);
00385       AddObjectToRotateUndoList (LINEPOINT_TYPE, ptr->Layer, ptr->Line,
00386                                  ptr->MovedPoint, CenterX, CenterY, Steps);
00387       EraseLine (ptr->Line);
00388       if (ptr->Layer)
00389         {
00390           RestoreToPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
00391           r_delete_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line);
00392         }
00393       else
00394         r_delete_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line);
00395       RotatePointLowLevel (ptr->MovedPoint, CenterX, CenterY, Steps);
00396       SetLineBoundingBox (ptr->Line);
00397       if (ptr->Layer)
00398         {
00399           r_insert_entry (ptr->Layer->line_tree, (BoxType *) ptr->Line, 0);
00400           ClearFromPolygon (PCB->Data, LINE_TYPE, ptr->Layer, ptr->Line);
00401           DrawLine (ptr->Layer, ptr->Line);
00402         }
00403       else
00404         {
00405           r_insert_entry (PCB->Data->rat_tree, (BoxType *) ptr->Line, 0);
00406           DrawRat ((RatType *) ptr->Line);
00407         }
00408       Crosshair.AttachedObject.RubberbandN--;
00409       ptr++;
00410     }
00411   AddObjectToRotateUndoList (Type, Ptr1, Ptr2, Ptr3, CenterX, CenterY,
00412                              Number);
00413   ptr2 = ObjectOperation (&RotateFunctions, Type, Ptr1, Ptr2, Ptr3);
00414   changed |= (ptr2 != NULL);
00415   if (changed)
00416     {
00417       Draw ();
00418       IncrementUndoSerialNumber ();
00419     }
00420   return (ptr2);
00421 }
00422 
00423 void
00424 RotateScreenObject (Coord X, Coord Y, unsigned Steps)
00425 {
00426   int type;
00427   void *ptr1, *ptr2, *ptr3;
00428   if ((type = SearchScreen (X, Y, ROTATE_TYPES, &ptr1, &ptr2,
00429                             &ptr3)) != NO_TYPE)
00430     {
00431       if (TEST_FLAG (LOCKFLAG, (ArcType *) ptr2))
00432         {
00433           Message (_("Sorry, the object is locked\n"));
00434           return;
00435         }
00436       Crosshair.AttachedObject.RubberbandN = 0;
00437       if (TEST_FLAG (RUBBERBANDFLAG, PCB))
00438         LookupRubberbandLines (type, ptr1, ptr2, ptr3);
00439       if (type == ELEMENT_TYPE)
00440         LookupRatLines (type, ptr1, ptr2, ptr3);
00441       RotateObject (type, ptr1, ptr2, ptr3, X, Y, Steps);
00442       SetChangedFlag (true);
00443     }
00444 }