2nd part of last commit's work: Implement a simple math solving
parser that allows simple expressions to be entered for dimensions, such as "2um + 2um" or even mixtures of units like "3um + 200i". This feature is currently experimental.
This commit is contained in:
parent
9760ef6d1d
commit
0cbed6078a
|
|
@ -73,9 +73,22 @@ TileTypeBitMask CmdYMAllButSpace;
|
||||||
* lambda, a suffix of "g" indicates the user grid, and a suffix in metric
|
* lambda, a suffix of "g" indicates the user grid, and a suffix in metric
|
||||||
* notation ("nm", "um", "mm", "cm") indicates natural units. Other valid
|
* notation ("nm", "um", "mm", "cm") indicates natural units. Other valid
|
||||||
* units are "cu" or "centimicrons" for centimicrons, or "microns" for um.
|
* units are "cu" or "centimicrons" for centimicrons, or "microns" for um.
|
||||||
* Units without any suffix are assumed to be in lambda if "snap"
|
* Traditional (backwards-compatible) behavior: Units without any suffix
|
||||||
* (DBWSnapToGrid) is set to lambda, grid units if "snap" is set to the
|
* are assumed to be in lambda if "snap" (DBWSnapToGrid) is set to lambda,
|
||||||
* user grid, and internal units otherwise.
|
* grid units if "snap" is set to the user grid, and internal units otherwise.
|
||||||
|
* Current behavior: Use of the "units" command to set the units to
|
||||||
|
* any value other than "default" causes cmdScaleCoord() to parse any
|
||||||
|
* units provided without an identifying suffix as the units indicted by
|
||||||
|
* the "units" command. Once the "units" command has been issued, the
|
||||||
|
* values are dependent on DBWUnits and not on DBWSnapToGrid.
|
||||||
|
*
|
||||||
|
* Additional behavior from magic version 8.3.596: A single command
|
||||||
|
* option can use simple expressions using '+', '-', '*', and '/'. These
|
||||||
|
* can be passed as a single token, without spaces, or within a string
|
||||||
|
* token deliniated by quotes or braces, per usual Tcl syntax. Unlike
|
||||||
|
* the Tcl "expr" command, this can solve arithmetic expressions of
|
||||||
|
* suffixed values, evaluated independently such that different suffixes
|
||||||
|
* may be used (e.g., "1g + 3um" meaning 1 grid pitch plus 3 microns).
|
||||||
*
|
*
|
||||||
* MagWindow argument w is used only with grid-based snapping, to find
|
* MagWindow argument w is used only with grid-based snapping, to find
|
||||||
* the value of the grid for the given window. In this case, because the
|
* the value of the grid for the given window. In this case, because the
|
||||||
|
|
@ -99,6 +112,13 @@ TileTypeBitMask CmdYMAllButSpace;
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define PARSEOP_NONE 0
|
||||||
|
#define PARSEOP_ADD 1
|
||||||
|
#define PARSEOP_SUB 2
|
||||||
|
#define PARSEOP_MUL 3
|
||||||
|
#define PARSEOP_DIV 4
|
||||||
|
#define PARSEOP_END 5
|
||||||
|
|
||||||
int
|
int
|
||||||
cmdScaleCoord(
|
cmdScaleCoord(
|
||||||
MagWindow *w,
|
MagWindow *w,
|
||||||
|
|
@ -110,19 +130,26 @@ cmdScaleCoord(
|
||||||
char *endptr;
|
char *endptr;
|
||||||
double dval = 0;
|
double dval = 0;
|
||||||
int mscale = 1, curunits;
|
int mscale = 1, curunits;
|
||||||
|
int retval, curval, parseop;
|
||||||
DBWclientRec *crec;
|
DBWclientRec *crec;
|
||||||
|
|
||||||
if (*arg == '{') arg++;
|
if (*arg == '{' || *arg == '"') arg++;
|
||||||
while (isspace(*arg)) arg++;
|
while (isspace(*arg) && (*arg != '\0')) arg++;
|
||||||
|
|
||||||
|
parseop = PARSEOP_NONE;
|
||||||
|
retval = 0;
|
||||||
|
while (*arg != '\0')
|
||||||
|
{
|
||||||
dval = strtod(arg, &endptr);
|
dval = strtod(arg, &endptr);
|
||||||
dval *= (double)scale;
|
dval *= (double)scale;
|
||||||
|
mscale = -1;
|
||||||
|
|
||||||
if (endptr == arg)
|
if (endptr == arg)
|
||||||
{
|
{
|
||||||
/* strtod() error condition */
|
/* strtod() error condition */
|
||||||
TxError("Coordinate value cannot be parsed: assuming 0\n");
|
TxError("Coordinate value cannot be parsed: assuming 0\n");
|
||||||
return 0;
|
curval = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Original behavior was to accept un-suffixed values according to the
|
/* Original behavior was to accept un-suffixed values according to the
|
||||||
|
|
@ -141,13 +168,11 @@ cmdScaleCoord(
|
||||||
/* lambda or default units */
|
/* lambda or default units */
|
||||||
dval *= (double)DBLambda[1];
|
dval *= (double)DBLambda[1];
|
||||||
dval /= (double)DBLambda[0];
|
dval /= (double)DBLambda[0];
|
||||||
return round(dval);
|
|
||||||
}
|
}
|
||||||
else if ((*endptr == 'i')
|
else if ((*endptr == 'i')
|
||||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL)))
|
|| ((*endptr == '\0') && (curunits == DBW_UNITS_INTERNAL)))
|
||||||
{
|
{
|
||||||
/* internal units */
|
/* internal units */
|
||||||
return round(dval);
|
|
||||||
}
|
}
|
||||||
else if ((*endptr == 'g')
|
else if ((*endptr == 'g')
|
||||||
|| ((*endptr == '\0') && (curunits == DBW_UNITS_USER)))
|
|| ((*endptr == '\0') && (curunits == DBW_UNITS_USER)))
|
||||||
|
|
@ -157,7 +182,10 @@ cmdScaleCoord(
|
||||||
{
|
{
|
||||||
windCheckOnlyWindow(&w, DBWclientID);
|
windCheckOnlyWindow(&w, DBWclientID);
|
||||||
if (w == (MagWindow *)NULL)
|
if (w == (MagWindow *)NULL)
|
||||||
return round(dval); /* Default, if window is unknown */
|
{
|
||||||
|
curval = round(dval); /* Default, if window is unknown */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
crec = (DBWclientRec *) w->w_clientData;
|
crec = (DBWclientRec *) w->w_clientData;
|
||||||
if (is_x)
|
if (is_x)
|
||||||
|
|
@ -174,7 +202,6 @@ cmdScaleCoord(
|
||||||
if (!is_relative)
|
if (!is_relative)
|
||||||
dval += (double)crec->dbw_gridRect.r_ybot;
|
dval += (double)crec->dbw_gridRect.r_ybot;
|
||||||
}
|
}
|
||||||
return round(dval);
|
|
||||||
}
|
}
|
||||||
else if (*endptr == '\0' && (curunits == DBW_UNITS_MICRONS))
|
else if (*endptr == '\0' && (curunits == DBW_UNITS_MICRONS))
|
||||||
{
|
{
|
||||||
|
|
@ -200,12 +227,12 @@ cmdScaleCoord(
|
||||||
mscale = 10000000;
|
mscale = 10000000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TxError("Unknown metric prefix \"%cm\"; assuming internal units\n",
|
TxError("Unknown metric prefix \"%cm\"; assuming "
|
||||||
*endptr);
|
"internal units\n", *endptr);
|
||||||
return round(dval);
|
mscale = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(endptr, "u"))
|
else if ((*endptr == 'u') && !isalnum(*(endptr + 1)))
|
||||||
/* Maybe "u" is too ambiguous but it is very commonly used as
|
/* Maybe "u" is too ambiguous but it is very commonly used as
|
||||||
* an abbreviation for "micron".
|
* an abbreviation for "micron".
|
||||||
*/
|
*/
|
||||||
|
|
@ -214,16 +241,72 @@ cmdScaleCoord(
|
||||||
mscale = 1000;
|
mscale = 1000;
|
||||||
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
|
else if (!strncmp(endptr, "centimicron", 11) || !strcmp(endptr, "cu"))
|
||||||
mscale = 10;
|
mscale = 10;
|
||||||
else if (!isspace(*endptr))
|
else if (!isspace(*endptr) && (*endptr != '+') && (*endptr != '-') &&
|
||||||
|
(*endptr != '*') && (*endptr != '/'))
|
||||||
{
|
{
|
||||||
TxError("Unknown coordinate type \"%s\"; assuming internal units\n",
|
TxError("Unknown coordinate type at \"%s\"; assuming internal units\n",
|
||||||
endptr);
|
endptr);
|
||||||
return round(dval);
|
mscale = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isspace(*endptr))
|
if ((mscale != -1) && !isspace(*endptr))
|
||||||
dval /= CIFGetOutputScale(mscale);
|
dval /= CIFGetOutputScale(mscale);
|
||||||
return round(dval);
|
curval = round(dval);
|
||||||
|
|
||||||
|
switch (parseop)
|
||||||
|
{
|
||||||
|
case PARSEOP_NONE:
|
||||||
|
retval = curval;
|
||||||
|
break;
|
||||||
|
case PARSEOP_ADD:
|
||||||
|
retval += curval;
|
||||||
|
break;
|
||||||
|
case PARSEOP_SUB:
|
||||||
|
retval -= curval;
|
||||||
|
break;
|
||||||
|
case PARSEOP_MUL:
|
||||||
|
retval *= curval;
|
||||||
|
break;
|
||||||
|
case PARSEOP_DIV:
|
||||||
|
retval /= curval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseop = PARSEOP_NONE;
|
||||||
|
while (*endptr != '\0')
|
||||||
|
{
|
||||||
|
switch (*endptr)
|
||||||
|
{
|
||||||
|
case '}':
|
||||||
|
case '"':
|
||||||
|
parseop = PARSEOP_END;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
parseop = PARSEOP_ADD;
|
||||||
|
endptr++;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
parseop = PARSEOP_SUB;
|
||||||
|
endptr++;
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
parseop = PARSEOP_MUL;
|
||||||
|
endptr++;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
parseop = PARSEOP_DIV;
|
||||||
|
endptr++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
endptr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (parseop != PARSEOP_NONE) break;
|
||||||
|
}
|
||||||
|
arg = endptr;
|
||||||
|
while (isspace(*arg) && (*arg != '\0')) arg++;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue