core: add vectors and limits

Also fix a bug in the computation of group sizes, due to subscripts and
superscripts being counted before their final layout was decided.
This commit is contained in:
Lephenixnoir 2019-05-31 13:53:34 -04:00
parent 41b28f6a62
commit 9b14ec8755
6 changed files with 126 additions and 36 deletions

View File

@ -24,7 +24,8 @@ List of currently supported elements:
* Subscripts and superscripts (`_` and `^`)
* Grouping parentheses, brackets and braces (`\left` and `\right`)
* Grouping angle brackets, vertical lines, and dots (invisible)
* Summation symbols
* Sums, products and integrals (`\sum`, `\prod` and `\int`)
* Vectors (`\vec`) and limits (`\lim`)
Features that are partially implemented (and what is left to finish them):
@ -40,7 +41,7 @@ See the `TODO.md` file for more features to come.
First specify the platform you want to use :
* `cli` is for command-line tests, with no visualization (PC)
* `sdl2` is an SDL interface with visualization (font support coming) (PC)
* `sdl2` is an SDL interface with visualization (PC)
* `fx9860g` builds the library for fx-9860G targets (calculator)
* `fxcg50` builds the library for fx-CG 50 targets (calculator)

19
TODO.md
View File

@ -1,11 +1,22 @@
* Write real error messages
* Support Unicode symbols (probably requires help from the font side, urgh)
Available blocks:
-> U+0020 .. U+007F (128) ASCII
-> U+00A0 .. U+00FF (96) Latin-1 Supplement
-> U+0390 .. U+03CF (64) Greek
-> U+2010 .. U+215F (80) General punctuation
-> U+2070 .. U+209F (48) Subscripts and superscripts
-> U+2160 .. U+217F (32) Roman numerals
-> U+2190 .. U+21FF (112) Arrows
Blocks to come:
-> U+2200 .. ? Mathematical operators
-> U+25A0 .. U+25FF (96) Geometric shapes
* Don't use TEX_LAYOUT_SPACING for everything, just make it the default
* Add a parameter to resolve as inline style or display style
* Support character-level spacing
* Parametrize character-level and word-level spacing
* Be more generic in what nodes have display mode by default
* Reduce horizontal spacing by using a proportional font
* Have a decent variable-height font system in gint
* Add square roots, and honor TEX_SQRT_SLANTED and TEX_SQRT_BAR_LENGTH
* Add vectors
* Add limits
* Add matrices

View File

@ -34,6 +34,15 @@
/* Whether to place bounds above and below integrals (display mode) */
#define TEX_INT_DISPLAY 0
/* Height of the integral symbol */
#define TEX_INT_HEIGHT 21
/* Length of arrow extensions from the tip of a vector */
#define TEX_VEC_ARROW_LENGTH 2
/* Horizontal margin around vector */
#define TEX_VEC_MARGIN 0
/* Extra height between argument and vector */
#define TEX_VEC_SPACING TEX_LAYOUT_SPACING
/* Make the vertical part of the square root symbol slanted at low heights */
#define TEX_SQRT_SLANTED 1

View File

