From 7cb88ffceb56c31acd11426d2c42da9b88ed5506 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 14:52:17 -0400 Subject: [PATCH] Added a new selection command option "select intersect" that selects the area of intersection between any number of types. --- commands/CmdRS.c | 147 ++++++++++----------------------- select/selCreate.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ select/select.h | 1 + 3 files changed, 245 insertions(+), 102 deletions(-) diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 37f9a58c..7bdb5b0f 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -528,6 +528,26 @@ CmdSee(w, cmd) return; } +#define SEL_AREA 0 +#define SEL_VISIBLE 1 +#define SEL_CELL 2 +#define SEL_LABELS 3 +#define SEL_INTERSECT 4 +#define SEL_CLEAR 5 +#define SEL_FLAT 6 +#define SEL_HELP 7 +#define SEL_KEEP 8 +#define SEL_MOVE 9 +#define SEL_PICK 10 +#define SEL_SAVE 11 +#define SEL_FEEDBACK 12 +#define SEL_BBOX 13 +#define SEL_BOX 14 +#define SEL_CHUNK 15 +#define SEL_REGION 16 +#define SEL_NET 17 +#define SEL_SHORT 18 +#define SEL_DEFAULT 19 /* * ---------------------------------------------------------------------------- @@ -550,86 +570,10 @@ CmdSee(w, cmd) /* ARGSUSED */ void -cmdSelectArea(layers, less) - char *layers; /* Which layers are to be selected. */ - bool less; -{ - SearchContext scx; - TileTypeBitMask mask; - int windowMask, xMask; - DBWclientRec *crec; - MagWindow *window; - - bzero(&scx, sizeof(SearchContext)); - window = ToolGetBoxWindow(&scx.scx_area, &windowMask); - if (window == NULL) - { - TxPrintf("The box isn't in a window.\n"); - return; - } - - /* Since the box may actually be in multiple windows, we have to - * be a bit careful. If the box is only in one window, then there's - * no problem. If it's in more than window, the cursor must - * disambiguate the windows. - */ - - xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; - if ((windowMask & ~xMask) != 0) - { - window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL); - xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; - if ((windowMask & xMask) == 0) - { - TxPrintf("The box is in more than one window; use the cursor\n"); - TxPrintf("to select the one you want to select from.\n"); - return; - } - } - if (CmdParseLayers(layers, &mask)) - { - if (TTMaskEqual(&mask, &DBSpaceBits)) - (void) CmdParseLayers("*,label", &mask); - TTMaskClearType(&mask, TT_SPACE); - } - else return; - - if (less) - { - (void) SelRemoveArea(&scx.scx_area, &mask); - return; - } - - scx.scx_use = (CellUse *) window->w_surfaceID; - scx.scx_trans = GeoIdentityTransform; - crec = (DBWclientRec *) window->w_clientData; - SelectArea(&scx, &mask, crec->dbw_bitmask); -} - -/* - * ---------------------------------------------------------------------------- - * - * cmdSelectVisible -- - * - * This is a utility procedure used by CmdSelect to do area - * selection of visible paint. - * - * Results: - * None. - * - * Side effects: - * The selection is augmented to contain all the information on - * layers that is visible under the box, including paint, labels, - * and expanded subcells. - * - * ---------------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -cmdSelectVisible(layers, less) +cmdSelectArea(layers, less, option) char *layers; /* Which layers are to be selected. */ bool less; + int option; /* Option from defined list above */ { SearchContext scx; TileTypeBitMask mask; @@ -680,6 +624,7 @@ cmdSelectVisible(layers, less) scx.scx_use = (CellUse *) window->w_surfaceID; scx.scx_trans = GeoIdentityTransform; crec = (DBWclientRec *) window->w_clientData; + if (option == SEL_VISIBLE) { int i; for (i = 0; i < DBNumUserLayers; i++) @@ -688,7 +633,10 @@ cmdSelectVisible(layers, less) TTMaskClearType(&mask, i); } } - SelectArea(&scx, &mask, crec->dbw_bitmask); + if (option == SEL_INTERSECT) + SelectIntersect(&scx, &mask, crec->dbw_bitmask); + else + SelectArea(&scx, &mask, crec->dbw_bitmask); } /* @@ -728,32 +676,13 @@ CmdSelect(w, cmd) * second table, due to a help message for ":select" with no arguments. */ -#define SEL_AREA 0 -#define SEL_VISIBLE 1 -#define SEL_CELL 2 -#define SEL_LABELS 3 -#define SEL_CLEAR 4 -#define SEL_FLAT 5 -#define SEL_HELP 6 -#define SEL_KEEP 7 -#define SEL_MOVE 8 -#define SEL_PICK 9 -#define SEL_SAVE 10 -#define SEL_FEEDBACK 11 -#define SEL_BBOX 12 -#define SEL_BOX 13 -#define SEL_CHUNK 14 -#define SEL_REGION 15 -#define SEL_NET 16 -#define SEL_SHORT 17 -#define SEL_DEFAULT 18 - static char *cmdSelectOption[] = { "area", "visible", "cell", "labels", + "intersection", "clear", "flat", "help", @@ -780,6 +709,7 @@ CmdSelect(w, cmd) "[more | less] visible [layers] [de]select all visible info under box in layers", "[more | less | top] cell [name] [de]select cell under cursor, or \"name\"", "[do | no] labels [do not] select subcell labels", + "[more | less] intersection [layers] [de]select intersection of layers", "clear clear selection", "flat flatten the contents of the selection", "help print this message", @@ -980,7 +910,7 @@ CmdSelect(w, cmd) } if (!(more || less)) SelectClear(); if (cmd->tx_argc == 3) - cmdSelectArea(optionArgs[1], less); + cmdSelectArea(optionArgs[1], less, option); else cmdSelectArea("*,label,subcell", less); return; @@ -994,8 +924,21 @@ CmdSelect(w, cmd) if (cmd->tx_argc > 3) goto usageError; if (!(more || less)) SelectClear(); if (cmd->tx_argc == 3) - cmdSelectVisible(optionArgs[1], less); - else cmdSelectVisible("*,label,subcell", less); + cmdSelectArea(optionArgs[1], less, option); + else cmdSelectArea("*,label,subcell", less, option); + return; + + /*-------------------------------------------------------------------- + * Select area that is the intersection of all the specified layers + *-------------------------------------------------------------------- + */ + + case SEL_INTERSECT: + if (cmd->tx_argc > 3) goto usageError; + if (!(more || less)) SelectClear(); + if (cmd->tx_argc == 3) + cmdSelectArea(optionArgs[1], less, option); + else cmdSelectArea("*,label,subcell", less, option); return; /*-------------------------------------------------------------------- diff --git a/select/selCreate.c b/select/selCreate.c index 22054364..7968dc61 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -253,6 +253,205 @@ selClearFunc(scx) else return 2; } +/* Structure used by selIntersectPaintFunc() */ + +struct selIntersectData { + Rect *sid_rect; + TileType sid_type; +}; + +/* + * ---------------------------------------------------------------------------- + * + * selDupPaintFunc -- + * + * Copy paint from tile area in Select2Def into SelectDef as all types + * in rMask. + * + * ---------------------------------------------------------------------------- + */ + +int +selDupPaintFunc(tile, rMask) + Tile *tile; /* The tile to get the area to copy paint. */ + TileTypeBitMask *rMask; /* Paint types to copy to. */ +{ + Rect r; + + TiToRect(tile, &r); + DBPaintMask(SelectDef, &r, rMask); + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc2 --- + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc2(tile, sid) + Tile *tile; /* The tile to copy paint from. */ + struct selIntersectData *sid; +{ + Rect r; + int p; + + TiToRect(tile, &r); + GEOCLIP(&r, sid->sid_rect); /* Clip out the intersection area */ + + DBPaint(Select2Def, &r, sid->sid_type); /* Paint back into Select2Def */ + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc -- + * + * Erase paint of types in rMask from the area of the tile. + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc(tile, type) + Tile *tile; /* The tile to copy paint from. */ + TileType type; /* The type of tile to keep */ +{ + TileTypeBitMask tMask; + Rect r; + int plane; + struct selIntersectData sid; + + TiToRect(tile, &r); + + TTMaskSetOnlyType(&tMask, type); + plane = DBPlane(type); + + sid.sid_type = TiGetTypeExact(tile); + sid.sid_rect = &r; + + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &r, + &tMask, selIntersectPaintFunc2, (ClientData)&sid); + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * SelectIntersect -- + * + * This procedure selects all information that falls in a given area + * and contains the intersection of all the supplied types. + * + * Results: + * None. + * + * Side effects: + * The indicated information is added to the select cell, and + * outlined on the screen. Only information of particular + * types, and in expanded cells (according to xMask) is + * selected. + * + * ---------------------------------------------------------------------------- + */ + +void +SelectIntersect(scx, types, xMask) + SearchContext *scx; /* Describes the area in which material + * is to be selected. The resulting + * coordinates should map to the coordinates + * of EditRootDef. The cell use should be + * the root of a window. + */ + TileTypeBitMask *types; /* Indicates which intersecting layers to + * select. May not include labels or cells. + */ + int xMask; /* Indicates window (or windows) where cells + * must be expanded for their contents to be + * considered. 0 means treat everything as + * expanded. + */ +{ + TileTypeBitMask tMask, rMask; + TileType s, t; + int plane; + + /* If the source definition is changing, clear the old selection. */ + + if (SelectRootDef != scx->scx_use->cu_def) + { + if (SelectRootDef != NULL) + SelectClear(); + SelectRootDef = scx->scx_use->cu_def; + SelSetDisplay(SelectUse, SelectRootDef); + } + + SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL); + + /* Select all paint of types in "types" mask and copy into Select2Def */ + + DBCellClearDef(Select2Def); + (void) DBCellCopyAllPaint(scx, types, xMask, Select2Use); + + /* Find the first type in the list. This will be used as the reference */ + + for (t = 0; t < DBNumUserLayers; t++) + if (TTMaskHasType(types, t)) + break; + + if (t == DBNumUserLayers) return; + + /* Compute the type mask of the reference type */ + TTMaskSetOnlyType(&tMask, t); + plane = DBPlane(t); + + /* For each other type in "types", do the following */ + + for (s = t + 1; s < DBNumUserLayers; s++) + { + if (TTMaskHasType(types, s)) + { + /* Copy the reference paint type from Select2Def into SelectDef */ + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, + &tMask, selDupPaintFunc, (ClientData)&tMask); + + /* Erase the reference paint type from Select2Def */ + DBEraseMask(Select2Def, &TiPlaneRect, &tMask); + + /* Scan Select2Def for all geometry of type s inside the areas of */ + /* the reference type, and copy back to Select2Def as the reference */ + /* type */ + DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane], + &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)s); + + /* Erase the reference paint type from SelectDef */ + DBEraseMask(SelectDef, &TiPlaneRect, &tMask); + } + } + + /* Copy any remaining paint in the reference layer in Select2Def to */ + /* SelectDef as all the intersection types. */ + + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, + &tMask, selDupPaintFunc, (ClientData)types); + + SelectDef->cd_types = *types; /* Remember what types were requested */ + + /* Display the new selection. */ + + SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area); + DBReComputeBbox(SelectDef); + DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE); + DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS, + &DBAllButSpaceBits); +} /* * ---------------------------------------------------------------------------- diff --git a/select/select.h b/select/select.h index 25509db0..3f53f648 100644 --- a/select/select.h +++ b/select/select.h @@ -35,6 +35,7 @@ extern void SelectRegion(); extern void SelectInit(); extern void SelectClear(); extern void SelectCell(); +extern void SelectIntersect(); extern void SelRemoveArea(); extern int SelRemoveSel2(); extern int SelectRemoveCellUse();