More stackup changes
[geda-pcb/pcjc2/v2.git] / src / insert.c
blobedacd04714f91acf2cb9f24fe4e74099e622d7c8
1 /*!
2 * \file src/insert.c
4 * \brief Functions used to insert points into objects.
6 * <hr>
8 * <h1><b>Copyright.</b></h1>\n
10 * PCB, interactive printed circuit board design
11 * Copyright (C) 1994,1995,1996 Thomas Nau
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * Contact addresses for paper mail and Email:
28 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
29 * Thomas.Nau@rz.uni-ulm.de
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include "global.h"
39 #include "copy.h"
40 #include "create.h"
41 #include "crosshair.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "insert.h"
45 #include "line.h"
46 #include "misc.h"
47 #include "move.h"
48 #include "polygon.h"
49 #include "rtree.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 /* ---------------------------------------------------------------------------
60 * some local prototypes
62 static void *InsertPointIntoLine (LayerType *, LineType *);
63 static void *InsertPointIntoPolygon (LayerType *, PolygonType *);
64 static void *InsertPointIntoRat (RatType *);
66 /* ---------------------------------------------------------------------------
67 * some local identifiers
69 static Coord InsertX, InsertY; /* used by local routines as offset */
70 static Angle InsertIncludedAngle; /* Only used by polygon point insert */
71 static Cardinal InsertAt;
72 static bool InsertLast;
73 static bool Forcible;
74 static ObjectFunctionType InsertFunctions = {
75 InsertPointIntoLine,
76 NULL,
77 InsertPointIntoPolygon,
78 NULL,
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 InsertPointIntoRat
89 /*!
90 * \brief Inserts a point into a rat-line.
92 static void *
93 InsertPointIntoRat (RatType *Rat)
95 LineType *newone;
97 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y,
98 InsertX, InsertY, Settings.LineThickness,
99 2 * Settings.Keepaway, Rat->Flags);
100 if (!newone)
101 return newone;
102 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
103 EraseRat (Rat);
104 DrawLine (CURRENT, newone);
105 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y,
106 InsertX, InsertY, Settings.LineThickness,
107 2 * Settings.Keepaway, Rat->Flags);
108 if (newone)
110 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
111 DrawLine (CURRENT, newone);
113 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
114 Draw ();
115 return (newone);
119 * \brief Inserts a point into a line.
121 static void *
122 InsertPointIntoLine (LayerType *Layer, LineType *Line)
124 LineType *line;
125 Coord X, Y;
127 if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) ||
128 ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY)))
129 return (NULL);
130 X = Line->Point2.X;
131 Y = Line->Point2.Y;
132 AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2,
133 InsertX - X, InsertY - Y);
134 EraseLine (Line);
135 r_delete_entry (Layer->line_tree, (BoxType *) Line);
136 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
137 Line->Point2.X = InsertX;
138 Line->Point2.Y = InsertY;
139 SetLineBoundingBox (Line);
140 r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
141 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
142 DrawLine (Layer, Line);
143 /* we must create after playing with Line since creation may
144 * invalidate the line pointer
146 if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY,
147 X, Y,
148 Line->Thickness, Line->Clearance,
149 Line->Flags)))
151 AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line);
152 DrawLine (Layer, line);
153 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, line);
154 /* creation call adds it to the rtree */
156 Draw ();
157 return (line);
161 * \brief Inserts a point into a polygon.
163 static void *
164 InsertPointIntoPolygon (LayerType *Layer, PolygonType *Polygon)
166 PointType save;
167 Cardinal n;
168 LineType line;
170 if (!Forcible)
173 * first make sure adding the point is sensible
175 line.Thickness = 0;
176 line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
177 line.Point2 = Polygon->Points[InsertAt];
178 if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
179 return (NULL);
182 * second, shift the points up to make room for the new point
184 ErasePolygon (Polygon);
185 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
186 save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY, InsertIncludedAngle);
187 for (n = Polygon->PointN - 1; n > InsertAt; n--)
188 Polygon->Points[n] = Polygon->Points[n - 1];
190 /* Shift up indices of any holes */
191 for (n = 0; n < Polygon->HoleIndexN; n++)
192 if (Polygon->HoleIndex[n] > InsertAt ||
193 (InsertLast && Polygon->HoleIndex[n] == InsertAt))
194 Polygon->HoleIndex[n]++;
196 Polygon->Points[InsertAt] = save;
197 SetChangedFlag (true);
198 AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
199 &Polygon->Points[InsertAt]);
201 SetPolygonBoundingBox (Polygon);
202 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
203 InitClip (PCB->Data, Layer, Polygon);
204 if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
206 DrawPolygon (Layer, Polygon);
207 Draw ();
209 return (&Polygon->Points[InsertAt]);
213 * \brief Inserts point into objects.
215 void *
216 InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3,
217 Coord DX, Coord DY, Angle included_angle, bool Force,
218 bool insert_last)
220 void *ptr;
222 /* setup offset */
223 InsertX = DX;
224 InsertY = DY;
225 InsertIncludedAngle = included_angle;
226 InsertAt = *Ptr3;
227 InsertLast = insert_last;
228 Forcible = Force;
230 /* the operation insert the points to the undo-list */
231 ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3);
232 if (ptr != NULL)
233 IncrementUndoSerialNumber ();
234 return (ptr);
238 * \brief Adjusts the insert point to make 45 degree lines as necessary.
240 PointType *
241 AdjustInsertPoint (void)
243 static PointType InsertedPoint;
244 double m;
245 Coord x, y, m1, m2;
246 LineType *line = (LineType *) Crosshair.AttachedObject.Ptr2;
248 if (Crosshair.AttachedObject.State == STATE_FIRST)
249 return NULL;
250 Crosshair.AttachedObject.Ptr3 = &InsertedPoint;
251 if (gui->shift_is_pressed ())
253 AttachedLineType myline;
254 /* only force 45 degree for nearest point */
255 if (Distance (Crosshair.X, Crosshair.Y, line->Point1.X, line->Point1.Y) <
256 Distance (Crosshair.X, Crosshair.Y, line->Point2.X, line->Point2.Y))
257 myline.Point1 = myline.Point2 = line->Point1;
258 else
259 myline.Point1 = myline.Point2 = line->Point2;
260 FortyFiveLine (&myline);
261 InsertedPoint.X = myline.Point2.X;
262 InsertedPoint.Y = myline.Point2.Y;
263 return &InsertedPoint;
265 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
267 InsertedPoint.X = Crosshair.X;
268 InsertedPoint.Y = Crosshair.Y;
269 return &InsertedPoint;
271 if (Crosshair.X == line->Point1.X)
272 m1 = 2; /* 2 signals infinite slope */
273 else
275 m = (double) (Crosshair.Y - line->Point1.Y) / (Crosshair.X - line->Point1.X);
276 m1 = 0;
277 if (m > TAN_30_DEGREE)
278 m1 = (m > TAN_60_DEGREE) ? 2 : 1;
279 else if (m < -TAN_30_DEGREE)
280 m1 = (m < -TAN_60_DEGREE) ? 2 : -1;
282 if (Crosshair.X == line->Point2.X)
283 m2 = 2; /* 2 signals infinite slope */
284 else
286 m = (double) (Crosshair.Y - line->Point2.Y) / (Crosshair.X - line->Point2.X);
287 m2 = 0;
288 if (m > TAN_30_DEGREE)
289 m2 = (m > TAN_60_DEGREE) ? 2 : 1;
290 else if (m < -TAN_30_DEGREE)
291 m2 = (m < -TAN_60_DEGREE) ? 2 : -1;
293 if (m1 == m2)
295 InsertedPoint.X = line->Point1.X;
296 InsertedPoint.Y = line->Point1.Y;
297 return &InsertedPoint;
299 if (m1 == 2)
301 x = line->Point1.X;
302 y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X);
304 else if (m2 == 2)
306 x = line->Point2.X;
307 y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X);
309 else
311 x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X
312 - m2 * line->Point2.X) / (m1 - m2);
313 y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X
314 - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2);
316 InsertedPoint.X = x;
317 InsertedPoint.Y = y;
318 return &InsertedPoint;