2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* PlowCmd.c --
|
|
|
|
|
*
|
|
|
|
|
* Commands for the plow module only.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
|
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
|
|
|
* * software and its documentation for any purpose and without *
|
|
|
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
|
|
|
* * notice appear in all copies. The University of California *
|
|
|
|
|
* * makes no representations about the suitability of this *
|
|
|
|
|
* * software for any purpose. It is provided "as is" without *
|
|
|
|
|
* * express or implied warranty. Export of this software outside *
|
|
|
|
|
* * of the United States of America may require an export license. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/plow/PlowCmd.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "utils/main.h"
|
|
|
|
|
#include "textio/txcommands.h"
|
|
|
|
|
#include "plow/plow.h"
|
|
|
|
|
#include "select/select.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "commands/commands.h"
|
|
|
|
|
#include "plow/plowInt.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CmdPlow --
|
|
|
|
|
*
|
|
|
|
|
* Implement the "plow" command: snowplow.
|
|
|
|
|
* One side of the box forms the plow, which is swept through the layout
|
|
|
|
|
* until it coincides with the opposite side of the box. The direction
|
|
|
|
|
* depends on that specified by the user.
|
|
|
|
|
*
|
|
|
|
|
* Usage:
|
|
|
|
|
* plow [options]
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the edit cell.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The order of the following must be identical to that in
|
|
|
|
|
* the table cmdPlowOption[] below.
|
|
|
|
|
*/
|
|
|
|
|
#define PLOWBOUND 0
|
|
|
|
|
#define PLOWHELP 1
|
|
|
|
|
#define PLOWHORIZON 2
|
|
|
|
|
#define PLOWJOGS 3
|
|
|
|
|
#define PLOWSELECTION 4
|
|
|
|
|
#define PLOWSTRAIGHTEN 5
|
|
|
|
|
#define PLOWNOBOUND 6
|
|
|
|
|
#define PLOWNOJOGS 7
|
|
|
|
|
#define PLOWNOSTRAIGHTEN 8
|
|
|
|
|
#define PLOWPLOW 9 /* Implicit when direction specified */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CmdPlow(w, cmd)
|
|
|
|
|
MagWindow *w;
|
|
|
|
|
TxCommand *cmd;
|
|
|
|
|
{
|
|
|
|
|
int xdelta, ydelta, absX, absY;
|
|
|
|
|
int option, dir, distance;
|
2024-10-10 21:18:48 +02:00
|
|
|
char *layers;
|
|
|
|
|
const char * const *msg;
|
2017-04-25 14:41:48 +02:00
|
|
|
TileTypeBitMask mask;
|
|
|
|
|
Rect rootBox, editBox, newBox;
|
|
|
|
|
CellDef *rootDef, *editDef;
|
|
|
|
|
Point rootPoint;
|
|
|
|
|
MagWindow *window;
|
|
|
|
|
Transform t;
|
2024-10-10 21:18:48 +02:00
|
|
|
static const char * const cmdPlowOption[] =
|
2020-05-23 23:13:14 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
"boundary set boundary around area plowing may affect",
|
|
|
|
|
"help print this help information",
|
|
|
|
|
"horizon n set the horizon for jog introduction to n lambda",
|
|
|
|
|
"jogs reenable jog insertion (set horizon to 0)",
|
|
|
|
|
"selection [direction [amount]]\n\
|
|
|
|
|
plow the selection",
|
|
|
|
|
"straighten automatically straighten jogs after each plow",
|
|
|
|
|
"noboundary remove boundary around area plowing may affect",
|
|
|
|
|
"nojogs disable jog insertion (infinite jog horizon)",
|
|
|
|
|
"nostraighten don't automatically straighten jogs after each plow",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (cmd->tx_argc < 2)
|
|
|
|
|
goto usage2;
|
|
|
|
|
|
|
|
|
|
option = Lookup(cmd->tx_argv[1], cmdPlowOption);
|
|
|
|
|
if (option == -1)
|
|
|
|
|
{
|
|
|
|
|
TxError("Ambiguous plowing option: \"%s\"\n", cmd->tx_argv[1]);
|
|
|
|
|
goto usage2;
|
|
|
|
|
}
|
|
|
|
|
if (option < 0)
|
|
|
|
|
{
|
|
|
|
|
dir = GeoNameToPos(cmd->tx_argv[1], TRUE, FALSE);
|
|
|
|
|
if (dir < 0)
|
|
|
|
|
goto usage;
|
|
|
|
|
dir = GeoTransPos(&RootToEditTransform, dir);
|
|
|
|
|
option = PLOWPLOW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (option)
|
|
|
|
|
{
|
|
|
|
|
case PLOWBOUND:
|
|
|
|
|
case PLOWSELECTION:
|
|
|
|
|
case PLOWNOBOUND:
|
|
|
|
|
case PLOWPLOW:
|
|
|
|
|
windCheckOnlyWindow(&w, DBWclientID);
|
|
|
|
|
if (w == (MagWindow *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Point to a window first\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (EditCellUse == (CellUse *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("There is no edit cell!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!ToolGetEditBox(&editBox) || !ToolGetBox(&rootDef, &rootBox))
|
|
|
|
|
return;
|
|
|
|
|
editDef = EditCellUse->cu_def;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (option)
|
|
|
|
|
{
|
|
|
|
|
case PLOWHELP:
|
|
|
|
|
TxPrintf("Plow commands have the form \"plow option\",\n");
|
|
|
|
|
TxPrintf("where option is one of:\n\n");
|
|
|
|
|
for (msg = &(cmdPlowOption[0]); *msg != NULL; msg++)
|
|
|
|
|
{
|
|
|
|
|
if (**msg == '*') continue;
|
|
|
|
|
TxPrintf(" %s\n", *msg);
|
|
|
|
|
}
|
|
|
|
|
TxPrintf("\n");
|
|
|
|
|
TxPrintf("Option may also be any Manhattan direction, which\n");
|
|
|
|
|
TxPrintf("causes the plow to be moved in that direction.\n");
|
|
|
|
|
return;
|
|
|
|
|
case PLOWBOUND:
|
|
|
|
|
if (cmd->tx_argc != 2)
|
|
|
|
|
{
|
|
|
|
|
wrongNumArgs:
|
|
|
|
|
TxError("Wrong number of arguments to %s option.\n",
|
|
|
|
|
cmd->tx_argv[1]);
|
|
|
|
|
TxError("Type \":plow help\" for help.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
PlowSetBound(editDef, &editBox, rootDef, &rootBox);
|
|
|
|
|
break;
|
|
|
|
|
case PLOWHORIZON:
|
|
|
|
|
if (cmd->tx_argc == 3) PlowJogHorizon = cmdParseCoord(w,
|
|
|
|
|
cmd->tx_argv[2], TRUE, TRUE);
|
|
|
|
|
else if (cmd->tx_argc != 2) goto wrongNumArgs;
|
|
|
|
|
|
|
|
|
|
if (PlowJogHorizon == INFINITY)
|
|
|
|
|
TxPrintf("Jog horizon set to infinity.\n");
|
|
|
|
|
else TxPrintf("Jog horizon set to %d units.\n", PlowJogHorizon);
|
|
|
|
|
break;
|
|
|
|
|
case PLOWSTRAIGHTEN:
|
|
|
|
|
PlowDoStraighten = TRUE;
|
|
|
|
|
TxPrintf("Jogs will be straightened after each plow.\n");
|
|
|
|
|
break;
|
|
|
|
|
case PLOWNOBOUND:
|
|
|
|
|
if (cmd->tx_argc != 2) goto wrongNumArgs;
|
|
|
|
|
PlowClearBound();
|
|
|
|
|
break;
|
|
|
|
|
case PLOWNOJOGS:
|
|
|
|
|
if (cmd->tx_argc != 2) goto wrongNumArgs;
|
|
|
|
|
PlowJogHorizon = INFINITY;
|
|
|
|
|
TxPrintf("Jog insertion disabled.\n");
|
|
|
|
|
break;
|
|
|
|
|
case PLOWJOGS:
|
|
|
|
|
if (cmd->tx_argc != 2) goto wrongNumArgs;
|
|
|
|
|
PlowJogHorizon = 0;
|
|
|
|
|
TxPrintf("Jog insertion re-enabled (horizon 0).\n");
|
|
|
|
|
break;
|
|
|
|
|
case PLOWNOSTRAIGHTEN:
|
|
|
|
|
PlowDoStraighten = FALSE;
|
|
|
|
|
TxPrintf("Jogs will not be straightened automatically.\n");
|
|
|
|
|
break;
|
|
|
|
|
case PLOWPLOW:
|
|
|
|
|
if (cmd->tx_argc > 3) goto wrongNumArgs;
|
|
|
|
|
layers = cmd->tx_argc == 2 ? "*,l,subcell,space" : cmd->tx_argv[2];
|
|
|
|
|
if (!CmdParseLayers(layers, &mask))
|
|
|
|
|
break;
|
2025-02-17 10:49:04 +01:00
|
|
|
if (Plow(editDef, &editBox, &mask, dir))
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
TxPrintf("Reduced plow size to stay within the boundary.\n");
|
|
|
|
|
GeoTransRect(&EditToRootTransform, &editBox, &rootBox);
|
|
|
|
|
ToolMoveBox(TOOL_BL, &rootBox.r_ll, FALSE, rootDef);
|
|
|
|
|
ToolMoveCorner(TOOL_TR, &rootBox.r_ur, FALSE, rootDef);
|
|
|
|
|
break;
|
|
|
|
|
case PLOWSELECTION:
|
|
|
|
|
if (cmd->tx_argc > 2)
|
|
|
|
|
{
|
|
|
|
|
dir = GeoNameToPos(cmd->tx_argv[2], TRUE, TRUE);
|
|
|
|
|
if (dir < 0)
|
|
|
|
|
return;
|
|
|
|
|
if (cmd->tx_argc == 4)
|
|
|
|
|
{
|
|
|
|
|
switch (dir)
|
|
|
|
|
{
|
|
|
|
|
case GEO_EAST: case GEO_WEST:
|
|
|
|
|
distance = cmdParseCoord(w, cmd->tx_argv[3], TRUE, TRUE);
|
|
|
|
|
break;
|
|
|
|
|
case GEO_NORTH: case GEO_SOUTH:
|
|
|
|
|
distance = cmdParseCoord(w, cmd->tx_argv[3], TRUE, FALSE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else distance = 1;
|
|
|
|
|
|
|
|
|
|
switch (dir)
|
|
|
|
|
{
|
|
|
|
|
case GEO_NORTH: xdelta = 0; ydelta = distance; break;
|
|
|
|
|
case GEO_SOUTH: xdelta = 0; ydelta = -distance; break;
|
|
|
|
|
case GEO_EAST: xdelta = distance; ydelta = 0; break;
|
|
|
|
|
case GEO_WEST: xdelta = -distance; ydelta = 0; break;
|
|
|
|
|
default:
|
|
|
|
|
ASSERT(FALSE, "Bad direction in CmdPlow");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Use the displacement between the box lower-left corner
|
|
|
|
|
* and the point as the transform.
|
|
|
|
|
*/
|
|
|
|
|
if (rootDef != SelectRootDef)
|
|
|
|
|
{
|
|
|
|
|
TxError("\"plow selection\" uses the box lower-left\n");
|
|
|
|
|
TxError("corner as a place to pick up the selection\n");
|
|
|
|
|
TxError("for plowing, but the box isn't in a window\n");
|
|
|
|
|
TxError("containing the selection\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
window = ToolGetPoint(&rootPoint, (Rect *) NULL);
|
|
|
|
|
if ((window == NULL) ||
|
|
|
|
|
(EditRootDef != ((CellUse *) window->w_surfaceID)->cu_def))
|
|
|
|
|
{
|
|
|
|
|
TxError("\"plow selection\" uses the point as the\n");
|
|
|
|
|
TxError("place to plow the selection, but the point\n");
|
|
|
|
|
TxError("doesn't point to the edit cell.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
xdelta = rootPoint.p_x - rootBox.r_xbot;
|
|
|
|
|
ydelta = rootPoint.p_y - rootBox.r_ybot;
|
|
|
|
|
if (xdelta < 0) absX = -xdelta; else absX = xdelta;
|
|
|
|
|
if (ydelta < 0) absY = -ydelta; else absY = ydelta;
|
|
|
|
|
if (absY <= absX)
|
|
|
|
|
{
|
|
|
|
|
ydelta = 0;
|
|
|
|
|
distance = absX;
|
|
|
|
|
dir = xdelta > 0 ? GEO_EAST : GEO_WEST;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
xdelta = 0;
|
|
|
|
|
distance = absY;
|
|
|
|
|
dir = ydelta > 0 ? GEO_NORTH : GEO_SOUTH;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!PlowSelection(editDef, &distance, dir))
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Reduced distance to stay in the boundary.\n");
|
|
|
|
|
switch (dir)
|
|
|
|
|
{
|
|
|
|
|
case GEO_EAST: xdelta = distance; break;
|
|
|
|
|
case GEO_NORTH: ydelta = distance; break;
|
|
|
|
|
case GEO_WEST: xdelta = -distance; break;
|
|
|
|
|
case GEO_SOUTH: ydelta = -distance; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GeoTransTranslate(xdelta, ydelta, &GeoIdentityTransform, &t);
|
|
|
|
|
GeoTransRect(&t, &rootBox, &newBox);
|
|
|
|
|
DBWSetBox(rootDef, &newBox);
|
|
|
|
|
SelectClear();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
usage:
|
|
|
|
|
TxError("\"%s\" isn't a valid plow option.", cmd->tx_argv[1]);
|
|
|
|
|
|
|
|
|
|
usage2:
|
|
|
|
|
TxError(" Type \"plow help\" for help.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CmdStraighten --
|
|
|
|
|
*
|
|
|
|
|
* Straighten jogs in an area by pulling in a particular direction.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies the geometry of the edit cell.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CmdStraighten(w, cmd)
|
|
|
|
|
MagWindow *w;
|
|
|
|
|
TxCommand *cmd;
|
|
|
|
|
{
|
|
|
|
|
Rect editBox;
|
|
|
|
|
int dir;
|
|
|
|
|
|
|
|
|
|
windCheckOnlyWindow(&w, DBWclientID);
|
|
|
|
|
if (w == (MagWindow *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Point to a window first\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cmd->tx_argc != 2)
|
|
|
|
|
goto usage;
|
|
|
|
|
|
|
|
|
|
dir = GeoNameToPos(cmd->tx_argv[1], TRUE, FALSE);
|
|
|
|
|
if (dir < 0)
|
|
|
|
|
goto usage;
|
|
|
|
|
dir = GeoTransPos(&RootToEditTransform, dir);
|
|
|
|
|
|
|
|
|
|
if (EditCellUse == (CellUse *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("There is no edit cell!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!ToolGetEditBox(&editBox))
|
|
|
|
|
{
|
|
|
|
|
TxError("The box is not in a window over the edit cell.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PlowStraighten(EditCellUse->cu_def, &editBox, dir);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
usage:
|
|
|
|
|
TxError("Usage: straighten manhattan-direction\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CmdPlowTest --
|
|
|
|
|
*
|
|
|
|
|
* Debugging of plowing.
|
|
|
|
|
*
|
|
|
|
|
* Usage:
|
|
|
|
|
* *plow cmd [args]
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* See comments in PlowTest() in plow/PlowTest.c for details.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CmdPlowTest(w, cmd)
|
|
|
|
|
MagWindow *w;
|
|
|
|
|
TxCommand *cmd;
|
|
|
|
|
{
|
|
|
|
|
PlowTest(w, cmd);
|
|
|
|
|
}
|
|
|
|
|
|