(no commit message)
[geda-pcb/pcjc2.git] / src / insert.c
bloba254998b275ebb96461466a1a64de194383365c6
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
28 /* functions used to insert points into objects
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
35 #include "global.h"
37 #include "copy.h"
38 #include "create.h"
39 #include "crosshair.h"
40 #include "data.h"
41 #include "draw.h"
42 #include "insert.h"
43 #include "line.h"
44 #include "misc.h"
45 #include "move.h"
46 #include "polygon.h"
47 #include "rtree.h"
48 #include "search.h"
49 #include "select.h"
50 #include "set.h"
51 #include "undo.h"
53 #ifdef HAVE_LIBDMALLOC
54 #include <dmalloc.h>
55 #endif
57 /* ---------------------------------------------------------------------------
58 * some local prototypes
60 static void *InsertPointIntoLine (LayerType *, LineType *);
61 static void *InsertPointIntoPolygon (LayerType *, PolygonType *);
62 static void *InsertPointIntoRat (RatType *);
64 /* ---------------------------------------------------------------------------
65 * some local identifiers
67 static Coord InsertX, InsertY; /* used by local routines as offset */
68 static Cardinal InsertAt;
69 static bool InsertLast;
70 static bool Forcible;
71 static ObjectFunctionType InsertFunctions = {
72 InsertPointIntoLine,
73 NULL,
74 InsertPointIntoPolygon,
75 NULL,
76 NULL,
77 NULL,
78 NULL,
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 InsertPointIntoRat
86 /* ---------------------------------------------------------------------------
87 * inserts a point into a rat-line
89 static void *
90 InsertPointIntoRat (RatType *Rat)
92 LineType *newone;
94 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y,
95 InsertX, InsertY, Settings.LineThickness,
96 2 * Settings.Keepaway, Rat->Flags);
97 if (!newone)
98 return newone;
99 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
100 EraseRat (Rat);
101 DrawLine (CURRENT, newone);
102 newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y,
103 InsertX, InsertY, Settings.LineThickness,
104 2 * Settings.Keepaway, Rat->Flags);
105 if (newone)
107 AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone);
108 DrawLine (CURRENT, newone);
110 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
111 Draw ();
112 return (newone);
115 /* ---------------------------------------------------------------------------
116 * inserts a point into a line
118 static void *
119 InsertPointIntoLine (LayerType *Layer, LineType *Line)
121 LineType *line;
122 Coord X, Y;
124 if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) ||
125 ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY)))
126 return (NULL);
127 X = Line->Point2.X;
128 Y = Line->Point2.Y;
129 AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2,
130 InsertX - X, InsertY - Y);
131 EraseLine (Line);
132 r_delete_entry (Layer->line_tree, (BoxType *) Line);
133 RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line);
134 Line->Point2.X = InsertX;
135 Line->Point2.Y = InsertY;
136 SetLineBoundingBox (Line);
137 r_insert_entry (Layer->line_tree, (BoxType *) Line, 0);
138 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line);
139 DrawLine (Layer, Line);
140 /* we must create after playing with Line since creation may
141 * invalidate the line pointer
143 if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY,
144 X, Y,
145 Line->Thickness, Line->Clearance,
146 Line->Flags)))
148 AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line);
149 DrawLine (Layer, line);
150 ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, line);
151 /* creation call adds it to the rtree */
153 Draw ();
154 return (line);
157 /* ---------------------------------------------------------------------------
158 * inserts a point into a polygon
160 static void *
161 InsertPointIntoPolygon (LayerType *Layer, PolygonType *Polygon)
163 PointType save;
164 Cardinal n;
165 LineType line;
167 if (!Forcible)
170 * first make sure adding the point is sensible
172 line.Thickness = 0;
173 line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)];
174 line.Point2 = Polygon->Points[InsertAt];
175 if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line))
176 return (NULL);
179 * second, shift the points up to make room for the new point
181 ErasePolygon (Polygon);
182 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
183 save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY);
184 for (n = Polygon->PointN - 1; n > InsertAt; n--)
185 Polygon->Points[n] = Polygon->Points[n - 1];
187 /* Shift up indices of any holes */
188 for (n = 0; n < Polygon->HoleIndexN; n++)
189 if (Polygon->HoleIndex[n] > InsertAt ||
190 (InsertLast && Polygon->HoleIndex[n] == InsertAt))
191 Polygon->HoleIndex[n]++;
193 Polygon->Points[InsertAt] = save;
194 SetChangedFlag (true);
195 AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon,
196 &Polygon->Points[InsertAt]);
198 SetPolygonBoundingBox (Polygon);
199 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
200 InitClip (PCB->Data, Layer, Polygon);
201 if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon))
203 DrawPolygon (Layer, Polygon);
204 Draw ();
206 return (&Polygon->Points[InsertAt]);
209 /* ---------------------------------------------------------------------------
210 * inserts point into objects
212 void *
213 InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3,
214 Coord DX, Coord DY, bool Force,
215 bool insert_last)
217 void *ptr;
219 /* setup offset */
220 InsertX = DX;
221 InsertY = DY;
222 InsertAt = *Ptr3;
223 InsertLast = insert_last;
224 Forcible = Force;
226 /* the operation insert the points to the undo-list */
227 ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3);
228 if (ptr != NULL)
229 IncrementUndoSerialNumber ();
230 return (ptr);
233 /* ---------------------------------------------------------------------------
234 * adjusts the insert point to make 45 degree lines as necessary
236 PointType *
237 AdjustInsertPoint (void)
239 static PointType InsertedPoint;
240 double m;
241 Coord x, y, m1, m2;
242 LineType *line = (LineType *) Crosshair.AttachedObject.Ptr2;
244 if (Crosshair.AttachedObject.State == STATE_FIRST)
245 return NULL;
246 Crosshair.AttachedObject.Ptr3 = &InsertedPoint;
247 if (gui->shift_is_pressed ())
249 AttachedLineType myline;
250 /* only force 45 degree for nearest point */
251 if (Distance (Crosshair.X, Crosshair.Y, line->Point1.X, line->Point1.Y) <
252 Distance (Crosshair.X, Crosshair.Y, line->Point2.X, line->Point2.Y))
253 myline.Point1 = myline.Point2 = line->Point1;
254 else
255 myline.Point1 = myline.Point2 = line->Point2;
256 FortyFiveLine (&myline);
257 InsertedPoint.X = myline.Point2.X;
258 InsertedPoint.Y = myline.Point2.Y;
259 return &InsertedPoint;
261 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
263 InsertedPoint.X = Crosshair.X;
264 InsertedPoint.Y = Crosshair.Y;
265 return &InsertedPoint;
267 if (Crosshair.X == line->Point1.X)
268 m1 = 2; /* 2 signals infinite slope */
269 else
271 m = (double) (Crosshair.Y - line->Point1.Y) / (Crosshair.X - line->Point1.X);
272 m1 = 0;
273 if (m > TAN_30_DEGREE)
274 m1 = (m > TAN_60_DEGREE) ? 2 : 1;
275 else if (m < -TAN_30_DEGREE)
276 m1 = (m < -TAN_60_DEGREE) ? 2 : -1;
278 if (Crosshair.X == line->Point2.X)
279 m2 = 2; /* 2 signals infinite slope */
280 else
282 m = (double) (Crosshair.Y - line->Point2.Y) / (Crosshair.X - line->Point2.X);
283 m2 = 0;
284 if (m > TAN_30_DEGREE)
285 m2 = (m > TAN_60_DEGREE) ? 2 : 1;
286 else if (m < -TAN_30_DEGREE)
287 m2 = (m < -TAN_60_DEGREE) ? 2 : -1;
289 if (m1 == m2)
291 InsertedPoint.X = line->Point1.X;
292 InsertedPoint.Y = line->Point1.Y;
293 return &InsertedPoint;
295 if (m1 == 2)
297 x = line->Point1.X;
298 y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X);
300 else if (m2 == 2)
302 x = line->Point2.X;
303 y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X);
305 else
307 x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X
308 - m2 * line->Point2.X) / (m1 - m2);
309 y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X
310 - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2);
312 InsertedPoint.X = x;
313 InsertedPoint.Y = y;
314 return &InsertedPoint;