@ -243,11 +243,9 @@ void supsubscript_render(struct TeX_Node const * node, int x, int y,
//---
// Summation symbol.
// * args: 0 (ignored)
// * flow: default
// * flow: display mode when available
//
// Summation symbols are just nodes with a constant size and function.
// They are automatically placed in display mode except if the user asked
// for inline mode.
//---
void sum_size(struct TeX_Node *node)
@ -271,9 +269,7 @@ void sum_render(__attribute__((unused)) struct TeX_Node const * node, int x,
//---
// Product symbol.
// * args: 0 (ignored)
// * flow: default
//
// Just like summation symbols, uses display mode by default.
// * flow: display mode when available
//---
void prod_size(struct TeX_Node *node)
@ -302,8 +298,8 @@ void prod_render(__attribute__((unused)) struct TeX_Node const * node, int x,
void int_size(struct TeX_Node *node)
{
node->width = 5;
node->height = 19;
node->line = 9;
node->height = TEX_INT_HEIGHT;
node->line = TEX_INT_HEIGHT >> 1;
}
void int_render(struct TeX_Node const * node, int x, int y, int color)
@ -317,6 +313,79 @@ void int_render(struct TeX_Node const * node, int x, int y, int color)
TeX_pixel(x + 1, y + h - 1, color);
}
//---
// Vectors
// * args: 1 (<1 invalidate, >1 ignore)
// * flow: normal
//
// This "\vec" command is an equivalent of "\overrightarrow" in LaTeX, it
// covers its argument and extends.
//
// Graphical parameters:
//
// TEX_VEC_ARROW_LENGTH:
// Number of pixels that extend diagonally from the tip of the arrow.
// TEX_VEC_SPACING:
// Number of pixels of spacing between argument and vector
// TEX_VEC_MARGIN:
// Horizontal margin around the argument.
//
// ------> ] related to TEX_VEC_ARROW_LENGTH
// ] TEX_VEC_SPACING
// 1
// |_| |_|
// TEX_VEC_MARGIN
//---
void vec_size(struct TeX_Node *node)
{
int arrow_height = 2 * TEX_VEC_ARROW_LENGTH + 1;
node->width = w(0) + 2 * TEX_VEC_MARGIN;
node->height = h(0) + TEX_VEC_SPACING + arrow_height;
node->line = l(0) + TEX_VEC_SPACING + arrow_height;
}
void vec_render(struct TeX_Node const * node, int x, int y, int color)
{
int length = TEX_VEC_ARROW_LENGTH;
int arrow_height = 2 * length + 1;
int w = node->width;
/* Draw arrow */
TeX_line(x, y + length, x + w - 1, y + length, color);
TeX_line(x + w - 1, y + length, x + w - 1 - length, y, color);
TeX_line(x + w - 1, y + length, x + w - 1 - length, y + 2 * length,
color);
/* First argument */
render_flow(args[0],
x + TEX_VEC_MARGIN,
y + TEX_VEC_SPACING + arrow_height,
color);
}
//---
// Limit notation
// * args: 0 (ignored)
// * flow: display mode when available
//---
void lim_size(struct TeX_Node *node)
{
int w, h;
TeX_size("lim", &w, &h);
node->width = w;
node->height = h;
node->line = node->height >> 1;
}
void lim_render(__attribute__((unused)) struct TeX_Node const * node, int x,
int y, int color)
{
TeX_text("lim", x, y, color);
}
//---
// The class table and lookup functions
//---
@ -335,13 +404,15 @@ struct TeX_Class TeX_table[] = {
{ "\\sup", supsubscript_size, supsubscript_render },
{ "\\sub", supsubscript_size, supsubscript_render },
/* Large operator symbols */
/* Large operator symbols, integral */
{ "sum", sum_size, sum_render },
{ "prod", prod_size, prod_render },
/* Integral */
{ "int", int_size, int_render },
/* Vectors, limits */
{ "vec", vec_size, vec_render },
{ "lim", lim_size, lim_render },
/* NULL terminator */
{ NULL },
};

View File

@ -221,11 +221,11 @@ void group_open(struct group *group, struct TeX_Node *left)
}
/* group_update(): Update a group with a new node */
void group_update(struct group *group, struct TeX_Node *node)
void group_update(struct group *group, struct chunk *chunk)
{
/* Account for node displacement around baseline */
group->above = max(node->line - node->l, group->above);
group->below = max(node->height - node->line + node->l, group->below);
group->above = max(chunk->line, group->above);
group->below = max(chunk->height - chunk->line, group->below);
}
/* group_close(): Close a group with its right node */
@ -259,10 +259,12 @@ void group_close(struct group *group, struct TeX_Node *right)
// Laying out flows
//---
static void update(struct chunk *c, int *x, int *above, int *below)
static void update(struct chunk *c, struct group *g, int *x, int *above,
int *below)
{
if(!chunk_set(c)) return;
chunk_compute(c);
group_update(g, c);
*x += c->width + TEX_LAYOUT_SPACING;
*above = max(*above, c->line - c->base->l);
@ -290,7 +292,6 @@ void size_flow(struct TeX_Flow *flow)
{
char const *class = "";
size_node(node);
group_update(g, node);
if(node->type != TEX_NODECLASS_TEXT)
class = TeX_table[node->type - 1].name;
@ -305,11 +306,13 @@ void size_flow(struct TeX_Flow *flow)
chunk_set_subscript(&c, node);
continue;
}
/* Leave the last chunk and make a new one */
update(&c, g, &x, &above, &below);
if(!strcmp(class, "left") && g-groups < TEX_LEFTRIGHT_NESTING)
{
g++;
group_open(g, node);
group_update(g, node);
}
if(!strcmp(class, "right") && g - groups > 0)
{
@ -317,13 +320,12 @@ void size_flow(struct TeX_Flow *flow)
g--;
}
/* Leave the last chunk and make a new one */
update(&c, &x, &above, &below);
int mode = TEX_CHUNK_INLINE;
if(!strcmp(class, "sum") || !strcmp(class, "prod")
if(!strcmp(class, "sum")
|| !strcmp(class, "prod")
|| !strcmp(class, "lim")
#if TEX_INT_DISPLAY
|| !strcmp(class, "int")
|| !strcmp(class, "int")
#endif
)
{
@ -335,7 +337,7 @@ void size_flow(struct TeX_Flow *flow)
}
/* Finish the last chunk */
update(&c, &x, &above, &below);
update(&c, g, &x, &above, &below);
flow->height = above + below;
flow->line = above;

View File

@ -104,10 +104,6 @@ void intf_text(char const *str, int x, int y, int color)
SDL_RenderCopy(r, font, &src, &dst);
x += FONT_WIDTH + 1;
}
// SDL_Rect rect = { .x = x, .y = y };
// intf_size(str, &rect.w, &rect.h);
// SDL_RenderDrawRect(r, &rect);
}
//---
@ -170,9 +166,9 @@ int main(void)
{
char const * formula =
"\\frac{x^7\\left[X,Y\\right]+3\\left|\\frac{A}{B}\\right>}"
"{\\prod_{k=1}^n\\left\\{\\frac{a_k+b_k}{k!}\\right\\}^5}"
" + \\sum_{k=1}^n\\frac{(b-a)^k}{k!}"
"+\\int_a^b\\frac{(b-t)^{n+1}}{n!}dt";
"{\\lim_{x->0}\\left\\{\\frac{a_k+b_k}{k!}\\right\\}^5}"
" + \\int_a^b\\frac{\\left(b-t\\right)^{n+1}}{n!}dt"
" + \\vec{A}.\\vec{B}";
struct TeX_Flow *flow = TeX_parse(formula);
if(!flow) { puts("parsing error!"); return 1; }