From ea13d896dbead7151e9d86819c51f4d34d52c8d6 Mon Sep 17 00:00:00 2001 From: Peter Clifton Date: Sun, 6 Jun 2010 23:24:19 +0100 Subject: [PATCH] Introduce POLYGONHOLE_MODE for creating holes in polygons Having selected polygon hole mode, the first click selects which polygon to cut a hole in. A second click defines the start point of the hole contour. The tool then behaves in a similar way to the polygon drawing tool, with the hole ending when the start point is re-clicked. To avoid creating illegal polygons, the hole drawn is subtracted from a representation of the original polygon with the poly_Boolean_free(). This consolidates any contours it intersects with and prevents the user defining contours which intersect each other. (Although we don't currently prevent the the user drawing self-intersecting contours). The resulting POLYAREA is re-processed into PolygonType objects, potentially more than one - if the hole drawn bisects the original polygon. To keep undo operations simple, these are added as completely new objects and the original polygon is deleted - along with its ID. --- src/action.c | 121 +++++++++++++++++++++++++++++++- src/const.h | 1 + src/crosshair.c | 5 +- src/flags.c | 1 + src/gpcb-menu.res | 1 + src/hid/gtk/gui-icons-mode-buttons.data | 28 ++++++++ src/hid/gtk/gui-misc.c | 1 + src/hid/gtk/gui-output-events.c | 1 + src/hid/gtk/gui-top-window.c | 1 + src/hid/lesstif/main.c | 4 ++ src/pcb-menu.res | 1 + src/set.c | 1 + 12 files changed, 161 insertions(+), 5 deletions(-) diff --git a/src/action.c b/src/action.c index ab2d6c55..5f1c7a1e 100644 --- a/src/action.c +++ b/src/action.c @@ -145,6 +145,7 @@ typedef enum F_PinOrPadName, F_Pinout, F_Polygon, + F_PolygonHole, F_PreviousPoint, F_RatsNest, F_Rectangle, @@ -380,6 +381,7 @@ static FunctionType Functions[] = { {"PinOrPadName", F_PinOrPadName}, {"Pinout", F_Pinout}, {"Polygon", F_Polygon}, + {"PolygonHole", F_PolygonHole}, {"PreviousPoint", F_PreviousPoint}, {"RatsNest", F_RatsNest}, {"Rectangle", F_Rectangle}, @@ -843,6 +845,7 @@ AdjustAttachedObjects (void) /* polygon creation mode */ case POLYGON_MODE: + case POLYGONHOLE_MODE: AdjustAttachedLine (); break; /* line creation mode */ @@ -1448,6 +1451,101 @@ NotifyMode (void) break; } + case POLYGONHOLE_MODE: + { + switch (Crosshair.AttachedObject.State) + { + /* first notify, lookup object */ + case STATE_FIRST: + Crosshair.AttachedObject.Type = + SearchScreen (Note.X, Note.Y, POLYGON_TYPE, + &Crosshair.AttachedObject.Ptr1, + &Crosshair.AttachedObject.Ptr2, + &Crosshair.AttachedObject.Ptr3); + + if (Crosshair.AttachedObject.Type != NO_TYPE) + { + if (TEST_FLAG (LOCKFLAG, (PolygonTypePtr) + Crosshair.AttachedObject.Ptr2)) + { + Message (_("Sorry, the object is locked\n")); + Crosshair.AttachedObject.Type = NO_TYPE; + break; + } + else + Crosshair.AttachedObject.State = STATE_SECOND; + } + break; + + /* second notify, insert new point into object */ + case STATE_SECOND: + { + PointTypePtr points = Crosshair.AttachedPolygon.Points; + Cardinal n = Crosshair.AttachedPolygon.PointN; + POLYAREA *original, *new_hole, *result; + FlagType Flags; + + /* do update of position; use the 'LINE_MODE' mechanism */ + NotifyLine (); + + /* check if this is the last point of a polygon */ + if (n >= 3 && + points->X == Crosshair.AttachedLine.Point2.X && + points->Y == Crosshair.AttachedLine.Point2.Y) + { + /* Create POLYAREAs from the original polygon + * and the new hole polygon */ + original = PolygonToPoly (Crosshair.AttachedObject.Ptr2); + new_hole = PolygonToPoly (&Crosshair.AttachedPolygon); + + /* Subtract the hole from the original polygon shape */ + poly_Boolean_free (original, new_hole, &result, PBO_SUB); + + /* Convert the resulting polygon(s) into a new set of nodes + * and place them on the page. Delete the original polygon. + */ + SaveUndoSerialNumber (); + Flags = ((PolygonType *)Crosshair.AttachedObject.Ptr2)->Flags; + PolyToPolygonsOnLayer (PCB->Data, Crosshair.AttachedObject.Ptr1, + result, Flags); + RemoveObject (POLYGON_TYPE, + Crosshair.AttachedObject.Ptr1, + Crosshair.AttachedObject.Ptr2, + Crosshair.AttachedObject.Ptr3); + RestoreUndoSerialNumber (); + IncrementUndoSerialNumber (); + Draw (); + + /* reset state of attached line */ + memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType)); + Crosshair.AttachedLine.State = STATE_FIRST; + addedLines = 0; + + break; + } + + /* create new point if it's the first one or if it's + * different to the last one + */ + if (!n || + points[n - 1].X != Crosshair.AttachedLine.Point2.X || + points[n - 1].Y != Crosshair.AttachedLine.Point2.Y) + { + CreateNewPointInPolygon (&Crosshair.AttachedPolygon, + Crosshair.AttachedLine.Point2.X, + Crosshair.AttachedLine.Point2.Y); + + /* copy the coordinates */ + Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; + Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; + } + break; + } + } + + break; + } + case PASTEBUFFER_MODE: { TextType estr[MAX_ELEMENTNAMES]; @@ -3022,6 +3120,16 @@ ActionMode (int argc, char **argv, int x, int y) } break; + case POLYGONHOLE_MODE: + if (Crosshair.AttachedLine.State == STATE_FIRST) + SetMode (ARROW_MODE); + else + { + SetMode (NO_MODE); + SetMode (POLYGONHOLE_MODE); + } + break; + case ARC_MODE: if (Crosshair.AttachedBox.State == STATE_FIRST) SetMode (ARROW_MODE); @@ -3050,6 +3158,9 @@ ActionMode (int argc, char **argv, int x, int y) case F_Polygon: SetMode (POLYGON_MODE); break; + case F_PolygonHole: + SetMode (POLYGONHOLE_MODE); + break; #ifndef HAVE_LIBSTROKE case F_Release: ReleaseMode (); @@ -6098,7 +6209,8 @@ ActionUndo (int argc, char **argv, int x, int y) if (!function || !*function) { /* don't allow undo in the middle of an operation */ - if (Crosshair.AttachedObject.State != STATE_FIRST) + if (Settings.Mode != POLYGONHOLE_MODE && + Crosshair.AttachedObject.State != STATE_FIRST) return 1; if (Crosshair.AttachedBox.State != STATE_FIRST && Settings.Mode != ARC_MODE) @@ -6106,7 +6218,9 @@ ActionUndo (int argc, char **argv, int x, int y) /* undo the last operation */ HideCrosshair (true); - if (Settings.Mode == POLYGON_MODE && Crosshair.AttachedPolygon.PointN) + if ((Settings.Mode == POLYGON_MODE || + Settings.Mode == POLYGONHOLE_MODE) && + Crosshair.AttachedPolygon.PointN) { GoToPreviousPoint (); RestoreCrosshair (true); @@ -6268,7 +6382,8 @@ three "undone" lines. static int ActionRedo (int argc, char **argv, int x, int y) { - if ((Settings.Mode == POLYGON_MODE && + if (((Settings.Mode == POLYGON_MODE || + Settings.Mode == POLYGONHOLE_MODE) && Crosshair.AttachedPolygon.PointN) || Crosshair.AttachedLine.State == STATE_SECOND) return 1; diff --git a/src/const.h b/src/const.h index 2f97d4ea..676a6f06 100644 --- a/src/const.h +++ b/src/const.h @@ -92,6 +92,7 @@ #define ARROW_MODE 110 /* selection with arrow mode */ #define PAN_MODE 0 /* same as no mode */ #define LOCK_MODE 111 /* lock/unlock objects */ +#define POLYGONHOLE_MODE 112 /* cut holes in filled polygons */ /* --------------------------------------------------------------------------- * object flags diff --git a/src/crosshair.c b/src/crosshair.c index fa086959..b9a3dd2b 100644 --- a/src/crosshair.c +++ b/src/crosshair.c @@ -588,8 +588,9 @@ DrawAttached (bool BlockToo) } break; - /* the attached line is used by both LINEMODE and POLYGON_MODE */ + /* the attached line is used by both LINEMODE, POLYGON_MODE and POLYGONHOLE_MODE*/ case POLYGON_MODE: + case POLYGONHOLE_MODE: /* draw only if starting point is set */ if (Crosshair.AttachedLine.State != STATE_FIRST) gui->draw_line (Crosshair.GC, @@ -598,7 +599,7 @@ DrawAttached (bool BlockToo) Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y); - /* draw attached polygon only if in POLYGON_MODE */ + /* draw attached polygon only if in POLYGON_MODE or POLYGONHOLE_MODE */ if (Crosshair.AttachedPolygon.PointN > 1) { XORPolygon (&Crosshair.AttachedPolygon, 0, 0); diff --git a/src/flags.c b/src/flags.c index 41e0b55b..60688dd2 100644 --- a/src/flags.c +++ b/src/flags.c @@ -192,6 +192,7 @@ HID_Flag flags_flag_list[] = { {"movemode", FlagMode, MOVE_MODE}, {"pastebuffermode", FlagMode, PASTEBUFFER_MODE}, {"polygonmode", FlagMode, POLYGON_MODE}, + {"polygonholemode", FlagMode, POLYGONHOLE_MODE}, {"rectanglemode", FlagMode, RECTANGLE_MODE}, {"removemode", FlagMode, REMOVE_MODE}, {"rotatemode", FlagMode, ROTATE_MODE}, diff --git a/src/gpcb-menu.res b/src/gpcb-menu.res index df307be5..0db5aad5 100644 --- a/src/gpcb-menu.res +++ b/src/gpcb-menu.res @@ -508,6 +508,7 @@ PopupMenus = {"Text" checked=textmode,1 Mode(Text) a={"F4" "F4"}} {"Rectangle" checked=rectanglemode,1 Mode(Rectangle) a={"F5" "F5"}} {"Polygon" checked=polygonmode,1 Mode(Polygon) a={"F6" "F6"}} + {"Polygon Hole" checked=polygonholemode,1 Mode(PolygonHole)} {"Buffer" checked=pastebuffermode,1 Mode(PasteBuffer) a={"F7" "F7"}} {"Remove" checked=removemode,1 Mode(Remove) a={"F8" "F8"}} {"Rotate" checked=rotatemode,1 Mode(Rotate) a={"F9" "F9"}} diff --git a/src/hid/gtk/gui-icons-mode-buttons.data b/src/hid/gtk/gui-icons-mode-buttons.data index 1938ee26..be040f1a 100644 --- a/src/hid/gtk/gui-icons-mode-buttons.data +++ b/src/hid/gtk/gui-icons-mode-buttons.data @@ -283,6 +283,34 @@ static char *poly[] = { "ooooooooooooooooooooo" }; +/* XPM */ +static char * polyhole[] = { +"21 21 3 1", +" c None", +". c #6EA5D7", +"+ c #000000", +" .. ", +" ... ", +" ..... ", +" ....... ", +" ......... ", +" ....+++++... ", +" ....+ +.... ", +" ...+ +..... ", +" ...++++++...... ", +" ................ ", +" ................. ", +" ", +" + + ++ + +++ ", +" + + + + + + ", +" + + + + + + ", +" ++++ + + + +++ ", +" + + + + + + ", +" + + + + + + ", +" + + + + + + ", +" + + ++ +++ +++ ", +" " +}; /* XPM */ static char *rect[] = { diff --git a/src/hid/gtk/gui-misc.c b/src/hid/gtk/gui-misc.c index 32ca1c9e..a607a697 100644 --- a/src/hid/gtk/gui-misc.c +++ b/src/hid/gtk/gui-misc.c @@ -220,6 +220,7 @@ ghid_mode_cursor (int Mode) break; case POLYGON_MODE: + case POLYGONHOLE_MODE: gport_set_cursor (GDK_SB_UP_ARROW); break; diff --git a/src/hid/gtk/gui-output-events.c b/src/hid/gtk/gui-output-events.c index c82e0673..7230aa3e 100644 --- a/src/hid/gtk/gui-output-events.c +++ b/src/hid/gtk/gui-output-events.c @@ -277,6 +277,7 @@ have_crosshair_attachments (void) result = TRUE; break; case POLYGON_MODE: + case POLYGONHOLE_MODE: if (Crosshair.AttachedLine.State != STATE_FIRST) result = TRUE; break; diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c index 4d4ba7c7..4c00c133 100644 --- a/src/hid/gtk/gui-top-window.c +++ b/src/hid/gtk/gui-top-window.c @@ -1983,6 +1983,7 @@ static ModeButton mode_buttons[] = { {NULL, NULL, NULL, "text", TEXT_MODE, text}, {NULL, NULL, NULL, "rectangle", RECTANGLE_MODE, rect}, {NULL, NULL, NULL, "polygon", POLYGON_MODE, poly}, + {NULL, NULL, NULL, "polygonhole", POLYGONHOLE_MODE, polyhole}, {NULL, NULL, NULL, "buffer", PASTEBUFFER_MODE, buf}, {NULL, NULL, NULL, "remove", REMOVE_MODE, del}, {NULL, NULL, NULL, "rotate", ROTATE_MODE, rot}, diff --git a/src/hid/lesstif/main.c b/src/hid/lesstif/main.c index 3280032b..e16397eb 100644 --- a/src/hid/lesstif/main.c +++ b/src/hid/lesstif/main.c @@ -2631,6 +2631,10 @@ idle_proc (XtPointer dummy) s = "Polygon"; cursor = XC_sb_up_arrow; break; + case POLYGONHOLE_MODE: + s = "Polygon Hole"; + cursor = XC_sb_up_arrow; + break; case PASTEBUFFER_MODE: s = "Paste"; cursor = XC_hand1; diff --git a/src/pcb-menu.res b/src/pcb-menu.res index 38e86e46..0df4b7fc 100644 --- a/src/pcb-menu.res +++ b/src/pcb-menu.res @@ -174,6 +174,7 @@ MainMenu = {"Text" checked=textmode,1 Mode(Text) a={"F4" "F4"}} {"Rectangle" checked=rectanglemode,1 Mode(Rectangle) a={"F5" "F5"}} {"Polygon" checked=polygonmode,1 Mode(Polygon) a={"F6" "F6"}} + {"Polygon Hole" checked=polygonholemode,1 Mode(PolygonHole)} {"Buffer" checked=pastebuffermode,1 Mode(PasteBuffer) a={"F7" "F7"}} {"Remove" checked=removemode,1 Mode(Remove) a={"F8" "F8"}} {"Rotate" checked=rotatemode,1 Mode(Rotate) a={"F9" "F9"}} diff --git a/src/set.c b/src/set.c index 48d704d4..7a41f73c 100644 --- a/src/set.c +++ b/src/set.c @@ -253,6 +253,7 @@ SetMode (int Mode) { if (Mode == ARC_MODE || Mode == RECTANGLE_MODE || Mode == VIA_MODE || Mode == POLYGON_MODE || + Mode == POLYGONHOLE_MODE || Mode == TEXT_MODE || Mode == INSERTPOINT_MODE || Mode == THERMAL_MODE) { -- 2.11.4.GIT