Fixing a particularly smelly bug in regard to X Cursor targetting causing issues with certain functions.

This commit is contained in:
Ad5001 2024-09-20 19:02:10 +02:00
parent 7f57ed13c7
commit 370402f303
Signed by: Ad5001
GPG key ID: EF45F9C6AFE20160
9 changed files with 32 additions and 27 deletions

View file

@ -291,7 +291,7 @@ class CanvasAPI extends Module {
} else { } else {
for(let x = 1; x < this.axesSteps.x.maxDraw; x += 1) { for(let x = 1; x < this.axesSteps.x.maxDraw; x += 1) {
let drawX = x*this.axesSteps.x.value let drawX = x*this.axesSteps.x.value
let txtX = this.axesSteps.x.expression.simplify(x).replace(/^\((.+)\)$/, '$1') let txtX = this.axesSteps.x.expression.simplify(x).toString().replace(/^\((.+)\)$/, '$1')
let textHeight = this.measureText(txtX).height let textHeight = this.measureText(txtX).height
this.drawVisibleText(txtX, this.x2px(drawX)-4, axisxpx+this.textsize/2+textHeight) this.drawVisibleText(txtX, this.x2px(drawX)-4, axisxpx+this.textsize/2+textHeight)
this.drawVisibleText('-'+txtX, this.x2px(-drawX)-4, axisxpx+this.textsize/2+textHeight) this.drawVisibleText('-'+txtX, this.x2px(-drawX)-4, axisxpx+this.textsize/2+textHeight)
@ -301,7 +301,7 @@ class CanvasAPI extends Module {
if(this.showygrad) { if(this.showygrad) {
for(let y = 0; y < this.axesSteps.y.maxDraw; y += 1) { for(let y = 0; y < this.axesSteps.y.maxDraw; y += 1) {
let drawY = y*this.axesSteps.y.value let drawY = y*this.axesSteps.y.value
let txtY = this.axesSteps.y.expression.simplify(y).replace(/^\((.+)\)$/, '$1') let txtY = this.axesSteps.y.expression.simplify(y).toString().replace(/^\((.+)\)$/, '$1')
textWidth = this._ctx.measureText(txtY).width textWidth = this._ctx.measureText(txtY).width
this.drawVisibleText(txtY, axisypx-6-textWidth, this.y2px(drawY)+4+(10*(y===0))) this.drawVisibleText(txtY, axisypx-6-textWidth, this.y2px(drawY)+4+(10*(y===0)))
if(y !== 0) if(y !== 0)

View file

@ -199,6 +199,7 @@ export class Range extends Domain {
} }
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) && return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) &&
((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute())) ((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute()))
@ -257,16 +258,19 @@ export class SpecialDomain extends Domain {
} }
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
return this.isValid(x) return this.isValid(x)
} }
next(x) { next(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
return this.nextValue(x) return this.nextValue(x)
} }
previous(x) { previous(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
return this.prevValue(x) return this.prevValue(x)
} }
@ -315,6 +319,7 @@ export class DomainSet extends SpecialDomain {
} }
includes(x) { includes(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
for(let value of this.values) for(let value of this.values)
if(x === value.execute()) return true if(x === value.execute()) return true
@ -322,6 +327,7 @@ export class DomainSet extends SpecialDomain {
} }
next(x) { next(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
if(x < this.executedValues[0]) return this.executedValues[0] if(x < this.executedValues[0]) return this.executedValues[0]
for(let i = 1; i < this.values.length; i++) { for(let i = 1; i < this.values.length; i++) {
@ -333,6 +339,7 @@ export class DomainSet extends SpecialDomain {
} }
previous(x) { previous(x) {
if(x instanceof Expression) x = x.execute()
if(typeof x == 'string') x = executeExpression(x) if(typeof x == 'string') x = executeExpression(x)
if(x > this.executedValues[this.executedValues.length-1]) if(x > this.executedValues[this.executedValues.length-1])
return this.executedValues[this.executedValues.length-1] return this.executedValues[this.executedValues.length-1]

View file

@ -29,8 +29,14 @@ export class Expression {
throw new Error('Expression parser not initialized.') throw new Error('Expression parser not initialized.')
if(!Modules.Objects) if(!Modules.Objects)
throw new Error('Objects API not initialized.') throw new Error('Objects API not initialized.')
if(typeof expr === "string") {
this.expr = Utils.exponentsToExpression(expr) this.expr = Utils.exponentsToExpression(expr)
this.calc = Modules.ExprParser.parse(this.expr).simplify() this.calc = Modules.ExprParser.parse(this.expr).simplify()
} else {
// Passed an expression here directly.
this.calc = expr.simplify()
this.expr = expr.toString()
}
this.cached = this.isConstant() this.cached = this.isConstant()
this.cachedValue = null this.cachedValue = null
if(this.cached && this.allRequirementsFullfilled()) if(this.cached && this.allRequirementsFullfilled())
@ -72,19 +78,8 @@ export class Expression {
simplify(x) { simplify(x) {
let expr = this.calc.substitute('x', x).simplify() let expr = this.calc.substitute('x', x).simplify()
if(expr.evaluate() === 0) return '0' if(expr.evaluate() === 0) expr = '0'
let str = Utils.makeExpressionReadable(expr.toString()); return new Expression(expr)
if(str !== undefined && str.match(/^\d*\.\d+$/)) {
if(str.split('.')[1].split('0').length > 7) {
// Likely rounding error
str = parseFloat(str.substring(0, str.length-1)).toString();
}
}
return str
}
duplicate() {
return new Expression(this.toEditableString())
} }
toEditableString() { toEditableString() {
@ -93,6 +88,12 @@ export class Expression {
toString(forceSign=false) { toString(forceSign=false) {
let str = Utils.makeExpressionReadable(this.calc.toString()) let str = Utils.makeExpressionReadable(this.calc.toString())
if(str !== undefined && str.match(/^\d*\.\d+$/)) {
if(str.split('.')[1].split('0').length > 7) {
// Likely rounding error
str = parseFloat(str.substring(0, str.length-1)).toString();
}
}
if(str[0] !== '-' && forceSign) str = '+' + str if(str[0] !== '-' && forceSign) str = '+' + str
return str return str
} }

View file

@ -52,10 +52,9 @@ export class Sequence extends Expr.Expression {
} }
simplify(n = 1) { simplify(n = 1) {
if(n in this.calcValues) if(!(n in this.calcValues))
return Utils.makeExpressionReadable(this.calcValues[n].toString())
this.cache(n) this.cache(n)
return Utils.makeExpressionReadable(this.calcValues[n].toString()) return this.calcValues[n].toString()
} }
cache(n = 1) { cache(n = 1) {

View file

@ -380,7 +380,7 @@ export class ExecutableObject extends DrawableObject {
* Returns the simplified expression string for a given x. * Returns the simplified expression string for a given x.
* *
* @param {number} x * @param {number} x
* @returns {string} * @returns {string|Expression}
*/ */
simplify(x = 1) {return '0'} simplify(x = 1) {return '0'}

View file

@ -88,7 +88,7 @@ export default class PhaseBode extends ExecutableObject {
return this.om_0.y.toString() return this.om_0.y.toString()
} else { } else {
let newExp = this.om_0.y.toEditableString() + ' + ' + this.phase.toEditableString() let newExp = this.om_0.y.toEditableString() + ' + ' + this.phase.toEditableString()
return (new Expression(newExp)).toString() return new Expression(newExp)
} }
} }

View file

@ -81,7 +81,7 @@ export default class RepartitionFunction extends ExecutableObject {
// Simplify returns the simplified string of the expression. // Simplify returns the simplified string of the expression.
simplify(x = 1) { simplify(x = 1) {
return this.execute(x) return this.execute(x).toString()
} }
getLabel() { getLabel() {

View file

@ -92,7 +92,7 @@ export default class XCursor extends DrawableObject {
approx = approx.toPrecision(this.rounding + Math.round(approx).toString().length) approx = approx.toPrecision(this.rounding + Math.round(approx).toString().length)
} }
let simpl = t.simplify(this.x.toEditableString()) let simpl = t.simplify(this.x.toEditableString())
return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.tokens ? Latex.expression(simpl.tokens) : simpl}` + return `${Latex.variable(t.name)}(${Latex.variable(this.name)}) = ${simpl.latexMarkup ? simpl.latexMarkup : Latex.variable(simpl)}` +
(this.approximate ? ' \\simeq ' + approx : '') (this.approximate ? ' \\simeq ' + approx : '')
} }

View file

@ -272,8 +272,6 @@ export function makeExpressionReadable(str) {
[/_([\d\w+-]+)/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'],
[/([^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}`