Compare commits
2 commits
bc35b18da0
...
038dd9f4a8
Author | SHA1 | Date | |
---|---|---|---|
038dd9f4a8 | |||
cf754a7a34 |
6 changed files with 45 additions and 22 deletions
|
@ -301,7 +301,7 @@ Canvas {
|
||||||
} else {
|
} else {
|
||||||
for(var x = 1; x < drawMaxX; x += 1) {
|
for(var x = 1; x < drawMaxX; x += 1) {
|
||||||
var drawX = x*xaxisstep1
|
var drawX = x*xaxisstep1
|
||||||
var txtX = xaxisstepExpr.simplify(x)
|
var txtX = xaxisstepExpr.simplify(x).replace(/^\((.+)\)$/, '$1')
|
||||||
var textSize = measureText(ctx, txtX, 6).height
|
var textSize = measureText(ctx, txtX, 6).height
|
||||||
drawVisibleText(ctx, txtX, x2px(drawX)-4, axisxpx+textsize/2+textSize)
|
drawVisibleText(ctx, txtX, x2px(drawX)-4, axisxpx+textsize/2+textSize)
|
||||||
drawVisibleText(ctx, '-'+txtX, x2px(-drawX)-4, axisxpx+textsize/2+textSize)
|
drawVisibleText(ctx, '-'+txtX, x2px(-drawX)-4, axisxpx+textsize/2+textSize)
|
||||||
|
@ -311,7 +311,7 @@ Canvas {
|
||||||
if(showygrad) {
|
if(showygrad) {
|
||||||
for(var y = 0; y < drawMaxY; y += 1) {
|
for(var y = 0; y < drawMaxY; y += 1) {
|
||||||
var drawY = y*yaxisstep1
|
var drawY = y*yaxisstep1
|
||||||
var txtY = yaxisstepExpr.simplify(y)
|
var txtY = yaxisstepExpr.simplify(y).replace(/^\((.+)\)$/, '$1')
|
||||||
var textSize = ctx.measureText(txtY).width
|
var textSize = ctx.measureText(txtY).width
|
||||||
drawVisibleText(ctx, txtY, axisypx-6-textSize, y2px(drawY)+4+(10*(y==0)))
|
drawVisibleText(ctx, txtY, axisypx-6-textSize, y2px(drawY)+4+(10*(y==0)))
|
||||||
if(y != 0)
|
if(y != 0)
|
||||||
|
|
|
@ -521,7 +521,7 @@ Expression.prototype.substitute = function (variable, expr) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Expression.prototype.evaluate = function (values) {
|
Expression.prototype.evaluate = function (values) {
|
||||||
values = values || {};
|
values = Object.assign({}, values, this.parser.consts)
|
||||||
return evaluate(this.tokens, this, values);
|
return evaluate(this.tokens, this, values);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,8 +541,9 @@ Expression.prototype.variables = function (options) {
|
||||||
var vars = [];
|
var vars = [];
|
||||||
getSymbols(this.tokens, vars, options);
|
getSymbols(this.tokens, vars, options);
|
||||||
var functions = this.functions;
|
var functions = this.functions;
|
||||||
|
var consts = this.parser.consts
|
||||||
return vars.filter(function (name) {
|
return vars.filter(function (name) {
|
||||||
return !(name in functions);
|
return !(name in functions) && !(name in consts);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -580,7 +581,7 @@ function TokenStream(parser, expression) {
|
||||||
this.unaryOps = parser.unaryOps;
|
this.unaryOps = parser.unaryOps;
|
||||||
this.binaryOps = parser.binaryOps;
|
this.binaryOps = parser.binaryOps;
|
||||||
this.ternaryOps = parser.ternaryOps;
|
this.ternaryOps = parser.ternaryOps;
|
||||||
this.consts = parser.consts;
|
this.builtinConsts = parser.builtinConsts;
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
this.savedPosition = 0;
|
this.savedPosition = 0;
|
||||||
this.savedCurrent = null;
|
this.savedCurrent = null;
|
||||||
|
@ -700,8 +701,8 @@ TokenStream.prototype.isConst = function () {
|
||||||
}
|
}
|
||||||
if (i > startPos) {
|
if (i > startPos) {
|
||||||
var str = this.expression.substring(startPos, i);
|
var str = this.expression.substring(startPos, i);
|
||||||
if (str in this.consts) {
|
if (str in this.builtinConsts) {
|
||||||
this.current = this.newToken(TNUMBER, this.consts[str]);
|
this.current = this.newToken(TNUMBER, this.builtinConsts[str]);
|
||||||
this.pos += str.length;
|
this.pos += str.length;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1792,12 +1793,12 @@ class Parser {
|
||||||
join: arrayJoin
|
join: arrayJoin
|
||||||
};
|
};
|
||||||
|
|
||||||
this.consts = {
|
// These constants will automatically be replaced the MOMENT they are parsed.
|
||||||
E: Math.E,
|
// (Original consts from the parser)
|
||||||
PI: Math.PI,
|
this.builtinConsts = {};
|
||||||
'true': true,
|
// These consts will only be replaced when the expression is evaluated.
|
||||||
'false': false
|
this.consts = {}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(expr) {
|
parse(expr) {
|
||||||
|
|
|
@ -26,13 +26,17 @@ const DERIVATION_PRECISION = 0.1
|
||||||
|
|
||||||
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manually
|
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manually
|
||||||
"pi": Math.PI,
|
"pi": Math.PI,
|
||||||
|
"PI": Math.PI,
|
||||||
"π": Math.PI,
|
"π": Math.PI,
|
||||||
"inf": Infinity,
|
"inf": Infinity,
|
||||||
"infinity": Infinity,
|
"infinity": Infinity,
|
||||||
"Infinity": Infinity,
|
"Infinity": Infinity,
|
||||||
"∞": Infinity,
|
"∞": Infinity,
|
||||||
"e": Math.E,
|
"e": Math.E,
|
||||||
"E": Math.E
|
"E": Math.E,
|
||||||
|
"true": true,
|
||||||
|
"false": false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentVars = {}
|
var currentVars = {}
|
||||||
|
@ -54,3 +58,4 @@ parser.functions.derivative = function(f, variable, x) {
|
||||||
f = parser.parse(f).toJSFunction(variable, currentVars)
|
f = parser.parse(f).toJSFunction(variable, currentVars)
|
||||||
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
*/
|
*/
|
||||||
class Expression {
|
class Expression {
|
||||||
constructor(expr) {
|
constructor(expr) {
|
||||||
this.expr = expr
|
this.expr = Utils.exponentsToExpression(expr)
|
||||||
this.calc = C.parser.parse(expr).simplify()
|
this.calc = C.parser.parse(this.expr).simplify()
|
||||||
this.cached = this.isConstant()
|
this.cached = this.isConstant()
|
||||||
this.cachedValue = this.cached && this.allRequirementsFullfilled() ? this.calc.evaluate(C.currentObjectsByName) : null
|
this.cachedValue = this.cached && this.allRequirementsFullfilled() ? this.calc.evaluate(C.currentObjectsByName) : null
|
||||||
this.latexMarkup = Latex.expression(this.calc.tokens)
|
this.latexMarkup = Latex.expression(this.calc.tokens)
|
||||||
|
@ -68,6 +68,7 @@ class Expression {
|
||||||
|
|
||||||
simplify(x) {
|
simplify(x) {
|
||||||
var expr = this.calc.substitute('x', x).simplify()
|
var expr = this.calc.substitute('x', x).simplify()
|
||||||
|
print(this.expr, this.calc.substitute('x', x), expr)
|
||||||
if(expr.evaluate() == 0) return '0'
|
if(expr.evaluate() == 0) return '0'
|
||||||
var str = Utils.makeExpressionReadable(expr.toString());
|
var str = Utils.makeExpressionReadable(expr.toString());
|
||||||
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
||||||
|
|
|
@ -62,6 +62,11 @@ var powerpos = {
|
||||||
"z": "ᶻ"
|
"z": "ᶻ"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exponents = [
|
||||||
|
"⁰","¹","²","³","⁴","⁵","⁶","⁷","⁸","⁹"
|
||||||
|
]
|
||||||
|
var exponentReg = new RegExp('(['+exponents.join('')+']+)', 'g')
|
||||||
|
|
||||||
var indicepos = {
|
var indicepos = {
|
||||||
"-": "₋",
|
"-": "₋",
|
||||||
"+": "₊",
|
"+": "₊",
|
||||||
|
@ -251,14 +256,14 @@ function makeExpressionReadable(str) {
|
||||||
// Other
|
// Other
|
||||||
[/ \* /g, '×'],
|
[/ \* /g, '×'],
|
||||||
[/ \^ /g, '^'],
|
[/ \^ /g, '^'],
|
||||||
[/\^\(([^\^]+)\)/g, function(match, p1) { return textsup(p1) }],
|
[/\^\(([\d\w+-]+)\)/g, function(match, p1) { return textsup(p1) }],
|
||||||
[/\^([^ "]+)/g, function(match, p1) { return textsup(p1) }],
|
[/\^([\d\w+-]+)/g, function(match, p1) { return textsup(p1) }],
|
||||||
[/_\(([^_]+)\)/g, function(match, p1) { return textsub(p1) }],
|
[/_\(([\d\w+-]+)\)/g, function(match, p1) { return textsub(p1) }],
|
||||||
[/_([^ "]+)/g, function(match, p1) { return textsub(p1) }],
|
[/_([\d\w+-]+)/g, function(match, p1) { return textsub(p1) }],
|
||||||
[/\[([^\[\]]+)\]/g, function(match, p1) { return textsub(p1) }],
|
[/\[([^\[\]]+)\]/g, function(match, p1) { return textsub(p1) }],
|
||||||
[/(\d|\))×/g, '$1'],
|
[/(\d|\))×/g, '$1'],
|
||||||
//[/×(\d|\()/g, '$1'],
|
//[/×(\d|\()/g, '$1'],
|
||||||
[/[^a-z]\(([^)(+.\/-]+)\)/g, "$1"],
|
[/([^a-z])\(([^)(+.\/-]+)\)/g, "$1×$2"],
|
||||||
[/integral\((.+),\s?(.+),\s?("|')(.+)("|'),\s?("|')(.+)("|')\)/g, function(match, a, b, p1, body, p2, p3, by, p4) {
|
[/integral\((.+),\s?(.+),\s?("|')(.+)("|'),\s?("|')(.+)("|')\)/g, function(match, a, b, p1, body, p2, p3, by, p4) {
|
||||||
if(a.length < b.length) {
|
if(a.length < b.length) {
|
||||||
return `∫${textsub(a)}${textsup(b)} ${body} d${by}`
|
return `∫${textsub(a)}${textsup(b)} ${body} d${by}`
|
||||||
|
@ -351,3 +356,14 @@ function getRandomColor() {
|
||||||
function escapeHTML(str) {
|
function escapeHTML(str) {
|
||||||
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') ;
|
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses exponents and replaces them with expression values
|
||||||
|
* @param {string} expression - The expression to replace in.
|
||||||
|
* @return {string} The parsed expression
|
||||||
|
*/
|
||||||
|
function exponentsToExpression(expression) {
|
||||||
|
return expression.replace(exponentReg, (m, exp) => '^' + exp.split('').map((x) => exponents.indexOf(x)).join(''))
|
||||||
|
}
|
||||||
|
|
|
@ -79,4 +79,4 @@ Language files translations located at LogarithmPlotter/i18n are licensed under
|
||||||
|
|
||||||
LogarithmPlotter includes [expr-eval](https://github.com/silentmatt/expr-eval) a port of [ndef.parser](https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html) by Raphael Graf <r@undefined.ch>, ported to javascript by Matthew Crumley <email@matthewcrumley.com> (http://silentmatt.com/), and then to QMLJS by Ad5001.
|
LogarithmPlotter includes [expr-eval](https://github.com/silentmatt/expr-eval) a port of [ndef.parser](https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html) by Raphael Graf <r@undefined.ch>, ported to javascript by Matthew Crumley <email@matthewcrumley.com> (http://silentmatt.com/), and then to QMLJS by Ad5001.
|
||||||
|
|
||||||
The code is licensed under the [MIT License](https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt).
|
The specific file (LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/expr-eval.js) is licensed under the [MIT License](https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt).
|
||||||
|
|
Loading…
Reference in a new issue