pcb 4.1.1
An interactive printed circuit board layout editor.

insert.c

Go to the documentation of this file.
00001 
00033 #ifdef HAVE_CONFIG_H
00034 #include "config.h"
00035 #endif
00036 
00037 #include "global.h"
00038 
00039 #include "copy.h"
00040 #include "create.h"
00041 #include "crosshair.h"
00042 #include "data.h"
00043 #include "draw.h"
00044 #include "insert.h"
00045 #include "line.h"
00046 #include "misc.h"
00047 #include "move.h"
00048 #include "polygon.h"
00049 #include "rtree.h"
00050 #include "search.h"
00051 #include "select.h"
00052 #include "set.h"
00053 #include "undo.h"
00054 
00055 #ifdef HAVE_LIBDMALLOC
00056 #include <dmalloc.h>
00057 #endif
00058 
00059 /* ---------------------------------------------------------------------------
00060  * some local prototypes
00061  */
00062 static void *InsertPointIntoLine (LayerType *, LineType *);
00063 static void *InsertPointIntoPolygon (LayerType *, PolygonType *);
00064 static void *InsertPointIntoRat (RatType *);
00065 
00066 /* ---------------------------------------------------------------------------
00067  * some local identifiers
00068  */
00069 static Coord InsertX, InsertY;  /* used by local routines as offset */
00070 static Cardinal InsertAt;
00071 static bool InsertLast;
00072 static bool Forcible;
00073 static ObjectFunctionType InsertFunctions = {
00074   InsertPointIntoLine,
00075   NULL,
00076   InsertPointIntoPolygon,
00077   NULL,
00078   NULL,
00079   NULL,
00080   NULL,
00081   NULL,
00082   NULL,
00083   NULL,
00084   NULL,
00085   InsertPointIntoRat
00086 };
00087 
00091 static void *
00092 InsertPointIntoRat (RatType *Rat)
00093 {
00094   LineType *newone;
00095 
00096   newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y,
00097                                 InsertX, InsertY, Settings.LineThickness,
00098                                 2 * Settings.Keepaway, Rat->Flags);
00099   if (!newone)
00100     return newone;
00101   AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
00102   EraseRat (Rat);
00103   DrawLine (CURRENT, newone);
00104   newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y,
00105                                 InsertX, InsertY, Settings.LineThickness,
00106                                 2 * Settings.Keepaway, Rat->Flags);
00107   if (newone)
00108     {
00109       AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
00110       DrawLine (CURRENT, newone);
00111     }
00112   MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
00113   Draw ();
00114   return (newone);
00115 }
00116 
00120 static void *
00121 InsertPointIntoLine (LayerType *Layer, LineType *Line)
00122 {
00123   LineType *line;
00124   Coord X, Y;
00125 
00126   if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) ||
00127       ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY)))
00128     return (NULL);
00129   X = Line->Point2.X;
00130   Y = Line->Point2.Y;
00131   AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2,
00132                            InsertX - X, InsertY - Y);
00133   EraseLine (Line);
00134   r_delete_entry (Layer->line_tree, (BoxType *) Line);
00135   RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00136   Line->Point2.X = InsertX;
00137   Line->Point2.Y = InsertY;
00138   SetLineBoundingBox (Line);
00139   r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
00140   ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
00141   DrawLine (Layer, Line);
00142   /* we must create after playing with Line since creation may
00143    * invalidate the line pointer
00144    */
00145   if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY,
00146                                       X, Y,
00147                                       Line->Thickness, Line->Clearance,
00148                                       Line->Flags)))
00149     {
00150       AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line);
00151       DrawLine (Layer, line);
00152       ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, line);
00153       /* creation call adds it to the rtree */
00154     }
00155   Draw ();
00156   return (line);
00157 }
00158 
00162 static void *
00163 InsertPointIntoPolygon (LayerType *Layer, PolygonType *Polygon)
00164 {
00165   PointType save;
00166   Cardinal n;
00167   LineType line;
00168 
00169   if (!Forcible)
00170     {
00171       /*
00172        * first make sure adding the point is sensible
00173        */
00174       line.Thickness = 0;
00175       line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
00176       line.Point2 = Polygon->Points[InsertAt];
00177       if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
00178         return (NULL);
00179     }
00180   /*
00181    * second, shift the points up to make room for the new point
00182    */
00183   ErasePolygon (Polygon);
00184   r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
00185   save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
00186   for (n = Polygon->PointN - 1; n > InsertAt; n--)
00187     Polygon->Points[n] = Polygon->Points[n - 1];
00188 
00189   /* Shift up indices of any holes */
00190   for (n = 0; n < Polygon->HoleIndexN; n++)
00191     if (Polygon->HoleIndex[n] > InsertAt ||
00192         (InsertLast && Polygon->HoleIndex[n] == InsertAt))
00193       Polygon->HoleIndex[n]++;
00194 
00195   Polygon->Points[InsertAt] = save;
00196   SetChangedFlag (true);
00197   AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
00198                                   &Polygon->Points[InsertAt]);
00199 
00200   SetPolygonBoundingBox (Polygon);
00201   r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
00202   InitClip (PCB->Data, Layer, Polygon);
00203   if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
00204     {
00205       DrawPolygon (Layer, Polygon);
00206       Draw ();
00207     }
00208   return (&Polygon->Points[InsertAt]);
00209 }
00210 
00214 void *
00215 InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3,
00216                        Coord DX, Coord DY, bool Force,
00217                        bool insert_last)
00218 {
00219   void *ptr;
00220 
00221   /* setup offset */
00222   InsertX = DX;
00223   InsertY = DY;
00224   InsertAt = *Ptr3;
00225   InsertLast = insert_last;
00226   Forcible = Force;
00227 
00228   /* the operation insert the points to the undo-list */
00229   ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3);
00230   if (ptr != NULL)
00231     IncrementUndoSerialNumber ();
00232   return (ptr);
00233 }
00234 
00238 PointType *
00239 AdjustInsertPoint (void)
00240 {
00241   static PointType InsertedPoint;
00242   double m;
00243   Coord x, y, m1, m2;
00244   LineType *line = (LineType *) Crosshair.AttachedObject.Ptr2;
00245 
00246   if (Crosshair.AttachedObject.State == STATE_FIRST)
00247     return NULL;
00248   Crosshair.AttachedObject.Ptr3 = &InsertedPoint;
00249   if (gui->shift_is_pressed ())
00250     {
00251       AttachedLineType myline;
00252       /* only force 45 degree for nearest point */
00253       if (Distance (Crosshair.X, Crosshair.Y, line->Point1.X, line->Point1.Y) <
00254           Distance (Crosshair.X, Crosshair.Y, line->Point2.X, line->Point2.Y))
00255         myline.Point1 = myline.Point2 = line->Point1;
00256       else
00257         myline.Point1 = myline.Point2 = line->Point2;
00258       FortyFiveLine (&myline);
00259       InsertedPoint.X = myline.Point2.X;
00260       InsertedPoint.Y = myline.Point2.Y;
00261       return &InsertedPoint;
00262     }
00263   if (PCB->RatDraw || TEST_FLAG (ALLDIRECTIONFLAG, PCB))
00264     {
00265       InsertedPoint.X = Crosshair.X;
00266       InsertedPoint.Y = Crosshair.Y;
00267       return &InsertedPoint;
00268     }
00269   if (Crosshair.X == line->Point1.X)
00270     m1 = 2;                     /* 2 signals infinite slope */
00271   else
00272     {
00273       m = (double) (Crosshair.Y - line->Point1.Y) / (Crosshair.X - line->Point1.X);
00274       m1 = 0;
00275       if (m > TAN_30_DEGREE)
00276         m1 = (m > TAN_60_DEGREE) ? 2 : 1;
00277       else if (m < -TAN_30_DEGREE)
00278         m1 = (m < -TAN_60_DEGREE) ? 2 : -1;
00279     }
00280   if (Crosshair.X == line->Point2.X)
00281     m2 = 2;                     /* 2 signals infinite slope */
00282   else
00283     {
00284       m = (double) (Crosshair.Y - line->Point2.Y) / (Crosshair.X - line->Point2.X);
00285       m2 = 0;
00286       if (m > TAN_30_DEGREE)
00287         m2 = (m > TAN_60_DEGREE) ? 2 : 1;
00288       else if (m < -TAN_30_DEGREE)
00289         m2 = (m < -TAN_60_DEGREE) ? 2 : -1;
00290     }
00291   if (m1 == m2)
00292     {
00293       InsertedPoint.X = line->Point1.X;
00294       InsertedPoint.Y = line->Point1.Y;
00295       return &InsertedPoint;
00296     }
00297   if (m1 == 2)
00298     {
00299       x = line->Point1.X;
00300       y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X);
00301     }
00302   else if (m2 == 2)
00303     {
00304       x = line->Point2.X;
00305       y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X);
00306     }
00307   else
00308     {
00309       x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X
00310            - m2 * line->Point2.X) / (m1 - m2);
00311       y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X
00312            - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2);
00313     }
00314   InsertedPoint.X = x;
00315   InsertedPoint.Y = y;
00316   return &InsertedPoint;
00317 }