2022-01-19 15:43:28 +00:00
|
|
|
|
/**
|
2022-03-05 16:49:35 +00:00
|
|
|
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
2022-01-19 15:43:28 +00:00
|
|
|
|
* Copyright (C) 2022 Ad5001
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-03-05 16:35:58 +00:00
|
|
|
|
.pragma library
|
2022-01-19 15:43:28 +00:00
|
|
|
|
|
2022-03-05 16:35:58 +00:00
|
|
|
|
.import "../expr-eval.js" as ExprEval
|
2022-01-19 15:43:28 +00:00
|
|
|
|
|
2022-03-05 15:43:22 +00:00
|
|
|
|
/**
|
|
|
|
|
* Puts element within parenthesis.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} elem - element to put within parenthesis.
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
2022-01-19 15:43:28 +00:00
|
|
|
|
function par(elem) {
|
|
|
|
|
return '(' + elem + ')'
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 15:43:22 +00:00
|
|
|
|
/**
|
|
|
|
|
* Checks if the element contains at least one of the elements of
|
|
|
|
|
* the string array contents , and returns the parenthesis version if so.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} elem - element to put within parenthesis.
|
|
|
|
|
* @param {Array} contents - Array of elements to put within parenthesis.
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
2022-01-19 15:43:28 +00:00
|
|
|
|
function parif(elem, contents) {
|
2022-03-05 16:35:58 +00:00
|
|
|
|
return contents.some(x => elem.toString().includes(x)) ? par(elem) : elem
|
2022-01-19 15:43:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 19:57:21 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a latex expression for a function.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} f - Function to convert
|
|
|
|
|
* @param {Array} args - Arguments of the function
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
|
|
|
|
function functionToLatex(f, args) {
|
|
|
|
|
switch(f) {
|
|
|
|
|
case "derivative":
|
|
|
|
|
return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(by, 'g'), 'x') + '}{dx}';
|
|
|
|
|
break;
|
|
|
|
|
case "integral":
|
|
|
|
|
return '\\int\\limits^{' + args[0] + '}_{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3];
|
|
|
|
|
break;
|
|
|
|
|
case "sqrt":
|
|
|
|
|
return '\\sqrt\\left(' + args.join(', ') + '\\right)';
|
|
|
|
|
break;
|
|
|
|
|
case "abs":
|
|
|
|
|
return '\\left|' + args.join(', ') + '\\right|';
|
|
|
|
|
break;
|
|
|
|
|
case "floor":
|
|
|
|
|
return '\\left\\lfloor' + args.join(', ') + '\\right\\rfloor';
|
|
|
|
|
break;
|
|
|
|
|
case "ceil":
|
|
|
|
|
return '\\left\\lceil' + args.join(', ') + '\\right\\rceil';
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return '\\mathrm{' + f + '}\\left(' + args.join(', ') + '\\right)';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-03-05 15:43:22 +00:00
|
|
|
|
/**
|
2022-03-05 19:57:21 +00:00
|
|
|
|
* Creates a latex variable from a variable.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} vari - variable to convert
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
|
|
|
|
function variableToLatex(vari) {
|
2022-03-05 20:00:29 +00:00
|
|
|
|
let unicodechars = ["α","β","γ","δ","ε","ζ","η",
|
|
|
|
|
"π","θ","κ","λ","μ","ξ","ρ",
|
|
|
|
|
"ς","σ","τ","φ","χ","ψ","ω",
|
|
|
|
|
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
|
|
|
|
|
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
|
|
|
|
|
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
|
|
|
|
"ₜ","¹","²","³","⁴","⁵","⁶",
|
|
|
|
|
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
|
|
|
|
"₄","₅","₆","₇","₈","₉","₀"]
|
|
|
|
|
let equivalchars = ["alpha","beta","gamma","delta","epsilon","zeta","eta",
|
|
|
|
|
"pi","theta","kappa","lambda","mu","xi","rho",
|
|
|
|
|
"sigma","sigma","tau","phi","chi","psi","omega",
|
|
|
|
|
"Gamma","Delta","Theta","Lambda","Xi","Pi","Sigma",
|
|
|
|
|
"Phy","Psi","Omega","{}_{a}","{}_{e}","{}_{o}","{}_{x}",
|
|
|
|
|
"{}_{h}","{}_{k}","{}_{l}","{}_{m}","{}_{n}","{}_{p}","{}_{s}",
|
|
|
|
|
"{}_{t}","{}^{1}","{}^{2}","{}^{3}","{}^{4}","{}^{5}","{}^{6}",
|
|
|
|
|
"{}^{7}","{}^{8}","{}^{9}","{}^{0}","{}_{1}","{}_{2}","{}_{3}",
|
|
|
|
|
"{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}"]
|
|
|
|
|
for(let i = 0; i < unicodechars.length; i++) {
|
2022-03-05 19:57:21 +00:00
|
|
|
|
if(vari.includes(unicodechars[i]))
|
|
|
|
|
vari = vari.replaceAll(unicodechars[i], equivalchars[i])
|
|
|
|
|
}
|
|
|
|
|
return vari;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts expr-eval tokens to a latex string.
|
2022-03-05 15:43:22 +00:00
|
|
|
|
*
|
|
|
|
|
* @param {Array} tokens - expr-eval tokens list
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
2022-01-19 15:43:28 +00:00
|
|
|
|
function expressionToLatex(tokens) {
|
|
|
|
|
var nstack = [];
|
|
|
|
|
var n1, n2, n3;
|
|
|
|
|
var f, args, argCount;
|
|
|
|
|
for (var i = 0; i < tokens.length; i++) {
|
|
|
|
|
var item = tokens[i];
|
|
|
|
|
var type = item.type;
|
|
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
case ExprEval.INUMBER:
|
|
|
|
|
if (typeof item.value === 'number' && item.value < 0) {
|
|
|
|
|
nstack.push(par(item.value));
|
|
|
|
|
} else if (Array.isArray(item.value)) {
|
2022-03-05 16:35:58 +00:00
|
|
|
|
nstack.push('[' + item.value.map(ExprEval.escapeValue).join(', ') + ']');
|
2022-01-19 15:43:28 +00:00
|
|
|
|
} else {
|
2022-03-05 16:35:58 +00:00
|
|
|
|
nstack.push(ExprEval.escapeValue(item.value));
|
2022-01-19 15:43:28 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IOP2:
|
|
|
|
|
n2 = nstack.pop();
|
|
|
|
|
n1 = nstack.pop();
|
|
|
|
|
f = item.value;
|
|
|
|
|
switch(f) {
|
|
|
|
|
case '-':
|
|
|
|
|
case '+':
|
|
|
|
|
nstack.push(n1 + this.ope + n2);
|
|
|
|
|
break;
|
|
|
|
|
case '||':
|
|
|
|
|
case 'or':
|
|
|
|
|
case '&&':
|
|
|
|
|
case 'and':
|
|
|
|
|
case '==':
|
|
|
|
|
case '!=':
|
|
|
|
|
nstack.push(par(n1) + this.ope + par(n2));
|
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-']));
|
|
|
|
|
break;
|
|
|
|
|
case '/':
|
|
|
|
|
nstack.push("\\frac{" + n1 + "}{" + n2 + "}");
|
|
|
|
|
break;
|
|
|
|
|
case '^':
|
|
|
|
|
nstack.push(parif(n1,['+','-','*','/','!']) + "^{" + n2 + "}");
|
|
|
|
|
break;
|
|
|
|
|
case '%':
|
|
|
|
|
nstack.push(parif(n1,['+','-','*','/','!','^']) + " \\mathrm{mod} " + parif(n2,['+','-','*','/','!','^']));
|
|
|
|
|
break;
|
|
|
|
|
case '[':
|
|
|
|
|
nstack.push(n1 + '[' + n2 + ']');
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new EvalError("Unknown operator " + ope + ".");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IOP3: // Thirdiary operator
|
|
|
|
|
n3 = nstack.pop();
|
|
|
|
|
n2 = nstack.pop();
|
|
|
|
|
n1 = nstack.pop();
|
|
|
|
|
f = item.value;
|
|
|
|
|
if (f === '?') {
|
|
|
|
|
nstack.push('(' + n1 + ' ? ' + n2 + ' : ' + n3 + ')');
|
|
|
|
|
} else {
|
|
|
|
|
throw new EvalError('Unknown operator ' + ope + '.');
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IVAR:
|
|
|
|
|
case ExprEval.IVARNAME:
|
2022-03-05 19:57:21 +00:00
|
|
|
|
nstack.push(variableToLatex(item.value));
|
2022-01-19 15:43:28 +00:00
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IOP1: // Unary operator
|
|
|
|
|
n1 = nstack.pop();
|
|
|
|
|
f = item.value;
|
|
|
|
|
switch(f) {
|
|
|
|
|
case '-':
|
|
|
|
|
case '+':
|
|
|
|
|
nstack.push(par(f + n1));
|
|
|
|
|
break;
|
|
|
|
|
case '!':
|
|
|
|
|
nstack.push(parif(n1,['+','-','*','/','^']) + '!');
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
nstack.push(f + parif(n1,['+','-','*','/','^']));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IFUNCALL:
|
|
|
|
|
argCount = item.value;
|
|
|
|
|
args = [];
|
|
|
|
|
while (argCount-- > 0) {
|
|
|
|
|
args.unshift(nstack.pop());
|
|
|
|
|
}
|
|
|
|
|
f = nstack.pop();
|
2022-03-05 16:35:58 +00:00
|
|
|
|
// Handling various functions
|
2022-03-05 19:57:21 +00:00
|
|
|
|
nstack.push(functionToLatex(f, args))
|
2022-01-19 15:43:28 +00:00
|
|
|
|
case ExprEval.IFUNDEF:
|
|
|
|
|
nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2));
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IMEMBER:
|
|
|
|
|
n1 = nstack.pop();
|
|
|
|
|
nstack.push(n1 + '.' + item.value);
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IARRAY:
|
|
|
|
|
argCount = item.value;
|
|
|
|
|
args = [];
|
|
|
|
|
while (argCount-- > 0) {
|
|
|
|
|
args.unshift(nstack.pop());
|
|
|
|
|
}
|
|
|
|
|
nstack.push('[' + args.join(', ') + ']');
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IEXPR:
|
|
|
|
|
nstack.push('(' + expressionToLatex(item.value) + ')');
|
|
|
|
|
break;
|
|
|
|
|
case ExprEval.IENDSTATEMENT:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new EvalError('invalid Expression');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (nstack.length > 1) {
|
|
|
|
|
if (toJS) {
|
|
|
|
|
nstack = [ nstack.join(',') ];
|
|
|
|
|
} else {
|
|
|
|
|
nstack = [ nstack.join(';') ];
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-05 19:57:21 +00:00
|
|
|
|
console.log(nstack[0]);
|
2022-03-05 16:35:58 +00:00
|
|
|
|
return String(nstack[0]);
|
2022-01-19 15:43:28 +00:00
|
|
|
|
}
|