Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / remove.c
blob98b9adee1e5d321714d59bde9516b763b19f92f1
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 remove vias, pins ...
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
37 #include <setjmp.h>
38 #include <memory.h>
40 #include "global.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "misc.h"
46 #include "move.h"
47 #include "mymem.h"
48 #include "polygon.h"
49 #include "rats.h"
50 #include "remove.h"
51 #include "rtree.h"
52 #include "search.h"
53 #include "select.h"
54 #include "set.h"
55 #include "undo.h"
57 #ifdef HAVE_LIBDMALLOC
58 #include <dmalloc.h>
59 #endif
61 RCSID ("$Id$");
64 /* ---------------------------------------------------------------------------
65 * some local prototypes
67 static void *DestroyVia (PinTypePtr);
68 static void *DestroyRat (RatTypePtr);
69 static void *DestroyLine (LayerTypePtr, LineTypePtr);
70 static void *DestroyArc (LayerTypePtr, ArcTypePtr);
71 static void *DestroyText (LayerTypePtr, TextTypePtr);
72 static void *DestroyPolygon (LayerTypePtr, PolygonTypePtr);
73 static void *DestroyElement (ElementTypePtr);
74 static void *RemoveVia (PinTypePtr);
75 static void *RemoveRat (RatTypePtr);
76 static void *DestroyPolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
77 static void *RemovePolygonContour (LayerTypePtr, PolygonTypePtr, Cardinal);
78 static void *RemovePolygonPoint (LayerTypePtr, PolygonTypePtr, PointTypePtr);
79 static void *RemoveLinePoint (LayerTypePtr, LineTypePtr, PointTypePtr);
81 /* ---------------------------------------------------------------------------
82 * some local types
84 static ObjectFunctionType RemoveFunctions = {
85 RemoveLine,
86 RemoveText,
87 RemovePolygon,
88 RemoveVia,
89 RemoveElement,
90 NULL,
91 NULL,
92 NULL,
93 RemoveLinePoint,
94 RemovePolygonPoint,
95 RemoveArc,
96 RemoveRat
98 static ObjectFunctionType DestroyFunctions = {
99 DestroyLine,
100 DestroyText,
101 DestroyPolygon,
102 DestroyVia,
103 DestroyElement,
104 NULL,
105 NULL,
106 NULL,
107 NULL,
108 DestroyPolygonPoint,
109 DestroyArc,
110 DestroyRat
112 static DataTypePtr DestroyTarget;
113 static bool Bulk = false;
115 /* ---------------------------------------------------------------------------
116 * remove PCB
118 void
119 RemovePCB (PCBTypePtr Ptr)
121 ClearUndoList (true);
122 FreePCBMemory (Ptr);
123 SaveFree (Ptr);
126 /* ---------------------------------------------------------------------------
127 * destroys a via
129 static void *
130 DestroyVia (PinTypePtr Via)
132 r_delete_entry (DestroyTarget->via_tree, (BoxTypePtr) Via);
133 MYFREE (Via->Name);
134 if (Via != &DestroyTarget->Via[--DestroyTarget->ViaN])
136 *Via = DestroyTarget->Via[DestroyTarget->ViaN];
137 r_substitute (DestroyTarget->via_tree, (BoxTypePtr)
138 (BoxType *) & DestroyTarget->Via[DestroyTarget->ViaN],
139 (BoxType *) Via);
141 memset (&DestroyTarget->Via[DestroyTarget->ViaN], 0, sizeof (PinType));
142 return (NULL);
145 /* ---------------------------------------------------------------------------
146 * destroys a line from a layer
148 static void *
149 DestroyLine (LayerTypePtr Layer, LineTypePtr Line)
151 r_delete_entry (Layer->line_tree, (BoxTypePtr) Line);
152 MYFREE (Line->Number);
153 if (Line != &Layer->Line[--Layer->LineN])
155 *Line = Layer->Line[Layer->LineN];
156 /* tricky - line pointers are moved around */
157 r_substitute (Layer->line_tree, (BoxType *) & Layer->Line[Layer->LineN],
158 (BoxType *) Line);
160 memset (&Layer->Line[Layer->LineN], 0, sizeof (LineType));
161 return (NULL);
164 /* ---------------------------------------------------------------------------
165 * destroys an arc from a layer
167 static void *
168 DestroyArc (LayerTypePtr Layer, ArcTypePtr Arc)
170 r_delete_entry (Layer->arc_tree, (BoxTypePtr) Arc);
171 if (Arc != &Layer->Arc[--Layer->ArcN])
173 *Arc = Layer->Arc[Layer->ArcN];
174 r_substitute (Layer->arc_tree, (BoxType *) & Layer->Arc[Layer->ArcN],
175 (BoxType *) Arc);
177 memset (&Layer->Arc[Layer->ArcN], 0, sizeof (ArcType));
178 return (NULL);
181 /* ---------------------------------------------------------------------------
182 * destroys a polygon from a layer
184 static void *
185 DestroyPolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
187 r_delete_entry (Layer->polygon_tree, (BoxTypePtr) Polygon);
188 FreePolygonMemory (Polygon);
189 if (Polygon != &Layer->Polygon[--Layer->PolygonN])
191 *Polygon = Layer->Polygon[Layer->PolygonN];
192 r_substitute (Layer->polygon_tree,
193 (BoxType *) & Layer->Polygon[Layer->PolygonN],
194 (BoxType *) Polygon);
196 memset (&Layer->Polygon[Layer->PolygonN], 0, sizeof (PolygonType));
197 return (NULL);
200 /* ---------------------------------------------------------------------------
201 * removes a polygon-point from a polygon and destroys the data
203 static void *
204 DestroyPolygonPoint (LayerTypePtr Layer,
205 PolygonTypePtr Polygon, PointTypePtr Point)
207 Cardinal point_idx;
208 Cardinal i;
209 Cardinal contour;
210 Cardinal contour_start, contour_end, contour_points;
212 point_idx = polygon_point_idx (Polygon, Point);
213 contour = polygon_point_contour (Polygon, point_idx);
214 contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
215 contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
216 Polygon->HoleIndex[contour];
217 contour_points = contour_end - contour_start;
219 if (contour_points <= 3)
220 return RemovePolygonContour (Layer, Polygon, contour);
222 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
224 /* remove point from list, keep point order */
225 for (i = point_idx; i < Polygon->PointN - 1; i++)
226 Polygon->Points[i] = Polygon->Points[i + 1];
227 Polygon->PointN--;
229 /* Shift down indices of any holes */
230 for (i = 0; i < Polygon->HoleIndexN; i++)
231 if (Polygon->HoleIndex[i] > point_idx)
232 Polygon->HoleIndex[i]--;
234 SetPolygonBoundingBox (Polygon);
235 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
236 InitClip (PCB->Data, Layer, Polygon);
237 return (Polygon);
240 /* ---------------------------------------------------------------------------
241 * destroys a text from a layer
243 static void *
244 DestroyText (LayerTypePtr Layer, TextTypePtr Text)
246 MYFREE (Text->TextString);
247 r_delete_entry (Layer->text_tree, (BoxTypePtr) Text);
248 if (Text != &Layer->Text[--Layer->TextN])
250 *Text = Layer->Text[Layer->TextN];
251 r_substitute (Layer->text_tree, (BoxType *) & Layer->Text[Layer->TextN],
252 (BoxType *) Text);
254 memset (&Layer->Text[Layer->TextN], 0, sizeof (TextType));
255 return (NULL);
258 /* ---------------------------------------------------------------------------
259 * destroys a element
261 static void *
262 DestroyElement (ElementTypePtr Element)
264 if (DestroyTarget->element_tree)
265 r_delete_entry (DestroyTarget->element_tree, (BoxType *) Element);
266 if (DestroyTarget->pin_tree)
268 PIN_LOOP (Element);
270 r_delete_entry (DestroyTarget->pin_tree, (BoxType *) pin);
272 END_LOOP;
274 if (DestroyTarget->pad_tree)
276 PAD_LOOP (Element);
278 r_delete_entry (DestroyTarget->pad_tree, (BoxType *) pad);
280 END_LOOP;
282 ELEMENTTEXT_LOOP (Element);
284 if (DestroyTarget->name_tree[n])
285 r_delete_entry (DestroyTarget->name_tree[n], (BoxType *) text);
287 END_LOOP;
288 FreeElementMemory (Element);
289 if (Element != &DestroyTarget->Element[--DestroyTarget->ElementN])
291 *Element = DestroyTarget->Element[DestroyTarget->ElementN];
292 /* deal with changed element pointer */
293 r_substitute (DestroyTarget->element_tree,
294 (BoxType *) & DestroyTarget->Element[DestroyTarget->
295 ElementN],
296 (BoxType *) Element);
298 PIN_LOOP (Element);
300 pin->Element = Element;
302 END_LOOP;
303 PAD_LOOP (Element);
305 pad->Element = Element;
307 END_LOOP;
308 ELEMENTTEXT_LOOP (Element);
310 r_substitute (DestroyTarget->name_tree[n],
311 (BoxType *) & DestroyTarget->Element[DestroyTarget->
312 ElementN].Name[n],
313 (BoxType *) text);
314 text->Element = Element;
316 END_LOOP;
317 memset (&DestroyTarget->Element[DestroyTarget->ElementN], 0,
318 sizeof (ElementType));
319 return (NULL);
322 /* ---------------------------------------------------------------------------
323 * destroys a rat
325 static void *
326 DestroyRat (RatTypePtr Rat)
328 if (DestroyTarget->rat_tree)
329 r_delete_entry (DestroyTarget->rat_tree, &Rat->BoundingBox);
330 if (Rat != &DestroyTarget->Rat[--DestroyTarget->RatN])
332 *Rat = DestroyTarget->Rat[DestroyTarget->RatN];
333 r_substitute (DestroyTarget->rat_tree,
334 &DestroyTarget->Rat[DestroyTarget->RatN].BoundingBox,
335 &Rat->BoundingBox);
337 memset (&DestroyTarget->Rat[DestroyTarget->RatN], 0, sizeof (RatType));
338 return (NULL);
342 /* ---------------------------------------------------------------------------
343 * removes a via
345 static void *
346 RemoveVia (PinTypePtr Via)
348 /* erase from screen and memory */
349 if (PCB->ViaOn)
351 EraseVia (Via);
352 if (!Bulk)
353 Draw ();
355 MoveObjectToRemoveUndoList (VIA_TYPE, Via, Via, Via);
356 return (NULL);
359 /* ---------------------------------------------------------------------------
360 * removes a rat
362 static void *
363 RemoveRat (RatTypePtr Rat)
365 /* erase from screen and memory */
366 if (PCB->RatOn)
368 EraseRat (Rat);
369 if (!Bulk)
370 Draw ();
372 MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat);
373 return (NULL);
376 struct rlp_info
378 jmp_buf env;
379 LineTypePtr line;
380 PointTypePtr point;
382 static int
383 remove_point (const BoxType * b, void *cl)
385 LineType *line = (LineType *) b;
386 struct rlp_info *info = (struct rlp_info *) cl;
387 if (line == info->line)
388 return 0;
389 if ((line->Point1.X == info->point->X)
390 && (line->Point1.Y == info->point->Y))
392 info->line = line;
393 info->point = &line->Point1;
394 longjmp (info->env, 1);
396 else
397 if ((line->Point2.X == info->point->X)
398 && (line->Point2.Y == info->point->Y))
400 info->line = line;
401 info->point = &line->Point2;
402 longjmp (info->env, 1);
404 return 0;
407 /* ---------------------------------------------------------------------------
408 * removes a line point, or a line if the selected point is the end
410 static void *
411 RemoveLinePoint (LayerTypePtr Layer, LineTypePtr Line, PointTypePtr Point)
413 PointType other;
414 struct rlp_info info;
415 if (&Line->Point1 == Point)
416 other = Line->Point2;
417 else
418 other = Line->Point1;
419 info.line = Line;
420 info.point = Point;
421 if (setjmp (info.env) == 0)
423 r_search (Layer->line_tree, (const BoxType *) Point, NULL, remove_point,
424 &info);
425 return RemoveLine (Layer, Line);
427 MoveObject (LINEPOINT_TYPE, Layer, info.line, info.point,
428 other.X - Point->X, other.Y - Point->Y);
429 return (RemoveLine (Layer, Line));
432 /* ---------------------------------------------------------------------------
433 * removes a line from a layer
435 void *
436 RemoveLine (LayerTypePtr Layer, LineTypePtr Line)
438 /* erase from screen */
439 if (Layer->On)
441 EraseLine (Line);
442 if (!Bulk)
443 Draw ();
445 MoveObjectToRemoveUndoList (LINE_TYPE, Layer, Line, Line);
446 return (NULL);
449 /* ---------------------------------------------------------------------------
450 * removes an arc from a layer
452 void *
453 RemoveArc (LayerTypePtr Layer, ArcTypePtr Arc)
455 /* erase from screen */
456 if (Layer->On)
458 EraseArc (Arc);
459 if (!Bulk)
460 Draw ();
462 MoveObjectToRemoveUndoList (ARC_TYPE, Layer, Arc, Arc);
463 return (NULL);
466 /* ---------------------------------------------------------------------------
467 * removes a text from a layer
469 void *
470 RemoveText (LayerTypePtr Layer, TextTypePtr Text)
472 /* erase from screen */
473 if (Layer->On)
475 EraseText (Layer, Text);
476 if (!Bulk)
477 Draw ();
479 MoveObjectToRemoveUndoList (TEXT_TYPE, Layer, Text, Text);
480 return (NULL);
483 /* ---------------------------------------------------------------------------
484 * removes a polygon from a layer
486 void *
487 RemovePolygon (LayerTypePtr Layer, PolygonTypePtr Polygon)
489 /* erase from screen */
490 if (Layer->On)
492 ErasePolygon (Polygon);
493 if (!Bulk)
494 Draw ();
496 MoveObjectToRemoveUndoList (POLYGON_TYPE, Layer, Polygon, Polygon);
497 return (NULL);
500 /* ---------------------------------------------------------------------------
501 * removes a contour from a polygon.
502 * If removing the outer contour, it removes the whole polygon.
504 static void *
505 RemovePolygonContour (LayerTypePtr Layer,
506 PolygonTypePtr Polygon,
507 Cardinal contour)
509 Cardinal contour_start, contour_end, contour_points;
510 Cardinal i;
512 if (contour == 0)
513 return RemovePolygon (Layer, Polygon);
515 if (Layer->On)
517 ErasePolygon (Polygon);
518 if (!Bulk)
519 Draw ();
522 /* Copy the polygon to the undo list */
523 AddObjectToRemoveContourUndoList (POLYGON_TYPE, Layer, Polygon);
525 contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
526 contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
527 Polygon->HoleIndex[contour];
528 contour_points = contour_end - contour_start;
530 /* remove points from list, keep point order */
531 for (i = contour_start; i < Polygon->PointN - contour_points; i++)
532 Polygon->Points[i] = Polygon->Points[i + contour_points];
533 Polygon->PointN -= contour_points;
535 /* remove hole from list and shift down remaining indices */
536 for (i = contour; i < Polygon->HoleIndexN; i++)
537 Polygon->HoleIndex[i - 1] = Polygon->HoleIndex[i] - contour_points;
538 Polygon->HoleIndexN--;
540 InitClip (PCB->Data, Layer, Polygon);
541 /* redraw polygon if necessary */
542 if (Layer->On)
544 DrawPolygon (Layer, Polygon, 0);
545 if (!Bulk)
546 Draw ();
548 return NULL;
551 /* ---------------------------------------------------------------------------
552 * removes a polygon-point from a polygon
554 static void *
555 RemovePolygonPoint (LayerTypePtr Layer,
556 PolygonTypePtr Polygon, PointTypePtr Point)
558 Cardinal point_idx;
559 Cardinal i;
560 Cardinal contour;
561 Cardinal contour_start, contour_end, contour_points;
563 point_idx = polygon_point_idx (Polygon, Point);
564 contour = polygon_point_contour (Polygon, point_idx);
565 contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1];
566 contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN :
567 Polygon->HoleIndex[contour];
568 contour_points = contour_end - contour_start;
570 if (contour_points <= 3)
571 return RemovePolygonContour (Layer, Polygon, contour);
573 if (Layer->On)
574 ErasePolygon (Polygon);
576 /* insert the polygon-point into the undo list */
577 AddObjectToRemovePointUndoList (POLYGONPOINT_TYPE, Layer, Polygon, point_idx);
578 r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon);
580 /* remove point from list, keep point order */
581 for (i = point_idx; i < Polygon->PointN - 1; i++)
582 Polygon->Points[i] = Polygon->Points[i + 1];
583 Polygon->PointN--;
585 /* Shift down indices of any holes */
586 for (i = 0; i < Polygon->HoleIndexN; i++)
587 if (Polygon->HoleIndex[i] > point_idx)
588 Polygon->HoleIndex[i]--;
590 SetPolygonBoundingBox (Polygon);
591 r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0);
592 RemoveExcessPolygonPoints (Layer, Polygon);
593 InitClip (PCB->Data, Layer, Polygon);
595 /* redraw polygon if necessary */
596 if (Layer->On)
598 DrawPolygon (Layer, Polygon, 0);
599 if (!Bulk)
600 Draw ();
602 return (NULL);
605 /* ---------------------------------------------------------------------------
606 * removes an element
608 void *
609 RemoveElement (ElementTypePtr Element)
611 /* erase from screen */
612 if ((PCB->ElementOn || PCB->PinOn) &&
613 (FRONT (Element) || PCB->InvisibleObjectsOn))
615 EraseElement (Element);
616 if (!Bulk)
617 Draw ();
619 MoveObjectToRemoveUndoList (ELEMENT_TYPE, Element, Element, Element);
620 return (NULL);
623 /* ----------------------------------------------------------------------
624 * removes all selected and visible objects
625 * returns true if any objects have been removed
627 bool
628 RemoveSelected (void)
630 Bulk = true;
631 if (SelectedOperation (&RemoveFunctions, false, ALL_TYPES))
633 IncrementUndoSerialNumber ();
634 Draw ();
635 Bulk = false;
636 return (true);
638 Bulk = false;
639 return (false);
642 /* ---------------------------------------------------------------------------
643 * remove object as referred by pointers and type,
644 * allocated memory is passed to the 'remove undo' list
646 void *
647 RemoveObject (int Type, void *Ptr1, void *Ptr2, void *Ptr3)
649 void *ptr = ObjectOperation (&RemoveFunctions, Type, Ptr1, Ptr2, Ptr3);
650 return (ptr);
653 /* ---------------------------------------------------------------------------
654 * DeleteRats - deletes rat lines only
655 * can delete all rat lines, or only selected one
658 bool
659 DeleteRats (bool selected)
661 bool changed = false;
662 Bulk = true;
663 RAT_LOOP (PCB->Data);
665 if ((!selected) || TEST_FLAG (SELECTEDFLAG, line))
667 changed = true;
668 RemoveRat (line);
671 END_LOOP;
672 Bulk = false;
673 if (changed)
675 Draw ();
676 IncrementUndoSerialNumber ();
678 return (changed);
681 /* ---------------------------------------------------------------------------
682 * remove object as referred by pointers and type
683 * allocated memory is destroyed assumed to already be erased
685 void *
686 DestroyObject (DataTypePtr Target, int Type, void *Ptr1,
687 void *Ptr2, void *Ptr3)
689 DestroyTarget = Target;
690 return (ObjectOperation (&DestroyFunctions, Type, Ptr1, Ptr2, Ptr3));