Repopulate route style selector on PCBChanged action
[geda-pcb/whiteaudio.git] / src / insert.c
blob514754fb68c59c95f904c5e28803fb70ed80f63b
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 Coord InsertX, InsertY; /* used by local routines as offset */
75 static Cardinal InsertAt;
76 static bool InsertLast;
77 static bool Forcible;
78 static ObjectFunctionType InsertFunctions = {
79 InsertPointIntoLine,
80 NULL,
81 InsertPointIntoPolygon,
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 NULL,
89 NULL,
90 InsertPointIntoRat
93 /* ---------------------------------------------------------------------------
94 * inserts a point into a rat-line
96 static void *
97 InsertPointIntoRat (RatTypePtr Rat)
99 LineTypePtr newone;
101 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y,
102 InsertX, InsertY, Settings.LineThickness,
103 2 * Settings.Keepaway, Rat->Flags);
104 if (!newone)
105 return newone;
106 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
107 EraseRat (Rat);
108 DrawLine (CURRENT, newone);
109 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y,
110 InsertX, InsertY, Settings.LineThickness,
111 2 * Settings.Keepaway, Rat->Flags);
112 if (newone)
114 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
115 DrawLine (CURRENT, newone);
117 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
118 Draw ();
119 return (newone);
122 /* ---------------------------------------------------------------------------
123 * inserts a point into a line
125 static void *
126 InsertPointIntoLine (LayerTypePtr Layer, LineTypePtr Line)
128 LineTypePtr line;
129 Coord X, Y;
131 if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) ||
132 ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY)))
133 return (NULL);
134 X = Line->Point2.X;
135 Y = Line->Point2.Y;
136 AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2,
137 InsertX - X, InsertY - Y);
138 EraseLine (Line);
139 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
140 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, 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 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
146 DrawLine (Layer, Line);
147 /* we must create after playing with Line since creation may
148 * invalidate the line pointer
150 if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY,
151 X, Y,
152 Line->Thickness, Line->Clearance,
153 Line->Flags)))
155 AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line);
156 DrawLine (Layer, line);
157 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, line);
158 /* creation call adds it to the rtree */
160 Draw ();
161 return (line);
164 /* ---------------------------------------------------------------------------
165 * inserts a point into a polygon
167 static void *
168 InsertPointIntoPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
170 PointType save;
171 Cardinal n;
172 LineType line;
174 if (!Forcible)
177 * first make sure adding the point is sensible
179 line.Thickness = 0;
180 line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
181 line.Point2 = Polygon->Points[InsertAt];
182 if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
183 return (NULL);
186 * second, shift the points up to make room for the new point
188 ErasePolygon (Polygon);
189 r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
190 save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
191 for (n = Polygon->PointN - 1; n > InsertAt; n--)
192 Polygon->Points[n] = Polygon->Points[n - 1];
194 /* Shift up indices of any holes */
195 for (n = 0; n < Polygon->HoleIndexN; n++)
196 if (Polygon->HoleIndex[n] > InsertAt ||
197 (InsertLast && Polygon->HoleIndex[n] == InsertAt))
198 Polygon->HoleIndex[n]++;
200 Polygon->Points[InsertAt] = save;
201 SetChangedFlag (true);
202 AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
203 &Polygon->Points[InsertAt]);
205 SetPolygonBoundingBox (Polygon);
206 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
207 InitClip (PCB->Data, Layer, Polygon);
208 if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
210 DrawPolygon (Layer, Polygon);
211 Draw ();
213 return (&Polygon->Points[InsertAt]);
216 /* ---------------------------------------------------------------------------
217 * inserts point into objects
219 void *
220 InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3,
221 Coord DX, Coord DY, bool Force,
222 bool insert_last)
224 void *ptr;
226 /* setup offset */
227 InsertX = DX;
228 InsertY = DY;
229 InsertAt = *Ptr3;
230 InsertLast = insert_last;
231 Forcible = Force;
233 /* the operation insert the points to the undo-list */
234 ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3);
235 if (ptr != NULL)
236 IncrementUndoSerialNumber ();
237 return (ptr);
240 /* ---------------------------------------------------------------------------
241 * adjusts the insert point to make 45 degree lines as necessary
243 PointTypePtr
244 AdjustInsertPoint (void)
246 static PointType InsertedPoint;
247 double m;
248 Coord x, y, m1, m2;
249 LineTypePtr line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
251 if (Crosshair.AttachedObject.State == STATE_FIRST)
252 return NULL;
253 Crosshair.AttachedObject.Ptr3 = &InsertedPoint;
254 if (gui->shift_is_pressed ())
256 AttachedLineType myline;
257 /* only force 45 degree for nearest point */
258 if (Distance (Crosshair.X, Crosshair.Y, line->Point1.X, line->Point1.Y) <
259 Distance (Crosshair.X, Crosshair.Y, line->Point2.X, line->Point2.Y))
260 myline.Point1 = myline.Point2 = line->Point1;
261 else
262 myline.Point1 = myline.Point2 = line->Point2;
263 FortyFiveLine (&myline);
264 InsertedPoint.X = myline.Point2.X;
265 InsertedPoint.Y = myline.Point2.Y;
266 return &InsertedPoint;
268 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
270 InsertedPoint.X = Crosshair.X;
271 InsertedPoint.Y = Crosshair.Y;
272 return &InsertedPoint;
274 if (Crosshair.X == line->Point1.X)
275 m1 = 2; /* 2 signals infinite slope */
276 else
278 m = (double) (Crosshair.X - line->Point1.X) / (Crosshair.Y - line->Point1.Y);
279 m1 = 0;
280 if (m > TAN_30_DEGREE)
281 m1 = (m > TAN_60_DEGREE) ? 2 : 1;
282 else if (m < -TAN_30_DEGREE)
283 m1 = (m < -TAN_60_DEGREE) ? 2 : -1;
285 if (Crosshair.X == line->Point2.X)
286 m2 = 2; /* 2 signals infinite slope */
287 else
289 m = (double) (Crosshair.X - line->Point1.X) / (Crosshair.Y - line->Point1.Y);
290 m2 = 0;
291 if (m > TAN_30_DEGREE)
292 m2 = (m > TAN_60_DEGREE) ? 2 : 1;
293 else if (m < -TAN_30_DEGREE)
294 m2 = (m < -TAN_60_DEGREE) ? 2 : -1;
296 if (m1 == m2)
298 InsertedPoint.X = line->Point1.X;
299 InsertedPoint.Y = line->Point1.Y;
300 return &InsertedPoint;
302 if (m1 == 2)
304 x = line->Point1.X;
305 y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X);
307 else if (m2 == 2)
309 x = line->Point2.X;
310 y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X);
312 else
314 x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X
315 - m2 * line->Point2.X) / (m1 - m2);
316 y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X
317 - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2);
319 InsertedPoint.X = x;
320 InsertedPoint.Y = y;
321 return &InsertedPoint;