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:
parent
41b28f6a62
commit
9b14ec8755
|
@ -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
19
TODO.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
|
26
src/flow.c
26
src/flow.c
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in New Issue