From 6b9efefc02ff3194b9d2ae30d28eaf700ed46af4 Mon Sep 17 00:00:00 2001 From: "R. Timothy Edwards" Date: Fri, 28 Mar 2025 10:11:17 -0400 Subject: [PATCH] Added a new "orthogonal" operator to cifoutput to allow non- manhattan shapes (especially minimum-sized ones) to be eliminated, as these can survive a shrink-grow operation intended to get rid of such shapes. This implementation may not be in its final form but should suffice for now. --- VERSION | 2 +- cif/CIFgen.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++----- cif/CIFint.h | 8 ++++-- cif/CIFtech.c | 41 +++++++++++++++++++++++++-- 4 files changed, 116 insertions(+), 13 deletions(-) diff --git a/VERSION b/VERSION index 6bdf1944..a512729b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.523 +8.3.524 diff --git a/cif/CIFgen.c b/cif/CIFgen.c index 67950ba1..c012dce1 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -2082,6 +2082,53 @@ cifBridgeCheckFunc( return 0; /* Nothing found here, so keep going */ } +/* + * ---------------------------------------------------------------------------- + * + * cifOrthogonalFunc -- + * + * Called for each relevant tile during "orthogonal" operations. + * + * Results: + * Always returns 0 to keep the search alive. + * + * Side effects: + * Paints into cifNewPlane. Tiles in old plane are copied as-is + * if they are not split tiles. Split tiles are either replaced + * with a rectangle of type "1" or "0" depending on whether the + * option is "fill" or "remove", respectively. + * ---------------------------------------------------------------------------- + */ + +int +cifOrthogonalFunc( + Tile *tile, + const PaintResultType *table) /* Table to be used for painting. */ +{ + Rect area; + TileType oldType = TiGetTypeExact(tile); + + TiToRect(tile, &area); + + /* In scaling the tile, watch out for infinities!! If something + * is already infinity, don't change it. */ + + if (area.r_xbot > TiPlaneRect.r_xbot) area.r_xbot *= cifScale; + if (area.r_ybot > TiPlaneRect.r_ybot) area.r_ybot *= cifScale; + if (area.r_xtop < TiPlaneRect.r_xtop) area.r_xtop *= cifScale; + if (area.r_ytop < TiPlaneRect.r_ytop) area.r_ytop *= cifScale; + + /* Diagonal tiles get replaced with non-diagonal tiles */ + + if (oldType & TT_DIAGONAL) + DBPaintPlane(cifPlane, &area, table, (PaintUndoInfo *) NULL); + else + DBPaintPlane(cifPlane, &area, CIFPaintTable, (PaintUndoInfo *) NULL); + + CIFTileOps += 1; + return 0; +} + /* * ---------------------------------------------------------------------------- * @@ -2117,16 +2164,18 @@ cifCloseFunc( atotal = 0; - /* Search all sides for connected space tiles, and accumulate the total */ - /* area. If any connected tile borders infinity, then stop searching */ - /* because the area is not enclosed. */ + /* Search all sides for connected space tiles, and accumulate the */ + /* total area. If any connected tile borders infinity, then stop */ + /* searching because the area is not enclosed. */ cifGatherFunc(tile, &atotal, CLOSE_SEARCH); - /* If the total area is smaller than the rule area, then paint all the */ - /* tile areas into the destination plane. */ + /* If the total area is smaller than the rule area, then paint all */ + /* the tile areas into the destination plane. A rule area of zero */ + /* indicates that any enclosed area, no matter how large, should be */ + /* filled. */ - if ((atotal != INFINITY) && (atotal < growDistance)) + if ((atotal != INFINITY) && ((atotal < growDistance) || (growDistance == 0))) { cifGatherFunc(tile, &atotal, CLOSE_FILL); } @@ -2134,7 +2183,6 @@ cifCloseFunc( { cifGatherFunc(tile, &atotal, CLOSE_DONE); } - return 0; } @@ -5264,6 +5312,22 @@ CIFGenLayer( } break; + case CIFOP_MANHATTAN: + DBClearPaintPlane(nextPlane); + cifPlane = nextPlane; + cifScale = 1; + DBSrPaintArea((Tile *) NULL, curPlane, &TiPlaneRect, + &CIFSolidBits, cifOrthogonalFunc, + (op->co_client == (ClientData)1) ? + (ClientData) CIFPaintTable : + (ClientData) CIFEraseTable); + + temp = curPlane; + curPlane = nextPlane; + nextPlane = temp; + break; + + case CIFOP_MAXRECT: cifPlane = curPlane; diff --git a/cif/CIFint.h b/cif/CIFint.h index 6bd6b983..b49b21df 100644 --- a/cif/CIFint.h +++ b/cif/CIFint.h @@ -141,6 +141,7 @@ typedef struct cifop * which will be painted into parent cells instead of the * current cell. This replaces the "fault" method. * CIFOP_CLOSE - Added 11/25/19---close up areas smaller than indicated + * CIFOP_MANHATTAN - Added 3/27/25---remove or fill nonmanhattan areas * CIFOP_BRIDGE - Added 6/11/20---Bridge across catecorner gaps * CIFOP_BRIDGELIM - Added 27/07/20---Bridge across catecorner gaps, but with limiting layers * CIFOP_MASKHINTS - Added 12/14/20---Add geometry from cell properties, if any. @@ -167,9 +168,10 @@ typedef struct cifop #define CIFOP_INTERACT 19 #define CIFOP_COPYUP 20 #define CIFOP_CLOSE 21 -#define CIFOP_BRIDGE 22 -#define CIFOP_BRIDGELIM 23 -#define CIFOP_MASKHINTS 24 +#define CIFOP_MANHATTAN 22 +#define CIFOP_BRIDGE 23 +#define CIFOP_BRIDGELIM 24 +#define CIFOP_MASKHINTS 25 /* Definitions of bit fields used in the value of co_client for CIFOP_INTERACT */ #define CIFOP_INT_NOT 0x1 /* Inverted sense (not interacting) */ diff --git a/cif/CIFtech.c b/cif/CIFtech.c index d9053ad4..5046a66d 100644 --- a/cif/CIFtech.c +++ b/cif/CIFtech.c @@ -111,6 +111,7 @@ cifTechFreeStyle(void) case CIFOP_MAXRECT: case CIFOP_BOUNDARY: case CIFOP_INTERACT: + case CIFOP_MANHATTAN: /* These options use co_client to hold a single */ /* integer value, so it is not allocated. */ break; @@ -1091,6 +1092,8 @@ CIFTechLine( newOp->co_opcode = CIFOP_MASKHINTS; else if (strcmp(argv[0], "close") == 0) newOp->co_opcode = CIFOP_CLOSE; + else if (strcmp(argv[0], "orthogonal") == 0) + newOp->co_opcode = CIFOP_MANHATTAN; else if (strcmp(argv[0], "bridge") == 0) newOp->co_opcode = CIFOP_BRIDGE; else if (strcmp(argv[0], "bridge-lim") == 0) @@ -1133,7 +1136,6 @@ CIFTechLine( case CIFOP_GROWMIN: case CIFOP_GROW_G: case CIFOP_SHRINK: - case CIFOP_CLOSE: if (argc != 2) goto wrongNumArgs; newOp->co_distance = atoi(argv[1]); if (newOp->co_distance <= 0) @@ -1143,6 +1145,26 @@ CIFTechLine( } break; + case CIFOP_CLOSE: + /* "close" is like "grow" and "shrink" except that it can have + * no argument, in which case any closed shape of any size + * will be closed (useful for finding enclosed areas). + */ + if (argc == 1) + newOp->co_distance = 0; + else if (argc != 2) + goto wrongNumArgs; + else + { + newOp->co_distance = atoi(argv[1]); + if (newOp->co_distance <= 0) + { + TechError("Grow/shrink distance must be greater than zero.\n"); + goto errorReturn; + } + } + break; + case CIFOP_BRIDGE: if (argc != 3) goto wrongNumArgs; newOp->co_distance = atoi(argv[1]); @@ -1334,6 +1356,19 @@ bloatCheck: goto wrongNumArgs; break; + case CIFOP_MANHATTAN: + if (argc == 2) + { + if (!strcmp(argv[1], "fill")) + newOp->co_client = (ClientData)1; + else if (strcmp(argv[1], "remove")) + TechError("Orthogonal takes only one optional argument " + "\"fill\" or \"remove\" (default).\n"); + } + else if (argc != 1) + goto wrongNumArgs; + break; + case CIFOP_BBOX: if (argc == 2) { @@ -1925,7 +1960,7 @@ CIFTechFinal(void) } } /* Presence of op->co_opcode in CIFOP_OR indicates a copy */ - /* of the SquaresData pointer from a following operator */ + /* of the SquaresData pointer from a following operator. */ /* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */ /* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */ /* uses it for a string. */ @@ -1938,6 +1973,7 @@ CIFTechFinal(void) case CIFOP_MASKHINTS: case CIFOP_BOUNDARY: case CIFOP_MAXRECT: + case CIFOP_MANHATTAN: case CIFOP_NET: break; case CIFOP_BRIDGELIM: @@ -2472,6 +2508,7 @@ CIFTechOutputScale( case CIFOP_BOUNDARY: case CIFOP_MASKHINTS: case CIFOP_MAXRECT: + case CIFOP_MANHATTAN: case CIFOP_NET: case CIFOP_INTERACT: break;