mirror of
https://gitlab.com/c3d/db48x.git
synced 2024-09-27 15:20:29 +02:00
equations: Add graphical rendering for integrate
Render integrals graphically, in line with sums and products. Fixes: #1174 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
parent
3ac9ce15d6
commit
4d7cbf0b3a
9 changed files with 91 additions and 15 deletions
BIN
color-images/integral-add.png
Normal file
BIN
color-images/integral-add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
color-images/integral-div.png
Normal file
BIN
color-images/integral-div.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
color-images/integral.png
Normal file
BIN
color-images/integral.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
images/integral-add.png
Normal file
BIN
images/integral-add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
images/integral-div.png
Normal file
BIN
images/integral-div.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
images/integral.png
Normal file
BIN
images/integral.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -1725,7 +1725,7 @@ grob_p expression::prefix(grapher &g,
|
|||
}
|
||||
|
||||
|
||||
grob_p expression::sumprod(grapher &g, bool isprod,
|
||||
grob_p expression::sumprod(grapher &g, id oid, sumprod_fn shape,
|
||||
coord vi, grob_g index,
|
||||
coord vf, grob_g first,
|
||||
coord vl, grob_g last,
|
||||
|
@ -1738,20 +1738,39 @@ grob_p expression::sumprod(grapher &g, bool isprod,
|
|||
using size = blitter::size;
|
||||
|
||||
|
||||
if (!index || !first || !last || !expr)
|
||||
if (!index || !first || !last || !expr || !shape)
|
||||
return nullptr;
|
||||
|
||||
if (oid == ID_Integrate)
|
||||
{
|
||||
// Order of arguments is not identical between sum and integrate
|
||||
// sum(index;first;last;expr)
|
||||
// integrate(first;last;expr;index)
|
||||
std::swap(last, expr); // integrate(first;last;index;expr)
|
||||
std::swap(first, last); // integrate(first;index;last;expr)
|
||||
std::swap(index, first); // integrate(index;first;last;expr)
|
||||
}
|
||||
|
||||
auto fid = g.font;
|
||||
g.reduce_font();
|
||||
grob_g lower = infix(g, vi, index, 0, "=", vf, first);
|
||||
grob_g lower = (oid == ID_Integrate
|
||||
? +first
|
||||
: infix(g, vi, index, 0, "=", vf, first));
|
||||
g.font = fid;
|
||||
if (!lower)
|
||||
return nullptr;
|
||||
|
||||
if (oid == ID_Integrate)
|
||||
{
|
||||
expr = infix(g, ve, expr, 0, "d", vi, index);
|
||||
ve = g.voffset;
|
||||
if (!expr)
|
||||
return nullptr;
|
||||
}
|
||||
grob::surface xs = expr->pixels();
|
||||
size xh = xs.height();
|
||||
size xw = xs.width();
|
||||
grob_g sign = isprod ? product(g, xh) : sum(g, xh);
|
||||
grob_g sign = shape(g, xh);
|
||||
if (!sign)
|
||||
return nullptr;
|
||||
|
||||
|
@ -1829,6 +1848,29 @@ grob_p expression::product(grapher &g, blitter::size h)
|
|||
}
|
||||
|
||||
|
||||
grob_p expression::integral(grapher &g, blitter::size h)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Create an 'integral' sign of height h
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
using size = blitter::size;
|
||||
size w = 32;
|
||||
grob_g result = g.grob(w, h);
|
||||
if (!result)
|
||||
return nullptr;
|
||||
|
||||
grob::surface rs = result->pixels();
|
||||
rs.fill (0, 0, w-1, h-1, g.background);
|
||||
rs.fill (w/2-2, w/4, w/2+1, h-w/4, g.foreground);
|
||||
rect rc = rs.clip();
|
||||
rs.clip(0, 0, w, w/4);
|
||||
rs.ellipse(w/2-1, 2, w-5, w/2-1, 3, g.foreground);
|
||||
rs.clip(0, h-w/4, w, h-1);
|
||||
rs.ellipse(4, h-w/2, w/2-0, h-3, 3, g.foreground);
|
||||
rs.clip(rc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline cstring mulsep()
|
||||
|
@ -1840,6 +1882,18 @@ static inline cstring mulsep()
|
|||
}
|
||||
|
||||
|
||||
inline expression::sumprod_fn expression::sumprod_shape(id oid)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Return the associated shape function
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
return oid == ID_Sum ? sum
|
||||
: oid == ID_Product ? product
|
||||
: oid == ID_Integrate ? integral
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
grob_p expression::graph(grapher &g, uint depth, int &precedence)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Render a single object as a graphical object
|
||||
|
@ -2021,22 +2075,30 @@ grob_p expression::graph(grapher &g, uint depth, int &precedence)
|
|||
case 4:
|
||||
{
|
||||
id oid = obj->type();
|
||||
if (oid == ID_Sum || oid == ID_Product)
|
||||
if (sumprod_fn shape = sumprod_shape(oid))
|
||||
{
|
||||
int eprec = 0;
|
||||
auto fid = g.font;
|
||||
grob_g expr = graph(g, depth, eprec);
|
||||
coord ve = g.voffset;
|
||||
g.reduce_font();
|
||||
if (oid != ID_Integrate)
|
||||
g.reduce_font();
|
||||
grob_g last = graph(g, depth, eprec);
|
||||
coord vl = g.voffset;
|
||||
if (oid == ID_Integrate)
|
||||
{
|
||||
// 'last' is really the expression
|
||||
if (eprec < MULTIPLICATIVE)
|
||||
last = parentheses(g, last);
|
||||
g.reduce_font();
|
||||
}
|
||||
grob_g first = graph(g, depth, eprec);
|
||||
coord vf = g.voffset;
|
||||
grob_g index = graph(g, depth, eprec);
|
||||
coord vi = g.voffset;
|
||||
g.font = fid;
|
||||
|
||||
return sumprod(g, oid == ID_Product,
|
||||
return sumprod(g, oid, shape,
|
||||
vi, index,
|
||||
vf, first,
|
||||
vl, last,
|
||||
|
|
|
@ -309,13 +309,17 @@ public:
|
|||
coord vx, cstring pfx,
|
||||
coord vy, grob_g y,
|
||||
int dir=0);
|
||||
static grob_p sumprod(grapher &g, bool product,
|
||||
coord vi, grob_g index,
|
||||
coord vf, grob_g first,
|
||||
coord vl, grob_g last,
|
||||
coord ve, grob_g expr);
|
||||
static grob_p sum(grapher &g, blitter::size h);
|
||||
static grob_p product(grapher &g, blitter::size h);
|
||||
|
||||
typedef grob_p (*sumprod_fn)(grapher &g, blitter::size h);
|
||||
static grob_p sumprod(grapher &g, id oid, sumprod_fn shape,
|
||||
coord vi, grob_g index,
|
||||
coord vf, grob_g first,
|
||||
coord vl, grob_g last,
|
||||
coord ve, grob_g expr);
|
||||
static grob_p sum(grapher &g, blitter::size h);
|
||||
static grob_p product(grapher &g, blitter::size h);
|
||||
static grob_p integral(grapher &g, blitter::size h);
|
||||
static sumprod_fn sumprod_shape(id oid);
|
||||
|
||||
|
||||
public:
|
||||
|
|
12
src/tests.cc
12
src/tests.cc
|
@ -172,7 +172,7 @@ void tests::run(uint onlyCurrent)
|
|||
{
|
||||
here().begin("Current");
|
||||
if (onlyCurrent & 1)
|
||||
units_and_conversions();
|
||||
editor_operations();
|
||||
if (onlyCurrent & 2)
|
||||
demo_ui();
|
||||
if (onlyCurrent & 4)
|
||||
|
@ -1131,6 +1131,16 @@ void tests::editor_operations()
|
|||
step("Implicit multiplication")
|
||||
.test(CLEAR, "'2X'", ENTER).expect("'2·X'");
|
||||
|
||||
step("Graphical rendering of integrals - Simple expression")
|
||||
.test(CLEAR, "'integrate(A;B;sin(X);X)'", ENTER, EXIT)
|
||||
.image_noheader("integral");
|
||||
step("Graphical rendering of integrals - Additive expression")
|
||||
.test(CLEAR, "'integrate(A;B;1+sin(X);X)'", ENTER, EXIT)
|
||||
.image_noheader("integral-add");
|
||||
step("Graphical rendering of integrals - Divide expression")
|
||||
.test(CLEAR, "'integrate(A;B;1/sin(X);X)'", ENTER, EXIT)
|
||||
.image_noheader("integral-div");
|
||||
|
||||
step("Enter X mod Y and checking it can be edited")
|
||||
.test(CLEAR, NOSHIFT, F, "X", RSHIFT, L, F3, "Y")
|
||||
.editor("'X mod Y'")
|
||||
|
|
Loading…
Reference in a new issue