Sindbad~EG File Manager
/* M. Beeson, for Mathpert */
/* locate_term to convert a bblocked term to an lterm;
Original date 1.28.95
modified 1.20.99
1.9.00 added BRACES
1.9.00 modified 'abstract' for CASES
1.9.99 modified locate_term at BRACES
1.12.00 corrected locate_prime
2.3.00 modified strip_parens
9.5.04 added include pstring
3.25.06 removed include heap.h
4.18.13 Added casts (int) strlen...
5.8.13 include <stddef.h>
modified abstract around line 526
5.15.13 added a case for BERNOULLI;
modified locate_subscripted_function at the dated line.
5.29.13 changed case SQRT and ROOT
12.11.23 made text_width not used if SVG is defined
12.28.23 passed size argument to sumspace
1.12.24 passed size argument to get_parenwidth etc.
4.7.24 corrected spacing in locate_term
6.13.24 corrected locate_integral and locate_def_integral to use integralsignwidth
11.19.24 removed a line in locate_limit (search "removed")
and changed the lines above and below that one
11.24.24 gave productspace a size argument
1.12.25 corrected locate_def_integral, no space after limits before integrand
1.13.25 in locate_term, no longer call papyrus_to_xpixel; but so far
I made that change in only one place.
2.18.25 moved GETBLOCK up one line around line 285, otherwise b is used uninitialized.
2.18.25 in locate_matrix, moved line leftside.block.w = ... down until right side is defined.
2.18.25 added newarg.info = 0 in locate_matrix
*/
#include <string.h>
#include <assert.h>
#include <stddef.h>
#include "terms.h"
#include "display.h"
#include "display1.h"
#include "bigrect.h"
#include "lterm.h"
#include "probtype.h" /* get_problemtype, LINEAR_EQUATIONS */
#include "defns.h" /* set_valuepointers */
#include "vaux.h" /* get_currentline */
#include "islinear.h" /* is_linear_system */
#include "proverdl.h" /* history */
#include "dispfunc.h"
#include "speed.h" /* tnegate */
#include "pstring.h" /* paren */
#include "termtoSVG.h" /* svg_text_width */
#define bterm term
static void locate_matrix(int,term, BIGRECT *, lterm *);
static void locate_root(term, BIGRECT *, lterm *);
static void locate_function(term, BIGRECT *, lterm *);
static void locate_integral(term, BIGRECT *, lterm *);
static void locate_def_integral(term, BIGRECT *, lterm *);
static void locate_logb1(term, BIGRECT *, lterm *);
static void locate_diff(term, BIGRECT *, lterm *);
static void locate_hi_diff (term, BIGRECT *, lterm *);
static void locate_indexed_sum(term, BIGRECT *, lterm *);
static void locate_limit(term, BIGRECT *, lterm *);
static void locate_eval(term, BIGRECT *, lterm *);
static void locate_prime(term, BIGRECT *, lterm *);
static void locate_subscripted_function(term, BIGRECT *, lterm *);
static void locate_and(term, BIGRECT *, lterm *);
/*_________________________________________________________________*/
void locate_term(term bt, BIGRECT *r, lterm *ans)
/* convert a bblocked term bt into a located term whose
rectangle has the same upper-lefthand corner as *r does.
However, *ans may or may not fit into *r. There is no
attempt at line-breaking in locate_term: the answer
is prepared for display without line breaks, so it can
be arbitrarily wide or tall.
It can fail on large terms if the rectangle required
has coordinates that overflow an int. I failed to
anticipate this possibility and return an error, and
when it was discovered, it was too late for this much
tinkering. So in that case, the overflowed coordinates
are used, and for example on (2x+3)^60, expressed as a
polynomial, the overflowed coordinates result in locate_term
thinking that the term will fit on one line.
Note that bt has height and width information
in device-independent papyrus coordinates, whereas
ans is supposed to contain rectangles for each subterm,
in window coordinates. The conversion is made using
papyrus_to_xpixel and papyrus_to_ypixel, whose correct
functioning depends on a 'papyrus' being associated
with the window in which terms are to be displayed.
In Web MathXpert, papyrus coordinates are the same size as
pixel coordinates, but the origins may be different.
*ans will overlap the input bt, so you can't destroy
bt until you are done with *ans.
Note: the 'path' field of *ans will be NULL, indicating
that it is not a selected subterm of some other term. The
line field of *ans will be NULL too, indicating that lines
have not been broken-- *ans is prepared for one-line display,
regardless of its width.
*/
{ int i;
long space;
unsigned short n = (unsigned short)(ARITY(bt)-1);
unsigned short f = FUNCTOR(bt);
block b = GETBLOCK(bt);
coord level = b.wl;
long width = b.w;
block c;
BIGRECT s;
lterm u,uu;
term v;
long linewidth,termwidth;
long pixelwidth = papyrus_to_xpixel(WIDTH(bt));
long pixelheight = papyrus_to_ypixel(HEIGHT(bt));
ans->linelist = NULL;
ans->path = NULL;
ans->block = b;
if(b.leftbra || b.rightbra)
{ block oldb = b;
coord savespace;
CopyBigRect(&s,r);
savespace = save_space(bt);
if(b.leftbra)
{ s.left = (coord)(s.left + papyrus_to_xpixel(savespace));
b.w = (coord)(b.w - savespace); /* adjust width for left parens */
b.leftbra = 0;
}
if(b.rightbra)
{ s.right = (coord)(s.right - papyrus_to_xpixel(savespace));
b.w -= savespace;
b.rightbra = 0;
}
if( b.bra != BRACES && (f == MATRIX || f == LINEARSYSTEM))
/* brackets stick out matrixspace/2 above and below */
{ s.top = (coord)(s.top + papyrus_to_ypixel(get_matrixspace()/2));
s.bottom = (coord)(s.bottom - papyrus_to_ypixel(get_matrixspace()));
b.h = (coord)(b.h - get_matrixspace());
}
SETBLOCK(bt,b);
if(b.bra == BARS || b.bra == TALLBARS || b.bra == BRACES)
/* for ABSFUNCTOR, DET, EVAL, CASES */
/* Then expand the rectangle to include the bars */
{ locate_term(bt,&s,ans);
if(oldb.leftbra)
ans->r.left -= papyrus_to_xpixel(savespace);
if(oldb.rightbra)
ans->r.right += papyrus_to_xpixel(savespace);
SETBLOCK(bt,oldb);
ans->block = oldb; /* put the block with rightbra != 0, or leftbra != 0,
into ans, where extract_bterm can find it */
return;
}
locate_term(bt,&s,ans); /* the parentheses will not be
included when the selected term is highlighted;
that is, you may or may not put your rectangle
around the parentheses as well as the term. */
SETBLOCK(bt,oldb);
ans->block = oldb;
return;
}
if(ISATOM(bt))
{ /* atomic terms have an ARGPTR pointing to the current decimal value,
somewhere in the varinfo array.
atomic bterms have an ARGPTR that points to
(0) the block
(1) the display string;
The value pointer is not retained.
Atomic lterms have an ARGPTR that points to
the display string.
*/
ans->symbol = f;
ans->arity = 0; /* artificially so ISATOM will work on lterms */
ans->args = (void *) (ARGPTR(bt)+1);
ans->info = bt.info;
SetBigRect(&ans->r, r->left, r->top, r->left + pixelwidth, r->top + pixelheight);
return;
}
if(f == ILLEGAL)
/* ILLEGAL terms are used in displaying interval_as_and terms.
Process like an atom but make an empty rectangle
*/
{ ans->symbol = f;
ans->arity = 0;
ans->args = (void *) (ARGPTR(bt)+1);
ans->info = bt.info;
SetBigRectEmpty(&ans->r);
return;
}
if(f == 0) /* a bblocked object */
{ /* object bterms have an ARGPTR that points to three
things: (0) the block;
(1) the display string
(2) the actual data
object lterms have (1) and (2)
*/
ans->symbol = 0;
ans->arity = 1; /* so OBJECT(t) will work on lterms */
ans->args = (void *) (ARGPTR(bt) + 1);
ans->info = bt.info;
SetBigRect(&ans->r, r->left, r->top, r->left + pixelwidth, r->top + pixelheight);
return;
}
ans->symbol = f;
ans->args = (void *) callocate(n,sizeof(lterm));
if(f == MATRIX || f == VECTOR || f == LINEARSYSTEM)
--n; /* bblocked matrices and vectors have an extra arg */
/* The extra arg is allocated in the lterm but not counted in the arity */
ans->arity = n;
ans->info = bt.info;
if(ans->args == NULL)
{ nospace();
return;
}
SetBigRect(&ans->r, r->left, r->top, r->left + pixelwidth, r->top + pixelheight);
CopyBigRect(&s,r); /* slightly wasteful to do it here because in some cases
below, helper functions are called and this copy isn't
used. But if I put it in each case separately I
probably will forget it in at least one case. */
/* Now, what to do varies with the functor, just as in display_term */
switch(f)
{ case '-': /* fall through */
case NOT:
v = ARG(1,bt);
space = WIDTH(bt)-WIDTH(v);
/* it varies, depending on whether it was bblocked
in EIGHTPOINT or TENPOINT; and it used to depend on
whether v is an object or not; this code won't have
to be changed if bblock_minus and display change again.
*/
s.left += papyrus_to_xpixel(space);
locate_term(v,&s,&u);
LARGREP(*ans,0,u);
return;
case '+': /* fall through */
case '*':
/* We have to calculate in papyrus coordinates to avoid
problems with roundoff error */
linewidth = 0;
for(i=1;i<=n;i++)
{ v = ARG(i,bt); /* in bt the 0th arg is the block */
c = GETBLOCK(v);
termwidth = c.w;
/* line up the water levels */
s.left = r->left + papyrus_to_xpixel(linewidth);
s.top = r->top + papyrus_to_ypixel(b.wl - c.wl);
s.bottom = s.top + papyrus_to_ypixel(c.h);
locate_term(v,&s,&u);
LARGREP(*ans,i-1,u);
if(i==n)
break; /* done */
/* Now find the space between this arg and the next, in
papyrus coordinates. */
if(f == '*')
space = product_spacing(v, ARG(i+1,bt)); /* i+1 >= n */
else /* if(f == '+') */
{ if(FUNCTOR(ARG(i+1,bt)) == '-') /* next arg has a minus sign */
space = get_sumspace(b.size); /* space before the minus sign */
/* the minus sign itself is part of the next arg */
else
space = 2*get_sumspace(b.size) + get_pluswidth(b.size);
/* space before and after the + sign and
space for the + sign itself */
}
linewidth = linewidth + space + termwidth;
}
return;
case AND:
locate_and(bt,r,ans);
return;
case OR:
assert(0);
case '^':
c = GETBLOCK(ARG(1,bt));
if(c.extra && f && PREFIX(FUNCTOR(ARG(1,bt))))
/* infix exponent like sin^2 x */
{ unsigned short g = FUNCTOR(ARG(1,bt));
block b;
char fname[32];
functor_string(g,SCREEN,fname); /* in terms.c */
b = GETBLOCK(ARG(2,bt));
s.left = (coord)(s.left + papyrus_to_xpixel(functor_width(g,(short)b.size) + get_powerspace()));
locate_term(ARG(2,bt),&s,&u);
LARGREP(*ans,1,u);
s.left += papyrus_to_xpixel( WIDTH(ARG(2,bt)) + get_powerspace());
s.top = r->top;
s.right = r->right;
s.bottom = r->bottom;
s.top += papyrus_to_ypixel(level-LEVEL(ARG(1,bt)));
locate_term(ARG(1,ARG(1,bt)),&s,&u);
uu.args = (void *) callocate(1,sizeof(lterm));
if(uu.args == NULL)
{ nospace();
return;
}
uu.info = ARG(1,bt).info;
uu.arity = 1;
uu.symbol = g;
uu.r = u.r;
uu.r.left = r->left;
uu.linelist = NULL;
uu.path = NULL;
uu.block = GETBLOCK(ARG(1,bt));
uu.block.w = (coord)(uu.block.w + 2 *get_powerspace() - get_prefixspace() + WIDTH(ARG(2,bt)));
LARGREP(uu,0,u);
LARGREP(*ans,0,uu);
return;
}
/* Now in case it's an ordinary, not an infix, exponent */
{
s.top += papyrus_to_ypixel(level - LEVEL(ARG(1,bt)));
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
width = WIDTH(ARG(1,bt)); /* width of base in papyrus coordinates */
if(FUNCTOR(ARG(1,bt)) || ARITY(ARG(1,bt)) > 1)
/* not a void base */
width += get_powerspace();
s.left += papyrus_to_xpixel(width);
s.top = r->top; /* reset the top, it was moved down for the base */
locate_term(ARG(2,bt),&s,&u);
LARGREP(*ans,1,u);
if(FUNCTOR(LARG(0,*ans)) == MATRIX &&
NEGATIVE(LARG(1,*ans))
)
{ ans->arity = 1;
ans->symbol = MATRIXINVERSE;
}
return;
}
case '/':
space = (width - WIDTH(ARG(1,bt)))/2;
/* how far to move to center numerator */
s.left += papyrus_to_xpixel(space);
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
s = *r;
s.top += papyrus_to_ypixel(level+get_belowfractionspace());
s.left += papyrus_to_xpixel((width-WIDTH(ARG(2,bt)))/2);
if(GETBLOCK(ARG(2,bt)).leftbra)
s.top += papyrus_to_ypixel(get_belowfractionspace());
locate_term(ARG(2,bt),&s,&u);
LARGREP(*ans,1,u);
return;
case FRACT:
s = *r;
s.top += papyrus_to_ypixel(LEVEL(bt) - LEVEL(ARG(1,bt)));
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
s = *r;
s.left += papyrus_to_xpixel(WIDTH(ARG(1,bt)) + (SIZE(bt) == TENPOINT ? get_charspace() : 10));
s.top += papyrus_to_ypixel(LEVEL(bt) - LEVEL(ARG(2,bt)));
locate_term(ARG(2,bt),&s,&u);
LARGREP(*ans,1,u);
return;
case BINOMIAL:
space = (width - WIDTH(ARG(1,bt)))/2;
/* how far to move to center numerator */
s.left += papyrus_to_xpixel(space);
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
s = *r;
s.left += papyrus_to_xpixel((width-WIDTH(ARG(2,bt)))/2);
locate_term(ARG(2,bt),&s,&u);
LARGREP(*ans,1,u);
return;
case LINEARSYSTEM:
locate_matrix(1,bt,r,ans);
return;
case MATRIX:
locate_matrix(0,bt,r,ans);
return;
case EVAL:
locate_eval(bt,r,ans);
return;
case DET: /* fall through */
case ABSFUNCTOR: /* gets here only after after parens have been stripped */
locate_term(ARG(1,bt),r,&u);
LARGREP(*ans,0,u);
return; /* The rectangle will get adjusted */
case DIFF:
if(n==2)
locate_diff(bt,r,ans);
else if(n==3)
locate_hi_diff(bt,r,ans);
else
assert(0);
return;
case INTEGRAL:
if(n==2)
locate_integral(bt,r,ans);
else if(n==4)
locate_def_integral(bt,r,ans);
else
assert(0);
return;
case PR:
locate_prime(bt,r,ans);
return;
case LIMIT:
locate_limit(bt,r,ans);
return;
case SQRT:
s.left += papyrus_to_xpixel( get_charspace()) + get_undersqrtshift(); // used to be 2 * charspace - undersqrtshift);
s.top += papyrus_to_ypixel(1 + get_belowrootbar());
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
return;
case ROOT:
locate_root(bt,r,ans);
return;
case BESSELJ: /* fall through */
case BESSELY:
case BESSELI:
case BESSELK:
case BERNOULLI:
case EULERNUMBER:
case CONSTANTOFINTEGRATION:
locate_subscripted_function(bt,r,ans);
return;
case LOGB:
locate_logb1(bt,r,ans);
return;
case SUM : /* fall through */
case PRODUCT:
locate_indexed_sum(bt,r,ans);
return;
case FLOOR:
textstyle = SYMBOLFONT;
s.left += get_charspace(); /* for | */
if (HEIGHT(bt) > get_charspace())
s.left += get_parenspace(SIZE(bt)); /* space after | */
s.right -= (s.left - r->left);
locate_term(ARG(1,bt),&s,&u);
LARGREP(*ans,0,u);
return;
default:
locate_function(bt,r,ans);
return;
}
}
/*__________________________________________________________________*/
static void locate_matrix(int lineupflag,term newexpr, BIGRECT *r, lterm *ans)
/* called to perform the work of locate_term on a MATRIX or
LINEARSYSTEM. The argument 'lineupflag' tells which: 0 for MATRIX
and 1 for LINEARSYSTEM. Newexpr is the bblocked term to be located
inside rectangle r. Return 0 for success, 1 for failure; if successful
then *ans is the located term produced. At entry, ans has everything
filled in but the args, and it has space allocated for the args.
When lineupflag is 1, so we're working on a LINEARSYSTEM,
the answer is a LINEARSYSTEM term whose args are located equations,
rather than vectors of elements as in newexpr. That makes the located
term correspond better to the original term that was bblocked to
get the LINEARSYSTEM term. But, the rectangles of all the subterms
of the equations are correct for the screen display with variables
lined up.
*/
{ term entry;
int i,j,savej;
unsigned short k;
coord x,y;
BIGRECT s=*r;
coord entryx,entryy,row,rowheight,rowlevel,temp,width;
lterm u;
lterm lrow;
bterm v;
unsigned short rows = (unsigned short)(ARITY(newexpr)-2);
coord *columnwidths = COLUMNWIDTHS(newexpr,rows);
unsigned short columns = (unsigned short)(ARITY(ARG(1,newexpr))-1);
/* Now locate the rows */
x=y=0;
row = y;
for(i=0;i<rows;i++)
{ lrow.args = (void *) callocate(columns, sizeof(lterm));
if(lrow.args==NULL)
{ nospace();
return;
}
SETFUNCTOR(lrow,VECTOR,columns);
lrow.info = ARG(i+1,newexpr).info;
lrow.path = NULL;
lrow.linelist = NULL;
rowlevel = LEVEL(ARG(i+1,newexpr));
rowheight = HEIGHT(ARG(i+1,newexpr));
lrow.r.left = r->left;
if(lineupflag)
{ /* If there are no nonvoid entries,
each row is as wide as the whole matrix.
Note that bblock_matrix does not put a meaningful
value in the width field of the block of a row.
But if there are void entries at the beginning of
the row, the rectangle must not include the blank
space at the beginning of the row.
*/
v = ARG(i+1,newexpr);
width = 0; /* width of void terms passed so far in papyrus coordinates */
for(k=0;k<columns;k++)
{ if(FUNCTOR(ARG(k+1,v)) != ILLEGAL)
break;
width = (coord)(width + columnwidths[k] + get_sumspace(TENPOINT));
}
assert(k < columns); /* rows with all void entries can't exist */
/* k is the index of the column with the first nonvoid entry */
/* entries are right-justified in the columns; don't include
the unused part of the k-th column in the rectangle for the row.
The next line takes care of this. */
width = (coord)(width + columnwidths[k] - WIDTH(ENTRY(i+1,k+1,newexpr)));
lrow.r.left += papyrus_to_xpixel(width);
}
else
{ width = (coord)((columnwidths[0] - WIDTH(ENTRY(i+1,1,newexpr)))/2);
/* The blank space in the first column due to centering
the entry in the column */
lrow.r.left += papyrus_to_xpixel(width);
}
lrow.r.top = r->top + papyrus_to_ypixel(row);
lrow.r.bottom = lrow.r.top + papyrus_to_ypixel(rowheight);
lrow.r.right = ans->r.right;
entryx = x; /* leftmost point */
for(j=0;j<columns;j++)
{ entry = ENTRY(i+1,j+1,newexpr); /* i,j-th entry of matrix */
entryy = (coord)(row + rowlevel - (LEVEL(entry)));
/* at this point entryx is at the left side of the column */
temp = entryx;
if(lineupflag)
{ entryx = (coord)(entryx + columnwidths[j] - WIDTH(entry)); /* right justify */
if(j>0 && j<columns-2 &&
(FUNCTOR(entry)!=ILLEGAL) /* non-void term */
&& FUNCTOR(entry) != '-'
)
{ /* check whether all previous entries are void */
int p;
term priorentry;
for(p=0;p<j;p++)
{ priorentry = ENTRY(i+1,p+1,newexpr);
if(FUNCTOR(priorentry) != ILLEGAL) /* nonvoid*/
break;
}
}
}
else
entryx = (coord)(entryx + (columnwidths[j] - WIDTH(entry))/2); /* center the entry */
SetBigRect(&s, r->left + papyrus_to_xpixel(entryx),
r->top + papyrus_to_ypixel(entryy),
r->right,
r->bottom
);
locate_term(entry,&s,&u);
LARGREP(lrow,j,u);
entryx = (coord)(temp + columnwidths[j] + get_sumspace(TENPOINT));
/* this gets entryx ready for the next column */
}
lrow.block = GETBLOCK(ARG(i+1,newexpr));
LARGREP(*ans,i,lrow);
row = (coord) (row + rowheight + get_matrixspace());
}
if(columns == 1)
{ /* this is a VECTOR bblocked as a MATRIX for vertical display; but
the located term extracted from the bblocked term must be a VECTOR
again, or else an AND or an OR */
unsigned short ff = FUNCTOR(ARG(1,newexpr));
unsigned short hh;
term q = ARG(1,ARG(1,newexpr)); /* a bblocked term */
if(ff == VECTOR)
ff = FUNCTOR(q);
if(INEQUALITY(ff) || ff == MULTIPLICITY || ff == TRUEFUNCTOR || ff == FALSEFUNCTOR)
{ /* this is a vector of equations or inequalities, so it should
become an AND or an OR */
if(get_problemtype() == LINEAR_EQUATIONS)
hh = AND;
else if(get_problemtype() == RELATED_RATES && FUNCTOR(q) == '=')
hh = AND;
else
hh = OR;
}
else if(ff == ARROW && get_problemtype() == MINMAX)
hh = OR;
else if(ff == AND &&
INEQUALITY(FUNCTOR(ARG(1,q))) &&
INEQUALITY(FUNCTOR(ARG(2,q)))
)
/* q is a bblocked interval_as_and */
hh = OR;
else
hh = VECTOR;
SETFUNCTOR(*ans,hh,ARITY(*ans));
for(i=0;i<rows;i++)
LARGREP(*ans,i,LARG(0,LARG(i,*ans)));
}
if(lineupflag)
{ /* At present lt has VECTORS for args, but it should wind up
with equations for args. */
ans->symbol = AND; /* make it coincide with the original term */
SET_LINEUP(*ans); /* extract_bterm needs this */
for(i=0;i<rows;i++)
{ lterm leftside,rightside,newarg;
u = LARG(i,*ans);
rightside = LARG(columns-1,u);
v = ARG(i+1,newexpr);
/* construct left and right from the non-void arguments
of u, then put them together into a located equation.
The rectangle that u has now will not be changed,
only the args. */
/* Count the terms on the left side */
k = 0;
for(j=0;j<columns-2;j++)
{ if(FUNCTOR(ARG(j+1,v)) != ILLEGAL)
{ ++k;
savej = j;
}
}
if(k == 0)
assert(0);
if(k == 1)
leftside = LARG(savej,u);
else /* leftside will be a sum */
{ leftside.args = (void *) callocate(k,sizeof(lterm));
if(leftside.args == NULL)
{ nospace();
return;
}
leftside.symbol = '+';
leftside.arity = k;
leftside.block = u.block;
leftside.path = NULL;
leftside.linelist = NULL;
k = 0;
for(j=0;j<columns-2;j++)
{ if(FUNCTOR(ARG(j+1,v)) != ILLEGAL)
{ LARGREP(leftside,k,LARG(j,u));
++k;
}
}
if(k != leftside.arity)
assert(0);
leftside.r = u.r;
leftside.r.left = LARG(0,leftside).r.left;
leftside.r.right = LARG(k-1,leftside).r.right;
leftside.block.w = xpixel_to_papyrus(leftside.r.right-leftside.r.left);
}
newarg.symbol = '=';
newarg.arity = 2;
newarg.args = (void *) callocate(3, sizeof(lterm));
/* make an extra arg to stash the location of the '=' sign */
if(newarg.args == NULL)
{ nospace();
return;
}
newarg.r = u.r;
newarg.block = u.block;
newarg.linelist = NULL;
newarg.path = NULL;
LARGREP(newarg,0,leftside);
LARGREP(newarg,1,rightside);
LARGREP(newarg,2,LARG(columns-2,u));
/* This is an atomic lterm with functor '=' */
newarg.info = 0; /* otherwise it's uninitialized and provokes a warning */
SET_FACTORME(newarg); /* ldisplay looks for this bit in
order to treat these equations differently. */
LARGREP(*ans,i,newarg);
}
}
}
/*______________________________________________________________*/
static void locate_root(term bt, BIGRECT *r, lterm *ans)
/* do the work of locate_term on a ROOT term */
{ term arg, index;
coord height = HEIGHT(bt);
coord argheight;
BIGRECT s = *r;
coord x,y;
lterm u;
arg = ARG(2,bt);
index = ARG(1,bt);
x=y=0;
s.top += papyrus_to_ypixel(height- get_indexspace() - HEIGHT(index));
locate_term(index,&s,&u);
LARGREP(*ans,0,u);
x = (coord)(x + WIDTH(index) + get_rootspace()); /* papyrus coords */
argheight = HEIGHT(arg);
y = (coord)(y + height-argheight); /* - belowrootbar omitted */
x = (coord)(x + get_charspace() + get_undersqrtshift());
s.left = r->left + papyrus_to_xpixel(x);
s.top = r->top + papyrus_to_ypixel(y); /* +belowrootbar omitted */
locate_term(arg,&s,&u);
LARGREP(*ans,1,u);
}
/*________________________________________________________________*/
static void locate_function(term bt, BIGRECT *r, lterm *ans)
/* Do the work of locate_term on a predefined function
other than those explicitly treated in locate_term
*/
{ term u,v;
BIGRECT s;
long X,Y; /* papyrus coordinates measured from upper left of r */
coord level = LEVEL(bt);
coord Height = HEIGHT(bt);
unsigned long Width;
unsigned short f = FUNCTOR(bt);
char fname[32];
int Namelength; /* papyrus coordinates, width of functor name */
lterm larg;
if(SUBSCRIPTARGS(bt))
{ locate_subscripted_function(bt,r,ans);
return;
}
CopyBigRect(&s,r);
functor_string(f,SCREEN,fname); /* in dispfunc.c */
X=Y=0;
u = ARG(1,bt);
if(PREFIX(f))
{ if(f=='-')
textstyle = SYMBOLFONT; /* wider width */
else
textstyle = ROMAN; /* prefix function names in Roman type */
X = (coord)( X + functor_width(f,(short)SIZE(bt)) + get_prefixspace());
s.left += papyrus_to_xpixel(X);
Y = (coord)(level - LEVEL(u));
s.top += papyrus_to_ypixel(Y);
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
return;
}
if(POSTFIX(f))
{ s.top += papyrus_to_ypixel(level-LEVEL(u));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
return;
}
if(INFIX(f))
{ Namelength = functor_width(f,(short)SIZE(bt));
v = ARG(2,bt);
s.top += papyrus_to_ypixel(level-LEVEL(u));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
X = WIDTH(u);
Width = (unsigned long)(WIDTH(u) + WIDTH(v) + Namelength);
if(f==MOD || f == MULTIPLICITY )
textstyle = ROMAN;
else
textstyle = SYMBOLFONT; /* all other infix operators are symbolic */
CopyBigRect(&s,r);
if(Width == WIDTH(bt))
/* no space by operator */
{
s.left += papyrus_to_xpixel(X+Namelength);
s.top += papyrus_to_ypixel(level-LEVEL(v));
locate_term(v,&s,&larg);
LARGREP(*ans,1,larg);
return;
}
else
{ long Gap = (WIDTH(bt)-Width);
assert(Gap > 0);
assert(Gap <= 2*get_charspace());
s.left += papyrus_to_xpixel(X+Namelength+Gap);
s.top += papyrus_to_ypixel(level-LEVEL(v));
locate_term(v,&s,&larg);
LARGREP(*ans,1,larg);
return;
}
}
else
{ unsigned short arity = (unsigned short)(ARITY(bt)-1); /* number of arguments to locate */
int i;
textstyle = text_style(f);
#ifndef SVG
if(DEFINED_FUNCTION(f))
X = (coord)( X + text_width(fname,(short)SIZE(bt)) + get_parenwidth());
else
X = (coord) (X + functor_width(f,(short)SIZE(bt)) + get_parenwidth());
#else
X = (coord) (X + functor_width(f,(short)SIZE(bt)) + get_parenwidth(SIZE(bt)));
#endif
if(Height > get_charspace())
X = (coord)(X + get_parenspace(SIZE(bt)));
for(i=1;i<=arity;i++)
{ Y = (coord)(level-LEVEL(ARG(i,bt)));
s.top = r->top + papyrus_to_ypixel(Y);
s.left = r->left + papyrus_to_xpixel(X);
locate_term(ARG(i,bt),&s,&larg);
LARGREP(*ans,i-1,larg);
X = (coord)(X + WIDTH(ARG(i,bt)));
if(i < arity)
X = (coord)(X + get_parenwidth(SIZE(bt))); /* for the comma between the args */
}
return;
}
}
/*__________________________________________________________________*/
static void locate_integral(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on an indefinite integral,
by locating the arguments and placing them into *ans */
{ term u,t;
block b;
coord level;
coord X,Y;
BIGRECT s= *r;
lterm larg;
X=Y=0; /* papyrus coordinates from upper left of r */
b = GETBLOCK(newexpr);
level = b.wl;
u=ARG(1,newexpr);
t=ARG(2,newexpr);
X = (coord)(X + get_integralsignwidth() + get_productspace(b.size));
s.left = r->left + papyrus_to_xpixel(X);
s.top = r->top + papyrus_to_ypixel(level-LEVEL(u));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
X = (coord)(X + WIDTH(u) + get_productspace(b.size) + get_charspace()); /* for the 'd' and space before it */
s.left = r->left + papyrus_to_xpixel(X);
s.top = r->top + papyrus_to_ypixel(Y+level-LEVEL(t));
locate_term(t,&s,&larg);
LARGREP(*ans,1,larg);
}
/*__________________________________________________________________*/
static void locate_def_integral(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on a definite integral,
by locating the arguments and placing them into *ans */
{
term u,t,lo,hi;
block b;
coord height,level;
coord X,Y;
BIGRECT q= *r;
lterm larg;
coord S;
X=Y=0;
b = GETBLOCK(newexpr);
height = b.h;
level = b.wl;
u = ARG(1,newexpr);
t = ARG(2,newexpr);
lo = ARG(3,newexpr);
hi = ARG(4,newexpr);
/* Now find the top of the integral sign */
// S = (coord)(Y + HEIGHT(hi) - EIGHTPOINTHEIGHT + upperlimy);
S = (coord)(Y + height - HEIGHT(lo) + get_lowerlimy());
X+= get_integralsignwidth(); /* for the integral sign */
q.left = r->left + papyrus_to_xpixel(X + get_lowerlimx());
q.top = r->top + papyrus_to_ypixel(S);
locate_term(lo,&q,&larg);
LARGREP(*ans,2,larg);
q = *r;
q.left = r->left + papyrus_to_xpixel(X + get_upperlimx());
locate_term(hi,&q,&larg);
LARGREP(*ans,3,larg);
X = (coord)(X + MAXIMUM(WIDTH(lo)+get_lowerlimx(),WIDTH(hi)+get_upperlimx()) + get_productspace(b.size)); // space after limits before integrand
S = (coord)(Y + level - LEVEL(u));
q = *r;
q.left = r->left + papyrus_to_xpixel(X);
q.top = r->top + papyrus_to_ypixel(S);
locate_term(u,&q,&larg);
LARGREP(*ans,0,larg);
X = (coord)(X + WIDTH(u));
S = (coord)(Y + level - papyrus_to_ypixel(LEVEL(t)));
X = (coord)(X+get_charspace()); /* for the 'd' you just wrote; but no space after 'd' */
q = *r;
q.left += papyrus_to_xpixel(X);
q.top += papyrus_to_ypixel(S);
locate_term(t,&q,&larg);
LARGREP(*ans,1,larg);
}
/*___________________________________________________________________*/
static void locate_logb1(term newexpr, BIGRECT *r, lterm *ans)
{ term arg,index;
coord level = LEVEL(newexpr);
coord x;
lterm larg;
BIGRECT s = *r;
x = 0; /* papyrus coordinates from upper left of r */
arg = ARG(2,newexpr);
index = ARG(1,newexpr);
x = (coord)(x + functor_width(LOG,(short) SIZE(newexpr)) + get_powerspace());
/* for "log" and powerspace before the index */
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) + level);
/* r->top + papyrus_to_ypixel(level) produces roundoff error */
s.left = r->left + papyrus_to_xpixel(x);
locate_term(index,&s,&larg);
LARGREP(*ans,0,larg);
x = (coord)(x + WIDTH(index) + get_productspace(SIZE(newexpr))); /* productspace after the index */
s.left = r->left + papyrus_to_xpixel(x);
s.top = r->top;
locate_term(arg,&s,&larg);
LARGREP(*ans,1,larg);
}
/*__________________________________________________________________________*/
static void locate_diff(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on a DIFF term of arity 2 */
{ term u,t;
long width = WIDTH(newexpr);
coord level = LEVEL(newexpr);
long width1,width2;
coord level1;
coord charheight = (SIZE(newexpr) == TENPOINT ? get_charspace() : get_eightpointheight());
coord x,y,z;
unsigned long dwidth = atom_width('d',(short)SIZE(newexpr));
BIGRECT s = *r;
lterm larg;
x=y=z=0;
u = ARG(1,newexpr);
t = ARG(2,newexpr); /* doing du/dt */
width1 = WIDTH(u);
width2 = WIDTH(t);
level1 = LEVEL(u);
if(ISATOM(u) || (BB_OBJECT(u) && TYPE(u) != BIGNUM))
{ width1 += dwidth; /* width of 'numerator' */
width2 += dwidth; /* width of 'denominator' */
z = (coord)(x + (width-width1)/2);
/* in 'display_diff we write the 'd' now */
z = (coord)(z + dwidth);
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y + (HEIGHT(u) < charheight ? charheight-HEIGHT(u) : 0));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
y = (coord)(y + level);
/* draw_horz(width, x, y, attr); */
z = (coord)(x + (width - width2)/2);
y = (coord)(y + get_belowfractionspace());
/* Then write the 'd' in the denominator */
z = (coord)(z + dwidth);
if(HEIGHT(t) < charheight)
y = (coord)(y + charheight-HEIGHT(t));
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y);
locate_term(t,&s,&larg);
LARGREP(*ans,1,larg);
return;
}
/* Now the numerator is not atomic, so we display like d/dx sin x */
s.left = r->left + papyrus_to_xpixel(x+dwidth); /* for the open paren */
s.top = r->top + papyrus_to_ypixel(y+level+get_belowfractionspace() + (HEIGHT(t) < charheight ? charheight-HEIGHT(t):0));
locate_term(t,&s,&larg);
LARGREP(*ans,1,larg);
s.left = r->left + papyrus_to_xpixel(x+width-width1);
s.top = r->top + papyrus_to_ypixel(y+level-level1);
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
}
/*______________________________________________________________*/
static void locate_hi_diff(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on a DIFF of arity 3 */
{ term u,t,n;
long width1, width2, width = WIDTH(newexpr);
coord level = LEVEL(newexpr);
coord level1,secondrow;
coord x,y,z;
coord charwidth = (coord)(SIZE(newexpr) == EIGHTPOINT ? 13 : 16);
coord charheight = (coord)(SIZE(newexpr) == EIGHTPOINT ? get_charspace() : get_eightpointheight());
unsigned long dwidth = atom_width('d',(short)SIZE(newexpr));
BIGRECT s = *r;
lterm larg;
x=y=z=0;
u = ARG(1,newexpr);
n = ARG(3,newexpr);
t = ARG(2,newexpr); /* doing d^n u/dt^n */
width1 = WIDTH(u);
width2 = WIDTH(t);
level1 = LEVEL(u);
if( (ISATOM(u) || BB_OBJECT(u)) &&
(ISATOM(n) || BB_OBJECT(n))
)
{ width1 = (coord)(width1 + charwidth + WIDTH(n) + get_powerspace()); /* width of 'numerator' */
width2 = (coord)(width2 + charwidth + WIDTH(n) + get_powerspace()); /* width of 'denominator' */
z = (coord)(x + (width-width1)/2);
textstyle = ITALIC;
/* in 'display_hi_diff' we write the 'd' now */
z = (coord)(z + charwidth + get_powerspace());
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y);
locate_term(n,&s,&larg);
LARGREP(*ans,2,larg);
z = (coord)(z + WIDTH(n));
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y+6 +(HEIGHT(u) > charheight ? charheight - HEIGHT(u) : 0));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
y += level;
/* draw_horz(width, x, y, attr); */
z = (coord)(x + (width - width2)/2);
y += get_belowfractionspace();
/* Then write the 'd' in the denominator */
z += charwidth; /* the space for the 'd' */
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y+6+(HEIGHT(t) > charheight ? charheight - HEIGHT(t) : 0));
locate_term(t,&s,&larg);
LARGREP(*ans,1,larg);
/* The 'n' in the 'denominator' is not located, i.e. not selectable */
return;
}
/* Now the numerator is not atomic, so we display like (d^n/dx^n) sin x */
z =(coord)(x + width2/2);
/* Now display_hi_diff writes the 'd' in the 'numerator' */
z = (coord)(z + dwidth + get_powerspace());
// width2 = (coord)(width2 + WIDTH(n) + charspace + powerspace);
// the width of the horizontal bar
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(y + level - HEIGHT(n) - get_abovefractionspace() - 6);
locate_term(n,&s,&larg);
LARGREP(*ans,2,larg);
/* draw_horz(width2,x,y + level,attr); */
secondrow =(coord)( y + level + get_belowfractionspace() + HEIGHT(n) -(charheight-6));
/* WPUTCH('d',x,secondrow,attr); */
/* The n in the 'denominator' isn't located; to display it just
translate the other 'n' suitably */
s.left = r->left + papyrus_to_xpixel(x + dwidth);
s.top = r->top + papyrus_to_ypixel(secondrow+(HEIGHT(t) < charheight ? charheight-HEIGHT(t) : 0));
locate_term(t,&s,&larg);
LARGREP(*ans,1,larg);
s.left = r->left + papyrus_to_xpixel(x + width - width1);
s.top = r->top + papyrus_to_ypixel(y + level - level1);
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
}
/*_______________________________________________________________________*/
static void locate_indexed_sum(term newexpr, BIGRECT *r, lterm *ans)
/* finish the work of locate_term on an indexed sum or product */
{ term u,index,lo,hi;
long width = WIDTH(newexpr);
coord level = LEVEL(newexpr);
coord charheight = SIZE(newexpr) == TENPOINT ? get_charspace() : get_eightpointheight();
coord x,y; /* papyrus coordinates from upper left of r */
lterm larg;
BIGRECT s = *r;
coord z;
coord w;
unsigned long subscriptwidth;
coord subscriptlevel;
x=y=z=0;
w = (coord)(y + level);
u= ARG(1,newexpr);
index = ARG(2,newexpr);
lo = ARG(3,newexpr);
hi = ARG(4,newexpr);
subscriptlevel = MAXIMUM(LEVEL(lo),LEVEL(index));
subscriptwidth = (coord)(WIDTH(index) + WIDTH(lo) + 21U);
if(WIDTH(hi) > subscriptwidth)
{ z = (coord)(z + (WIDTH(hi) - subscriptwidth +1)/2);
/* +1 to cause uncentered display to shift right a half , not left */
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(w+charheight/2 + subscriptlevel - LEVEL(index));
locate_term(index,&s,&larg);
LARGREP(*ans,1,larg);
s.left = r->left + papyrus_to_xpixel(z+WIDTH(index)+21);
/* double coordinate conversions in the next line correct roundoff errors */
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) +
w+charheight/2 + subscriptlevel - LEVEL(lo)
);
locate_term(lo,&s,&larg);
LARGREP(*ans,2,larg);
s.left = r->left + papyrus_to_xpixel(x);
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) + y+level-HEIGHT(hi)-get_charspace()/2);
locate_term(hi,&s,&larg);
LARGREP(*ans,3,larg);
}
else
{ z = (coord)(z + (subscriptwidth-WIDTH(hi)+1)/2);
s.left = r->left + papyrus_to_xpixel(x);
/* double coordinate conversions in the next line correct roundoff errors */
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) +
w + charheight/2 + subscriptlevel-LEVEL(index)
);
locate_term(index,&s,&larg);
LARGREP(*ans,1,larg);
s.left = r->left + papyrus_to_xpixel(x+WIDTH(index)+21);
/* double coordinate conversions in the next line correct roundoff errors */
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) +
w + charheight/2 + subscriptlevel-LEVEL(lo)
);
locate_term(lo,&s,&larg);
LARGREP(*ans,2,larg);
s.left = r->left + papyrus_to_xpixel(z);
s.top = r->top + papyrus_to_ypixel(w-HEIGHT(hi)-charheight/2);
locate_term(hi,&s,&larg);
LARGREP(*ans,3,larg);
}
s.left = r->left + papyrus_to_xpixel(x+width-WIDTH(u));
/* The next line is so complicated to correct roundoff errors that
arose when I used
s.top = r->top + papyrus_to_ypixel(y+level-LEVEL(u));
*/
s.top = papyrus_to_ypixel(ypixel_to_papyrus(r->top) + y + level - LEVEL(u));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
if(ARITY(*ans) == 5)
{ /* a sum to be displayed using ... */
unsigned short m = ARITY(ARG(5,newexpr))-1;
locate_term(ARG(5,newexpr),r,LARGPTR(*ans)+4);
ans->r = LARG(4,*ans).r; /* use the rectangle of the sum rather than the sigma-notation term */
ans->block = LARG(4,*ans).block;
ans->block.leftbra = ans->block.rightbra = 0;
/* avoid double parens */
/* Shift the general term occurring as the 0-th arg to the position occupied by the
general term in the auxiliary sum, provided the auxiliary sum does display the general term. */
if(m >= 4 && FUNCTOR(LARG((unsigned short)(m-3),LARG(4,*ans))) == PSEUDOATOM)
{ /* ... + general term + ... */
BIGRECT rr = LARG((unsigned short)(m-2),LARG(4,*ans)).r;
BIGRECT ss = LARG(0,*ans).r;
shift(LARGPTR(*ans),rr.left-ss.left,rr.top-ss.top);
/* If the sum is not broken then rr.top == ss.top
but if it is broken, the general term in the sum can
be in the next line */
}
}
}
/*______________________________________________________________________*/
static void locate_limit(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on a limit term */
{ term arg,subscript;
int halfheight;
unsigned short arity = (unsigned short)(ARITY(newexpr)-1);
long limwidth = papyrus_to_xpixel(functor_width(LIMIT, (unsigned short)SIZE(newexpr)));
coord level = LEVEL(newexpr);
BIGRECT q = *r;
lterm larg;
long s;
coord x,y,subscriptwidth;
x=y=0;
subscript = ARG(1,newexpr);
if (arity ==2)
arg = ARG(2,newexpr);
else
arg = ARG(3,newexpr);
/* compute the x-coordinate where "lim" should be written */
subscriptwidth = (coord) WIDTH(subscript);
/* not counting the + or - in a one-sided limit */
if(subscriptwidth < limwidth + get_charspace())
s=x;
else
s =(coord)(x + (subscriptwidth - limwidth -get_charspace()/2));
textstyle = ROMAN;
halfheight = SIZE(newexpr) == TENPOINT ? 8 : 6;
/* WWRITE("lim",s,y+level-halfheight,attr); */
s += papyrus_to_xpixel(functor_width(LIMIT, (unsigned short)SIZE(newexpr))); /* next place after "lim" */
q.left = r->left + papyrus_to_xpixel(x);
q.top = r->top + papyrus_to_ypixel(y + level + halfheight);
locate_term(subscript,&q,&larg);
LARGREP(*ans,0,larg);
if(x + subscriptwidth > s)
s=x+subscriptwidth;
if(arity==3)
{ term dir = ARG(2,newexpr);
textstyle = SYMBOLFONT;
/* WPUTCH(sign,s,y+level,attr); */
/* The + or - sign that determines
direction is not selectable on-screen anyway.
But something has to go in as the 1st arg of
*ans, and that something has to be an lterm,
not a term. So we have to convert dir to
an atomic lterm larg. */
SetBigRectEmpty(&larg.r);
larg.symbol = FUNCTOR(dir);
larg.arity = 0;
larg.info = dir.info;
larg.args = NULL;
larg.path = NULL;
larg.linelist = NULL;
LARGREP(*ans,1,larg);
s+=3;
}
// s+= get_charspace(); /* removed 11.19.24 */
s += 10;
q = *r;
q.left = r->left + papyrus_to_xpixel(s);
q.top = r->top + papyrus_to_ypixel(y);
locate_term(arg,&q,&larg);
LARGREP(*ans, arity-1, larg);
}
/*___________________________________________________________________*/
static void locate_eval(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on functor EVAL */
{
term u,index,lo,hi;
block b = GETBLOCK(newexpr);
coord height = b.h;
coord s;
BIGRECT q = *r;
coord x,y;
lterm larg;
x=y=0;
u = ARG(1,newexpr);
index = ARG(2,newexpr); /* is not displayed! */
lo = ARG(3,newexpr);
hi = ARG(4,newexpr);
s = (coord)(y + b.wl - LEVEL(u)); /* put u on the water level line */
q.left = r->left + papyrus_to_xpixel(x);
q.right = r->top + papyrus_to_ypixel(s);
locate_term(u,&q,&larg);
LARGREP(*ans,0,larg);
x = (coord)(x + WIDTH(u) + get_productspace(b.size));
/* Now display draws the eval bar */
x = (coord)(x + get_charspace() + get_lowerlimx());
s = (coord)(y + height - HEIGHT(lo));
q.left = r->left + papyrus_to_xpixel(x);
q.right = r->top + papyrus_to_ypixel(s);
locate_term(lo,&q,&larg);
LARGREP(*ans,2,larg);
q.top = r->top + papyrus_to_ypixel(y);
locate_term(hi,&q,&larg);
LARGREP(*ans,3,larg);
/* Now *ans has no argument in index position, because the
index is not displayed. Still something must be put there;
just make sure its rectangle is empty. */
q = *r;
locate_term(index,&q,&larg);
SetBigRectEmpty(&larg.r);
LARGREP(*ans,1,larg);
}
/*_______________________________________________________________________*/
/* newexpr is a bblocked PR(u,n) */
static void locate_prime(term newexpr,BIGRECT *r, lterm *ans)
{ term u,exp;
// unsigned char *primestring;
unsigned short f;
int flag; /* same cases as in bblock_prime */
char fname[32];
coord level = LEVEL(newexpr);
BIGRECT s = *r;
BIGRECT q;
coord x,y;
lterm larg;
x=y=0;
u = ARG(1,newexpr);
exp = ARG(2,newexpr);
if(ATOMIC(u) ||
(COMPOUND(u) && paren(PR,FUNCTOR(u),LEFT)) /* e.g. for u= s+t, s*t, s^t, -s */
)
/* Then we have no args to print, so go ahead and display u */
{ s.left = r->left + papyrus_to_xpixel(x);
s.top = r->top + papyrus_to_ypixel(y+level-LEVEL(u));
locate_term(u,&s,&larg);
LARGREP(*ans,0,larg);
x = (coord)(x + WIDTH(u));
flag = 0;
}
else /* it's not so simple, u = f(x) and we must display f */
{ flag = 2; /* or maybe 3 if raised exp is required */
f=FUNCTOR(u);
functor_string(f,SCREEN,fname); /* in terms.c */
textstyle = ITALIC;
/* WWRITE(fname,x,y+level-charspace/2,attr); */
#ifndef SVG
if(DEFINED_FUNCTION(f))
x = (coord)(x + text_width(fname,(unsigned short)SIZE(newexpr)));
else
x = (coord)(x + functor_width(f,(unsigned short) SIZE(newexpr));
#else
x = (coord)(x + functor_width(f,(unsigned short) SIZE(newexpr)));
#endif
}
/* Now, either write n primes or a raised exponent if necessary */
/* careful about the y-coordinate of the primes or exponent; e.g.
if printing (a/b)' the prime does not go at the water level of (a/b)
but rather at the top */
if(BB_OBJECT(exp)
//&& *( primestring = *((unsigned char **) (ARGPTR(exp)+1))) == PRIMECHAR
)
{ q = *r;
if(flag) /* e.g. f'(a/b) */
{ textstyle = SYMBOLFONT;
/* WWRITE((char *) primestring,x,y+level-charspace/2,attr); */
q.top = r->top + papyrus_to_ypixel(y + level - get_charspace()/2);
q.left = r->left + papyrus_to_xpixel(x);
locate_term(exp,&q,&larg);
LARGREP(*ans,1,larg);
}
else /* e.g. (a/b)' */
{ textstyle = SYMBOLFONT;
/* WWRITE((char *) primestring,x,y,attr); */
q.top = r->top + papyrus_to_ypixel(y);
q.left = r->left + papyrus_to_xpixel(x);
locate_term(exp,&q,&larg);
LARGREP(*ans,1,larg);
}
}
else /* raised exponent */
{ ++flag; /* now flag is set to the proper case number */
s.left = r->left + papyrus_to_xpixel(x);
if(flag==3) /* e.g. prime(f(a/b),8) */
s.top = r->top + papyrus_to_ypixel(y+level-6-get_charspace()/2);
else /* e.g. prime(a/b,8) */
s.top = r->top + papyrus_to_ypixel(y);
locate_term(exp,&s,&larg);
LARGREP(*ans,1,larg);
}
if(flag == 3 && LEVEL(u) != level)
y = (coord)(y + level-LEVEL(u));
s.top = r->top + papyrus_to_ypixel(y);
s.left = r->left + papyrus_to_xpixel(WIDTH(exp));
locate_term(u,&s,&larg);
/* This gives the rectangles of the args correctly,
but the rectangle of u is set as if the primes weren't there
and the function name shifted to the right. So adjust it */
larg.r.left = r->left;
LARGREP(*ans,0,larg);
}
/*______________________________________________________________*/
static void locate_subscripted_function(term newexpr, BIGRECT *r, lterm *ans)
/* Finish the work of locate_term on a subscripted function,
for example Bessel functions or a constant_of_integration. */
{ term index;
term dummy;
block b;
unsigned short f = FUNCTOR(newexpr);
unsigned short n = ARITY(newexpr);
char fname[32];
int i;
coord x,y;
lterm larg;
BIGRECT s = *r;
coord level = LEVEL(newexpr);
coord depth;
x=y=0;
index = ARG(1,newexpr);
functor_string(f,SCREEN,fname); /* in terms.c */
textstyle = ITALIC;
/* here display writes out fname */
#ifdef SVG
x = (coord)(x + svg_text_width(fname,(unsigned short)SIZE(newexpr)));
#else
x = (coord)(x + text_width(fname,(unsigned short)SIZE(newexpr)));
#endif
s.left = r->left + papyrus_to_xpixel(x);
s.top = r->top + papyrus_to_ypixel(y+level);
locate_term(index,&s,&larg);
LARGREP(*ans,0,larg);
if(n==2) /* constant of integration or Bernoulli number, no variables */
{ ans->r.right = larg.r.right; // added 5.15.13
ans->r.bottom = larg.r.bottom;
return;
}
// x = (coord)(x + WIDTH(index));
dummy = make_term(f,(unsigned short)(ARITY(newexpr)-1));
/* make a term like newexpr but without the index arg */
ARGREP(dummy,0,ARG(0,newexpr));
for(i=1;i<ARITY(dummy);i++)
{ ARGREP(dummy,i,ARG(i+1,newexpr));
}
b = GETBLOCK(dummy);
depth = 0;
for(i=1;i<ARITY(dummy);i++)
depth = (coord)(MAXIMUM(depth,HEIGHT(ARG(i,dummy)) - LEVEL(ARG(i,dummy))));
depth = (coord)(depth + level);
b.h = depth;
SETBLOCK(dummy,b);
locate_term(dummy,&s,&larg);
larg.r.left = r->left; /* adjust as in display_prime */
for(i=1;i<ARITY(dummy);i++)
LARGREP(*ans,i,LARG(i-1,larg));
}
/*_________________________________________________________________*/
bterm extract_bterm(lterm t)
/* extract a bblocked term from an lterm */
{ bterm ans;
char *s,*ss;
int i,err;
term system,tt,vlist;
block b;
unsigned short f = FUNCTOR(t);
unsigned short n;
if(f == AND && LINEUP(t))
{ /* we must send a LINEARSYSTEM term to be bblocked. */
system = make_term(LINEARSYSTEM,2);
tt = abstract(t);
err = is_linear_system(tt,get_currentline(),&vlist);
if(!err)
{ ARGREP(system,0,tt);
ARGREP(system,1,vlist);
err = bblock(system,&ans);
if(!err)
{ SETBLOCK(ans,t.block);
return ans;
}
}
}
if(f == '=' && FACTORME(t))
/* This is an equation which is part of a linear system that has
been located after 'line up variables'. It should be displayed
directly by ldisplay and should not come here. */
assert(0);
if(f == MATRIX || f == VECTOR || f == MATRIXINVERSE ||
/* the lterm does not contain enough information to recover the
bblocked term. Recompute from scratch. */
f == AND || f == OR /* Perhaps the bblocked term should be a MATRIX */
)
{ bblock(abstract(t),&ans);
SETBLOCK(ans,t.block);
if(COLOR(t))
HIGHLIGHT(ans);
return ans;
}
if(ISATOM(t))
{ ans = make_term(f,2);
SETBLOCK(ans,t.block);
/* watch out not to access display strings of atoms that don't have them: */
if(f != LEFT && f != RIGHT) /* are there any others? */
* ((char **) (ARGPTR(ans) + 1)) = *((char **) LARGPTR(t)); /* the display string */
SETFUNCTOR(ans,f,0); /* arity set artificially to zero so ISATOM will work on it */
return ans;
}
if(OBJECT(t))
{ ans = make_term(0,3);
ans.info = t.info;
SETBLOCK(ans,t.block);
s = *((char **) LARGPTR(t)); /* the display string */
ss = (char *) callocate((int) strlen(s)+1, sizeof(char));
if(!ss)
{ nospace();
SETFUNCTOR(ans,ILLEGAL,0);
return ans;
}
strcpy(ss,s);
* ((char **) (ARGPTR(ans) + 1)) = s;
/* This makes a copy of the print string so that
destroy_term can be called on the result of extract_bterm */
memcpy(ARGPTR(ans) + 2, LARGPTR(t)+1, sizeof(term));
/* This copies the data: an int, double, or head of a bignum */
return ans;
}
n = ARITY(t);
if(f == MATRIX || f == VECTOR)
ans = make_term(f,(unsigned short)(n+2));
else
ans = make_term(f,(unsigned short) (n+1));
SETBLOCK(ans,t.block);
for(i=0;i<n;i++)
ARGREP(ans,i+1,extract_bterm(LARG(i,t)));
if(COLOR(t))
SETCOLOR(ans,COLOR(t));
if(f == MATRIX || f == VECTOR)
assert(0);
if(f == '^' && t.block.extra)
{ /* Infix exponent. Adjust the width of the base */
b = GETBLOCK(ARG(1,ans));
b.w = (coord)(b.w + WIDTH(ARG(2,ans)) + 2 * get_powerspace() - get_prefixspace());
SETBLOCK(ARG(1,ans),b);
}
if(DEFINED_FUNCTION(f) && SUBSCRIPTARGS(t))
SET_SUBSCRIPTARGS(ans);
return ans;
}
/*_______________________________________________________________*/
static void locate_and(term bt, BIGRECT *r, lterm *ans)
/* Finish locate_term on an AND term.
Note that an interval-as-and term
a < b < c is bblocked as a < b and void < c.
The corresponding located term has an empty rectangle for the void term,
so it can't be selected. You also can't select either a < b or b < c
out of such an interval-as-and. You can select a, b, c, or the whole
interval-as-and term.
The display code can also handle longer
strings of inequalities than two.
*/
{ BIGRECT s;
term u;
unsigned short n = (unsigned short)(ARITY(bt)-1);
int i;
int level = LEVEL(bt);
s = *r;
for(i=1;i<=n;i++)
{ if(i > 1 && FUNCTOR(ARG(1,ARG(i,bt))) != ILLEGAL)
{ /* not an interval_as_and */
textstyle = SYMBOLFONT;
s.left += papyrus_to_xpixel(get_charspace() + get_sumspace(TENPOINT));
}
u = ARG(i,bt);
s.top = r->top + papyrus_to_ypixel(level-LEVEL(u)); /* line up the levels */
locate_term(u,&s,LARGPTR(*ans)+i-1);
s.left += papyrus_to_xpixel(WIDTH(ARG(i,bt)) + get_sumspace(TENPOINT));
}
}
/*_________________________________________________________________*/
term abstract(lterm t)
/* discard display information from the located term t
to produce an ordinary term;
*/
{ int i,j;
unsigned short n,f,m,k;
term ans,u;
lterm row;
int problemtype;
lterm lu,lv;
if(FUNCTOR(t)== 0) /* an object */
{ term *p;
ans.symbol = 0;
ans.arity = 1;
ans.info = t.info;
p = (term *) ARGPTR(t) + 1;
LVARGPTR(ans) = (arg *) p; // the +1 works on (term *)
/* lterms contain the actual data of an object
after the print-string in ARGPTR(t) */
return ans;
}
f = FUNCTOR(t);
if(ISATOM(t))
{ ans.info = t.info;
ans.symbol = f;
ans.arity = 0;
if(!INEQUALITY(f) && f != ILLEGAL)
set_valuepointers(&ans);
/* the exceptions occur inside LINEARSYSTEM terms */
return ans;
}
n = ARITY(t);
switch(f)
{ case FRACT:
f = '/';
break;
case MATRIX:
problemtype = get_problemtype();
/* The original term may have been an OR
(of equations or inequalities or in general propositions),
or an AND (of linear equations, or under RELATED_RATES,
of more general equations), or a matrix obtained from
a LINEARSYSTEM term, or a genuine MATRIX term.
Since we only have the lterm at hand, we must decide
which from the contents. If it's a genuine matrix
we don't have to do anything special here.
*/
if(ARITY(LARG(0,t)) == 1 && lcontainseq(t))
{ /* only one column */
if(problemtype == RELATED_RATES ||
problemtype == LINEAR_EQUATIONS
)
{ /* it's an AND of the entries of the rows */
ans = make_term(AND,n);
ans.info = t.info;
for(i=0;i<n;i++)
ARGREP(ans,i,abstract(LARG(0,LARG(i,t))));
return ans;
}
/* else it's an OR of the entries of the rows */
ans = make_term(OR,n);
for(i=0;i<n;i++)
ARGREP(ans,i,abstract(LARG(0,LARG(i,t))));
return ans;
}
if(t.block.bra == BRACES)
{ /* we should produce a CASES term */
ans = make_term(CASES,n);
for(i=0;i<n;i++)
{ row = LARG(i,t);
if(FUNCTOR(row) != VECTOR)
assert(0);
if(ARITY(row) != 3)
assert(0);
if(FUNCTOR(ARG(2,row)) != ILLEGAL)
/* it's an "if" row */
u = if1(abstract(LARG(2,row)),abstract(LARG(0,row)));
else
u = abstract(LARG(0,row));
ARGREP(ans,i,u);
}
return ans;
}
break; /* No special treatment for matrices otherwise */
case AND:
if(n==2 &&
(FUNCTOR(LARG(1,t)) == '<' || FUNCTOR(LARG(1,t)) == LE) &&
FUNCTOR(LARG(0,LARG(1,t))) == ILLEGAL
)
{ /* interval_as_and. These are bblocked with an ILLEGAL term
as a < x && void < b, but now we need to restore b on the right
producing a < x && x < b */
term p;
ans = make_term(AND,2);
ans.info = t.info;
ARGREP(ans,0,abstract(LARG(0,t)));
p = make_term(FUNCTOR(LARG(1,t)),2);
copy(ARG(1,ARG(0,ans)),ARGPTR(p));
ARGREP(p,1,abstract(LARG(1,LARG(1,t))));
ARGREP(ans,1,p);
return ans;
}
break;
case LINEARSYSTEM:
ans = make_term(AND,n);
ans.info = t.info;
for(i=0;i<n;i++)
{ lu = LARG(i,t);
m = ARITY(lu);
assert(m >= 3);
k=0;
u = make_term('+',(unsigned short)(m-2));
for(j=0;j<m-2;j++)
{ lv = LARG(j,lu);
if(FUNCTOR(lv) != ILLEGAL)
{ ARGREP(u,j,abstract(lv));
++k;
}
}
if(k==0)
{ RELEASE(u);
u = make_int(0);
}
else if(k==1)
{ term temp = ARG(0,u);
RELEASE(u);
u = temp;
}
else
SETFUNCTOR(u,'+',k);
ARGREP(ans,i,equation(u,abstract(LARG(m-1,lu))));
}
SET_LINEUP(ans);
return ans;
}
ans = make_term(f,n);
ans.info = t.info;
if(f == AND && LINEUP(t))
SET_LINEUP(ans);
if(COLOR(t))
HIGHLIGHT(ans);
if(f == SUM && n == 5)
{ unsigned short m;
for(i=0;i<4;i++)
{ u = abstract(LARG(i,t));
ARGREP(ans,i,u);
}
/* the last arg should be a positive or negative integer; but
the last arg of t is a sum. */
m = ARITY(LARG(4,t));
if(m >= 4 && FUNCTOR(LARG((unsigned short)(m-3),LARG(4,t))) == PSEUDOATOM)
/* the general term is showing */
ARGREP(ans,4,make_int(m-3));
else
ARGREP(ans,4,tnegate(make_int(m-1)));
return ans;
}
for(i=0;i<n;i++)
{ u = abstract(LARG(i,t));
ARGREP(ans,i,u);
}
if(f == '-' && OBJECT(ARG(0,ans)))
SETTYPE(ans,TYPE(ARG(0,ans)));
if(f == '/' && ISINTEGER(ARG(0,ans)) && ISINTEGER(ARG(1,ans)))
SETTYPE(ans,RATIONAL);
if(f == '/' && OBJECT(ARG(0,ans)) && TYPE(ARG(0,ans)) == BIGNUM &&
OBJECT(ARG(1,ans)) && TYPE(ARG(1,ans)) == BIGNUM
)
SETTYPE(ans,BIGRAT);
return ans;
}
/*___________________________________________________________*/
int lcontainseq(lterm t)
/* does t contain an inequality symbol or '=' ?
If so return 1, if not return 0.
*/
{ unsigned short n;
int i;
unsigned short f = FUNCTOR(t);
if(INEQUALITY(f))
return 1;
if(ATOMIC(t))
return 0;
n = ARITY(t);
for(i=0;i<n;i++)
{ if(lcontainseq(LARG(i,t)))
return 1;
}
return 0;
}
/*______________________________________________________________________*/
int lequals(lterm a, lterm b)
/* return 1 if a and b represent equal terms */
{ unsigned short n;
int i;
if(ATOMIC(a) && ATOMIC(b))
return equals(abstract(a),abstract(b));
/* abstract allocates no space on atomic terms */
if(ATOMIC(a) || ATOMIC(b))
return 0;
if(FUNCTOR(a) != FUNCTOR(b) || ARITY(a) != ARITY(b))
return 0;
n = ARITY(a);
for(i=0;i<n;i++)
{ if(!lequals(LARG(i,a),LARG(i,b)))
return 0;
}
return 1;
}
/*______________________________________________________________________*/
int linterval_as_and(lterm t)
/* return 1 if t is a located interval_as_and term, 0 if not.
These terms are located with an ILLEGAL atom as the 0th arg
of the right-hand inequality.
*/
{ lterm left,right;
if(FUNCTOR(t) != AND || ARITY(t) != 2)
return 0;
left = LARG(0,t);
right = LARG(1,t);
if(FUNCTOR(left) != LE && FUNCTOR(left) != '<')
return 0;
if(FUNCTOR(right) != LE && FUNCTOR(right) != '<')
return 0;
if(FUNCTOR(LARG(0,right)) == ILLEGAL)
return 1;
return 0;
}
/*__________________________________________________________________________*/
void strip_parens(lterm *t)
/* change t->block to make t be a located version of the
term t without its parentheses.
This must stay in sync with save_space in display.c; if you
change one, change the other one too.
*/
{ int savespace; /* width due to one parenthesis and space after */
unsigned short f = FUNCTOR(*t);
t->block.leftbra = t->block.rightbra = 0;
if(f == ABSFUNCTOR)
savespace = 1 + get_parenspace(t->block.size);
else if(
OBJECT(*t) ||
(f == '-' && OBJECT(LARG(0,*t))) ||
(f == '-' && t->block.size == EIGHTPOINT)
)
savespace = (coord)(get_parenwidth(t->block.size) + get_parenspace(t->block.size)/2);
else
savespace = (coord)(get_parenwidth(t->block.size) + get_parenspace(t->block.size));
t->block.w = (unsigned short) (t->block.w - 2*savespace);
}
/*___________________________________________________________________________*/
void move_lterm_up(lterm *t, int y)
/* subtract y from the top and bottom of the rectangle of *t and all
of the subterms of t. */
{ unsigned short n;
int i;
t->r.top -= y;
t->r.bottom -=y;
if(ATOMIC(*t))
return;
n = ARITY(*t);
for(i=0;i<n;i++)
move_lterm_up(LARGPTR(*t) + i, y);
return;
}
/*_______________________________________________________________________*/
lterm located_subrange(lterm t, int j, int m)
/* return a located term corresponding to the subrange of
arguments j,j+1,...,j+m-1 of t. It is presumed that 0 <= j and
j+m-1 < ARITY(t). The located subterm returned at present has
the same .block as t, rather than a correct .block field.
*/
{ lterm ans = t;
int i;
ans.args = callocate(m,sizeof(lterm));
if(ans.args == NULL)
{ nospace();
SETFUNCTOR(ans,ILLEGAL,0);
return ans;
}
SETFUNCTOR(ans,FUNCTOR(t),m);
for(i=0;i<m;i++)
LARGREP(ans,i,LARG(j+i,t));
/* Now adjust ans.r; this code isn't going to
work if t is a broken lterm and the subrange extends over
more than one line. */
if(j > 0)
{ ans.r.left = LARG(j,t).r.left;
if(LARG(j,t).block.leftbra && LARG(j,t).block.bra != BARS)
ans.r.left -= papyrus_to_xpixel(paren_displacement(LARG(j,t)));
}
if(j+m < ARITY(t))
{ ans.r.right = LARG(j+m-1,t).r.right;
if(LARG(j+m-1,t).block.rightbra && LARG(j+m-1,t).block.bra != BARS)
ans.r.right += papyrus_to_xpixel(paren_displacement(LARG(j+m-1,t)));
}
/* ans.block is still wrong. I hope we don't need it. */
return ans;
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists