Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / insert.c
blob5e624635e516d80907f59b141a616c95ed3e8c23
1 /* $Id$ */
3 /*
4 * COPYRIGHT
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 1994,1995,1996 Thomas Nau
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Contact addresses for paper mail and Email:
24 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
25 * Thomas.Nau@rz.uni-ulm.de
30 /* functions used to insert points into objects
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 RCSID ("$Id$");
64 /* ---------------------------------------------------------------------------
65 * some local prototypes
67 static void *InsertPointIntoLine (LayerTypePtr, LineTypePtr);
68 static void *InsertPointIntoPolygon (LayerTypePtr, PolygonTypePtr);
69 static void *InsertPointIntoRat (RatTypePtr);
71 /* ---------------------------------------------------------------------------
72 * some local identifiers
74 static LocationType InsertX, /* used by local routines as offset */
75 InsertY;
76 static Cardinal InsertAt;
77 static bool InsertLast;
78 static bool Forcible;
79 static ObjectFunctionType InsertFunctions = {
80 InsertPointIntoLine,
81 NULL,
82 InsertPointIntoPolygon,
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 InsertPointIntoRat
94 /* ---------------------------------------------------------------------------
95 * inserts a point into a rat-line
97 static void *
98 InsertPointIntoRat (RatTypePtr Rat)
100 LineTypePtr new;
102 new = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y,
103 InsertX, InsertY, Settings.LineThickness,
104 2 * Settings.Keepaway, Rat->Flags);
105 if (!new)
106 return new;
107 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, new, new);
108 EraseRat (Rat);
109 DrawLine (CURRENT, new, 0);
110 new = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y,
111 InsertX, InsertY, Settings.LineThickness,
112 2 * Settings.Keepaway, Rat->Flags);
113 if (new)
115 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, new, new);
116 DrawLine (CURRENT, new, 0);
118 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
119 Draw ();
120 return (new);
123 /* ---------------------------------------------------------------------------
124 * inserts a point into a line
126 static void *
127 InsertPointIntoLine (LayerTypePtr Layer, LineTypePtr Line)
129 LineTypePtr line;
130 LocationType X, Y;
132 if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) ||
133 ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY)))
134 return (NULL);
135 X = Line->Point2.X;
136 Y = Line->Point2.Y;
137 AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2,
138 InsertX - X, InsertY - Y);
139 EraseLine (Line);
140 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
141 Line->Point2.X = InsertX;
142 Line->Point2.Y = InsertY;
143 SetLineBoundingBox (Line);
144 r_insert_entry (Layer->line_tree, (BoxTypePtr) Line, 0);
145 DrawLine (Layer, Line, 0);
146 /* we must create after playing with Line since creation may
147 * invalidate the line pointer
149 if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY,
150 X, Y,
151 Line->Thickness, Line->Clearance,
152 Line->Flags)))
154 AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line);
155 DrawLine (Layer, line, 0);
156 /* creation call adds it to the rtree */
158 Draw ();
159 return (line);
162 /* ---------------------------------------------------------------------------
163 * inserts a point into a polygon
165 static void *
166 InsertPointIntoPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
168 PointType save;
169 Cardinal n;
170 LineType line;
172 if (!Forcible)
175 * first make sure adding the point is sensible
177 line.Thickness = 0;
178 line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
179 line.Point2 = Polygon->Points[InsertAt];
180 if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
181 return (NULL);
184 * second, shift the points up to make room for the new point
186 ErasePolygon (Polygon);
187 r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
188 save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
189 for (n = Polygon->PointN - 1; n > InsertAt; n--)
190 Polygon->Points[n] = Polygon->Points[n - 1];
192 /* Shift up indices of any holes */
193 for (n = 0; n < Polygon->HoleIndexN; n++)
194 if (Polygon->HoleIndex[n] > InsertAt ||
195 (InsertLast && Polygon->HoleIndex[n] == InsertAt))
196 Polygon->HoleIndex[n]++;
198 Polygon->Points[InsertAt] = save;
199 SetChangedFlag (true);
200 AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
201 &Polygon->Points[InsertAt]);
203 SetPolygonBoundingBox (Polygon);
204 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
205 InitClip (PCB->Data, Layer, Polygon);
206 if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
208 DrawPolygon (Layer, Polygon, 0);
209 Draw ();
211 return (&Polygon->Points[InsertAt]);
214 /* ---------------------------------------------------------------------------
215 * inserts point into objects
217 void *
218 InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3,
219 LocationType DX, LocationType DY, bool Force,
220 bool insert_last)
222 void *ptr;
224 /* setup offset */
225 InsertX = DX;
226 InsertY = DY;
227 InsertAt = *Ptr3;
228 InsertLast = insert_last;
229 Forcible = Force;
231 /* the operation insert the points to the undo-list */
232 ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3);
233 if (ptr != NULL)
234 IncrementUndoSerialNumber ();
235 return (ptr);
238 /* ---------------------------------------------------------------------------
239 * adjusts the insert point to make 45 degree lines as necessary
241 PointTypePtr
242 AdjustInsertPoint (void)
244 static PointType InsertedPoint;
245 float m;
246 LocationType x, y, dx, dy, m1, m2;
247 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
249 if (Crosshair.AttachedObject.State == STATE_FIRST)
250 return NULL;
251 Crosshair.AttachedObject.Ptr3 = &InsertedPoint;
252 if (gui->shift_is_pressed ())
254 AttachedLineType myline;
255 dx = Crosshair.X - line->Point1.X;
256 dy = Crosshair.Y - line->Point1.Y;
257 m = dx * dx + dy * dy;
258 dx = Crosshair.X - line->Point2.X;
259 dy = Crosshair.Y - line->Point2.Y;
260 /* only force 45 degree for nearest point */
261 if (m < (dx * dx + dy * dy))
262 myline.Point1 = myline.Point2 = line->Point1;
263 else
264 myline.Point1 = myline.Point2 = line->Point2;
265 FortyFiveLine (&myline);
266 InsertedPoint.X = myline.Point2.X;
267 InsertedPoint.Y = myline.Point2.Y;
268 return &InsertedPoint;
270 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
272 InsertedPoint.X = Crosshair.X;
273 InsertedPoint.Y = Crosshair.Y;
274 return &InsertedPoint;
276 dx = Crosshair.X - line->Point1.X;
277 dy = Crosshair.Y - line->Point1.Y;
278 if (!dx)
279 m1 = 2; /* 2 signals infinite slope */
280 else
282 m = (float) dy / (float) dx;
283 m1 = 0;
284 if (m > TAN_30_DEGREE)
285 m1 = (m > TAN_60_DEGREE) ? 2 : 1;
286 else if (m < -TAN_30_DEGREE)
287 m1 = (m < -TAN_60_DEGREE) ? 2 : -1;
289 dx = Crosshair.X - line->Point2.X;
290 dy = Crosshair.Y - line->Point2.Y;
291 if (!dx)
292 m2 = 2; /* 2 signals infinite slope */
293 else
295 m = (float) dy / (float) dx;
296 m2 = 0;
297 if (m > TAN_30_DEGREE)
298 m2 = (m > TAN_60_DEGREE) ? 2 : 1;
299 else if (m < -TAN_30_DEGREE)
300 m2 = (m < -TAN_60_DEGREE) ? 2 : -1;
302 if (m1 == m2)
304 InsertedPoint.X = line->Point1.X;
305 InsertedPoint.Y = line->Point1.Y;
306 return &InsertedPoint;
308 if (m1 == 2)
310 x = line->Point1.X;
311 y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X);
313 else if (m2 == 2)
315 x = line->Point2.X;
316 y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X);
318 else
320 x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X
321 - m2 * line->Point2.X) / (m1 - m2);
322 y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X
323 - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2);
325 InsertedPoint.X = x;
326 InsertedPoint.Y = y;
327 return &InsertedPoint;