pcb 4.1.1
An interactive printed circuit board layout editor.
|
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 }