A lot of changes related to latex:
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
- Implemented latex for functions - Fixed Points with greek variable names - Small changes to test1 to fit latex better - History re/undos only redraw the graph every 4 change in order to speed up the process when re/undoing a lot of changes. - Removing some debug related to latex - Added latexMarkup property for domains, allowing them to be integrated into objects latex. - Fixed issues related to derivatives and integrals on latex - Fully fixed variable substitution for latex - Fixed sequence crashing - Adding getLatexLabel method for objects that have a latex label.
This commit is contained in:
parent
ccf3de5783
commit
0975189615
11 changed files with 144 additions and 57 deletions
|
@ -124,13 +124,15 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlmethod void History::undo()
|
\qmlmethod void History::undo(bool updateObjectList = true)
|
||||||
Undoes the historylib.Action at the top of the undo stack and pushes it to the top of the redo stack.
|
Undoes the historylib.Action at the top of the undo stack and pushes it to the top of the redo stack.
|
||||||
|
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||||
*/
|
*/
|
||||||
function undo() {
|
function undo(updateObjectList = true) {
|
||||||
if(undoStack.length > 0) {
|
if(undoStack.length > 0) {
|
||||||
var action = undoStack.pop()
|
var action = undoStack.pop()
|
||||||
action.undo()
|
action.undo()
|
||||||
|
if(updateObjectList)
|
||||||
objectLists.update()
|
objectLists.update()
|
||||||
redoStack.push(action)
|
redoStack.push(action)
|
||||||
undoCount--;
|
undoCount--;
|
||||||
|
@ -140,13 +142,15 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlmethod void History::redo()
|
\qmlmethod void History::redo(bool updateObjectList = true)
|
||||||
Redoes the historylib.Action at the top of the redo stack and pushes it to the top of the undo stack.
|
Redoes the historylib.Action at the top of the redo stack and pushes it to the top of the undo stack.
|
||||||
|
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||||
*/
|
*/
|
||||||
function redo() {
|
function redo(updateObjectList = true) {
|
||||||
if(redoStack.length > 0) {
|
if(redoStack.length > 0) {
|
||||||
var action = redoStack.pop()
|
var action = redoStack.pop()
|
||||||
action.redo()
|
action.redo()
|
||||||
|
if(updateObjectList)
|
||||||
objectLists.update()
|
objectLists.update()
|
||||||
undoStack.push(action)
|
undoStack.push(action)
|
||||||
undoCount++;
|
undoCount++;
|
||||||
|
@ -186,7 +190,7 @@ Item {
|
||||||
property int toUndoCount: 0
|
property int toUndoCount: 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if(toUndoCount > 0) {
|
if(toUndoCount > 0) {
|
||||||
historyObj.undo()
|
historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||||
toUndoCount--;
|
toUndoCount--;
|
||||||
} else {
|
} else {
|
||||||
running = false;
|
running = false;
|
||||||
|
@ -200,7 +204,7 @@ Item {
|
||||||
property int toRedoCount: 0
|
property int toRedoCount: 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if(toRedoCount > 0) {
|
if(toRedoCount > 0) {
|
||||||
historyObj.redo()
|
historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||||
toRedoCount--;
|
toRedoCount--;
|
||||||
} else {
|
} else {
|
||||||
running = false;
|
running = false;
|
||||||
|
|
|
@ -334,7 +334,7 @@ Canvas {
|
||||||
\note The \c x, \c y \c width and \c height properties here are relative to the canvas, not the plot.
|
\note The \c x, \c y \c width and \c height properties here are relative to the canvas, not the plot.
|
||||||
*/
|
*/
|
||||||
function drawVisibleImage(ctx, image, x, y, width, height) {
|
function drawVisibleImage(ctx, image, x, y, width, height) {
|
||||||
console.log("Drawing image", isImageLoaded(image), isImageError(image))
|
//console.log("Drawing image", isImageLoaded(image), isImageError(image))
|
||||||
markDirty(Qt.rect(x, y, width, height));
|
markDirty(Qt.rect(x, y, width, height));
|
||||||
ctx.drawImage(image, x, y, width, height)
|
ctx.drawImage(image, x, y, width, height)
|
||||||
/*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) {
|
/*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) {
|
||||||
|
|
|
@ -83,7 +83,7 @@ Item {
|
||||||
id: iconLabel
|
id: iconLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: icon == "" ? 0 : 3
|
anchors.topMargin: icon == "" ? 0 : 3
|
||||||
source: control.visible ? "../icons/" + control.icon : ""
|
source: control.visible && icon != "" ? "../icons/" + control.icon : ""
|
||||||
width: height
|
width: height
|
||||||
height: icon == "" || !visible ? 0 : 24
|
height: icon == "" || !visible ? 0 : 24
|
||||||
color: sysPalette.windowText
|
color: sysPalette.windowText
|
||||||
|
|
|
@ -152,10 +152,15 @@ class Domain {
|
||||||
* Represents an empty set.
|
* Represents an empty set.
|
||||||
*/
|
*/
|
||||||
class EmptySet extends Domain {
|
class EmptySet extends Domain {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.displayName = "∅"
|
||||||
|
this.latexMarkup = "\\emptyset"
|
||||||
|
}
|
||||||
|
|
||||||
includes(x) { return false }
|
includes(x) { return false }
|
||||||
|
|
||||||
toString() { return "∅" }
|
toString() { return this.displayName }
|
||||||
|
|
||||||
union(domain) { return domain }
|
union(domain) { return domain }
|
||||||
|
|
||||||
|
@ -177,6 +182,7 @@ class Range extends Domain {
|
||||||
this.openBegin = openBegin
|
this.openBegin = openBegin
|
||||||
this.openEnd = openEnd
|
this.openEnd = openEnd
|
||||||
this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]")
|
this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]")
|
||||||
|
this.latexMarkup = `\\mathopen${openBegin ? "]" : "["}${this.begin.latexMarkup};${this.end.latexMarkup}\\mathclose${openEnd ? "[" : "]"}`
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(x) {
|
includes(x) {
|
||||||
|
@ -292,6 +298,8 @@ class DomainSet extends SpecialDomain {
|
||||||
}
|
}
|
||||||
this.executedValues.sort((a,b) => a-b)
|
this.executedValues.sort((a,b) => a-b)
|
||||||
this.values = this.executedValues.map(val => newVals[val])
|
this.values = this.executedValues.map(val => newVals[val])
|
||||||
|
this.displayName = "{" + this.values.join(";") + "}"
|
||||||
|
this.latexMarkup = `\\{${this.values.join(";")}\\}`
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(x) {
|
includes(x) {
|
||||||
|
@ -325,7 +333,7 @@ class DomainSet extends SpecialDomain {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return "{" + this.values.join(";") + "}"
|
return this.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
union(domain) {
|
union(domain) {
|
||||||
|
@ -397,6 +405,8 @@ class UnionDomain extends Domain {
|
||||||
super()
|
super()
|
||||||
this.dom1 = dom1
|
this.dom1 = dom1
|
||||||
this.dom2 = dom2
|
this.dom2 = dom2
|
||||||
|
this.displayName = this.dom1.toString() + " ∪ " + this.dom2.toString()
|
||||||
|
this.latexMarkup = `${dom1.latexMarkup}\\cup${dom2.latexMarkup}`
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(x) {
|
includes(x) {
|
||||||
|
@ -404,7 +414,7 @@ class UnionDomain extends Domain {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.dom1.toString() + " ∪ " + this.dom2.toString()
|
return this.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
union(domain) {
|
union(domain) {
|
||||||
|
@ -441,6 +451,8 @@ class IntersectionDomain extends Domain {
|
||||||
super()
|
super()
|
||||||
this.dom1 = dom1
|
this.dom1 = dom1
|
||||||
this.dom2 = dom2
|
this.dom2 = dom2
|
||||||
|
this.displayName = dom1.toString() + " ∩ " + dom2.toString()
|
||||||
|
this.latexMarkup = `${dom1.latexMarkup}\\cap${dom2.latexMarkup}`
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(x) {
|
includes(x) {
|
||||||
|
@ -448,7 +460,7 @@ class IntersectionDomain extends Domain {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.dom1.toString() + " ∩ " + this.dom2.toString()
|
return this.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
union(domain) {
|
union(domain) {
|
||||||
|
@ -484,6 +496,8 @@ class MinusDomain extends Domain {
|
||||||
super()
|
super()
|
||||||
this.dom1 = dom1
|
this.dom1 = dom1
|
||||||
this.dom2 = dom2
|
this.dom2 = dom2
|
||||||
|
this.displayName = dom1.toString() + "∖" + dom2.toString()
|
||||||
|
this.latexMarkup = `${dom1.latexMarkup}\\setminus${dom2.latexMarkup}`
|
||||||
}
|
}
|
||||||
|
|
||||||
includes(x) {
|
includes(x) {
|
||||||
|
@ -491,7 +505,7 @@ class MinusDomain extends Domain {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
return this.dom1.toString() + "∖" + this.dom2.toString()
|
return this.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
static import(frm) {
|
static import(frm) {
|
||||||
|
@ -505,33 +519,45 @@ class MinusDomain extends Domain {
|
||||||
|
|
||||||
Domain.RE = new MinusDomain("R", "{0}")
|
Domain.RE = new MinusDomain("R", "{0}")
|
||||||
Domain.RE.displayName = "ℝ*"
|
Domain.RE.displayName = "ℝ*"
|
||||||
|
Domain.RE.latexMarkup = "\\mathbb{R}^{*}"
|
||||||
|
|
||||||
Domain.R = new Range(-Infinity,Infinity,true,true)
|
Domain.R = new Range(-Infinity,Infinity,true,true)
|
||||||
Domain.R.displayName = "ℝ"
|
Domain.R.displayName = "ℝ"
|
||||||
|
Domain.R.latexMarkup = "\\mathbb{R}"
|
||||||
Domain.RP = new Range(0,Infinity,true,false)
|
Domain.RP = new Range(0,Infinity,true,false)
|
||||||
Domain.RP.displayName = "ℝ⁺"
|
Domain.RP.displayName = "ℝ⁺"
|
||||||
|
Domain.RP.latexMarkup = "\\mathbb{R}^{+}"
|
||||||
Domain.RM = new Range(-Infinity,0,true,false)
|
Domain.RM = new Range(-Infinity,0,true,false)
|
||||||
Domain.RM.displayName = "ℝ⁻"
|
Domain.RM.displayName = "ℝ⁻"
|
||||||
|
Domain.RM.latexMarkup = "\\mathbb{R}^{-}"
|
||||||
Domain.RPE = new Range(0,Infinity,true,true)
|
Domain.RPE = new Range(0,Infinity,true,true)
|
||||||
Domain.RPE.displayName = "ℝ⁺*"
|
Domain.RPE.displayName = "ℝ⁺*"
|
||||||
|
Domain.RPE.latexMarkup = "\\mathbb{R}^{+*}"
|
||||||
Domain.RME = new Range(-Infinity,0,true,true)
|
Domain.RME = new Range(-Infinity,0,true,true)
|
||||||
Domain.RME.displayName = "ℝ⁻*"
|
Domain.RME.displayName = "ℝ⁻*"
|
||||||
|
Domain.RME.latexMarkup = "\\mathbb{R}^{+*}"
|
||||||
Domain.N = new SpecialDomain('ℕ', x => x%1==0 && x >= 0,
|
Domain.N = new SpecialDomain('ℕ', x => x%1==0 && x >= 0,
|
||||||
x => Math.max(Math.floor(x)+1, 0),
|
x => Math.max(Math.floor(x)+1, 0),
|
||||||
x => Math.max(Math.ceil(x)-1, 0))
|
x => Math.max(Math.ceil(x)-1, 0))
|
||||||
|
Domain.N.latexMarkup = "\\mathbb{N}"
|
||||||
Domain.NE = new SpecialDomain('ℕ*', x => x%1==0 && x > 0,
|
Domain.NE = new SpecialDomain('ℕ*', x => x%1==0 && x > 0,
|
||||||
x => Math.max(Math.floor(x)+1, 1),
|
x => Math.max(Math.floor(x)+1, 1),
|
||||||
x => Math.max(Math.ceil(x)-1, 1))
|
x => Math.max(Math.ceil(x)-1, 1))
|
||||||
|
Domain.NE.latexMarkup = "\\mathbb{N}^{*}"
|
||||||
Domain.Z = new SpecialDomain('ℤ', x => x%1==0, x => Math.floor(x)+1, x => Math.ceil(x)-1)
|
Domain.Z = new SpecialDomain('ℤ', x => x%1==0, x => Math.floor(x)+1, x => Math.ceil(x)-1)
|
||||||
|
Domain.Z.latexMarkup = "\\mathbb{Z}"
|
||||||
Domain.ZE = new SpecialDomain('ℤ*', x => x%1==0 && x != 0,
|
Domain.ZE = new SpecialDomain('ℤ*', x => x%1==0 && x != 0,
|
||||||
x => Math.floor(x)+1 == 0 ? Math.floor(x)+2 : Math.floor(x)+1,
|
x => Math.floor(x)+1 == 0 ? Math.floor(x)+2 : Math.floor(x)+1,
|
||||||
x => Math.ceil(x)-1 == 0 ? Math.ceil(x)-2 : Math.ceil(x)-1)
|
x => Math.ceil(x)-1 == 0 ? Math.ceil(x)-2 : Math.ceil(x)-1)
|
||||||
|
Domain.ZE.latexMarkup = "\\mathbb{Z}^{*}"
|
||||||
Domain.ZM = new SpecialDomain('ℤ⁻', x => x%1==0 && x <= 0,
|
Domain.ZM = new SpecialDomain('ℤ⁻', x => x%1==0 && x <= 0,
|
||||||
x => Math.min(Math.floor(x)+1, 0),
|
x => Math.min(Math.floor(x)+1, 0),
|
||||||
x => Math.min(Math.ceil(x)-1, 0))
|
x => Math.min(Math.ceil(x)-1, 0))
|
||||||
|
Domain.ZM.latexMarkup = "\\mathbb{Z}^{-}"
|
||||||
Domain.ZME = new SpecialDomain('ℤ⁻*', x => x%1==0 && x < 0,
|
Domain.ZME = new SpecialDomain('ℤ⁻*', x => x%1==0 && x < 0,
|
||||||
x => Math.min(Math.floor(x)+1, -1),
|
x => Math.min(Math.floor(x)+1, -1),
|
||||||
x => Math.min(Math.ceil(x)-1, -1))
|
x => Math.min(Math.ceil(x)-1, -1))
|
||||||
|
Domain.ZME.latexMarkup = "\\mathbb{Z}^{-*}"
|
||||||
Domain.NLog = new SpecialDomain('ℕˡᵒᵍ',
|
Domain.NLog = new SpecialDomain('ℕˡᵒᵍ',
|
||||||
x => x/Math.pow(10, x.toString().length-1) % 1 == 0 && x > 0,
|
x => x/Math.pow(10, x.toString().length-1) % 1 == 0 && x > 0,
|
||||||
function(x) {
|
function(x) {
|
||||||
|
@ -542,6 +568,7 @@ Domain.NLog = new SpecialDomain('ℕˡᵒᵍ',
|
||||||
var x10pow = Math.pow(10, x.toString().length-1)
|
var x10pow = Math.pow(10, x.toString().length-1)
|
||||||
return Math.max(1, (Math.ceil(x/x10pow)-1)*x10pow)
|
return Math.max(1, (Math.ceil(x/x10pow)-1)*x10pow)
|
||||||
})
|
})
|
||||||
|
Domain.NLog.latexMarkup = "\\mathbb{N}^{log}"
|
||||||
|
|
||||||
var refedDomains = []
|
var refedDomains = []
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,10 @@ function parif(elem, contents) {
|
||||||
function functionToLatex(f, args) {
|
function functionToLatex(f, args) {
|
||||||
switch(f) {
|
switch(f) {
|
||||||
case "derivative":
|
case "derivative":
|
||||||
return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(by, 'g'), 'x') + '}{dx}';
|
return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(args[1].substr(1, args[1].length-2), 'g'), 'x') + '}{dx}';
|
||||||
break;
|
break;
|
||||||
case "integral":
|
case "integral":
|
||||||
return '\\int\\limits^{' + args[0] + '}_{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3];
|
return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3].substr(1, args[3].length-2);
|
||||||
break;
|
break;
|
||||||
case "sqrt":
|
case "sqrt":
|
||||||
return '\\sqrt\\left(' + args.join(', ') + '\\right)';
|
return '\\sqrt\\left(' + args.join(', ') + '\\right)';
|
||||||
|
@ -92,19 +92,22 @@ function variableToLatex(vari) {
|
||||||
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
||||||
"ₜ","¹","²","³","⁴","⁵","⁶",
|
"ₜ","¹","²","³","⁴","⁵","⁶",
|
||||||
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
||||||
"₄","₅","₆","₇","₈","₉","₀"]
|
"₄","₅","₆","₇","₈","₉","₀",
|
||||||
let equivalchars = ["alpha","beta","gamma","delta","epsilon","zeta","eta",
|
"pi"]
|
||||||
"pi","theta","kappa","lambda","mu","xi","rho",
|
let equivalchars = ["\\alpha","\\beta","\\gamma","\\delta","\\epsilon","\\zeta","\\eta",
|
||||||
"sigma","sigma","tau","phi","chi","psi","omega",
|
"\\pi","\\theta","\\kappa","\\lambda","\\mu","\\xi","\\rho",
|
||||||
"Gamma","Delta","Theta","Lambda","Xi","Pi","Sigma",
|
"\\sigma","\\sigma","\\tau","\\phi","\\chi","\\psi","\\omega",
|
||||||
"Phy","Psi","Omega","{}_{a}","{}_{e}","{}_{o}","{}_{x}",
|
"\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma",
|
||||||
|
"\\Phy","\\Psi","\\Omega","{}_{a}","{}_{e}","{}_{o}","{}_{x}",
|
||||||
"{}_{h}","{}_{k}","{}_{l}","{}_{m}","{}_{n}","{}_{p}","{}_{s}",
|
"{}_{h}","{}_{k}","{}_{l}","{}_{m}","{}_{n}","{}_{p}","{}_{s}",
|
||||||
"{}_{t}","{}^{1}","{}^{2}","{}^{3}","{}^{4}","{}^{5}","{}^{6}",
|
"{}_{t}","{}^{1}","{}^{2}","{}^{3}","{}^{4}","{}^{5}","{}^{6}",
|
||||||
"{}^{7}","{}^{8}","{}^{9}","{}^{0}","{}_{1}","{}_{2}","{}_{3}",
|
"{}^{7}","{}^{8}","{}^{9}","{}^{0}","{}_{1}","{}_{2}","{}_{3}",
|
||||||
"{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}"]
|
"{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}",
|
||||||
|
"\\pi"]
|
||||||
for(let i = 0; i < unicodechars.length; i++) {
|
for(let i = 0; i < unicodechars.length; i++) {
|
||||||
|
//console.log(vari, unicodechars[i], equivalchars[i]);
|
||||||
if(vari.includes(unicodechars[i]))
|
if(vari.includes(unicodechars[i]))
|
||||||
vari = vari.replaceAll(unicodechars[i], equivalchars[i])
|
vari = vari.replace(new RegExp(unicodechars[i], 'g'), equivalchars[i])
|
||||||
}
|
}
|
||||||
return vari;
|
return vari;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +143,7 @@ function expressionToLatex(tokens) {
|
||||||
switch(f) {
|
switch(f) {
|
||||||
case '-':
|
case '-':
|
||||||
case '+':
|
case '+':
|
||||||
nstack.push(n1 + this.ope + n2);
|
nstack.push(n1 + f + n2);
|
||||||
break;
|
break;
|
||||||
case '||':
|
case '||':
|
||||||
case 'or':
|
case 'or':
|
||||||
|
@ -148,7 +151,7 @@ function expressionToLatex(tokens) {
|
||||||
case 'and':
|
case 'and':
|
||||||
case '==':
|
case '==':
|
||||||
case '!=':
|
case '!=':
|
||||||
nstack.push(par(n1) + this.ope + par(n2));
|
nstack.push(par(n1) + f + par(n2));
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-']));
|
nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-']));
|
||||||
|
@ -182,7 +185,7 @@ function expressionToLatex(tokens) {
|
||||||
break;
|
break;
|
||||||
case ExprEval.IVAR:
|
case ExprEval.IVAR:
|
||||||
case ExprEval.IVARNAME:
|
case ExprEval.IVARNAME:
|
||||||
nstack.push(variableToLatex(item.value));
|
nstack.push(variableToLatex(item.value.toString()));
|
||||||
break;
|
break;
|
||||||
case ExprEval.IOP1: // Unary operator
|
case ExprEval.IOP1: // Unary operator
|
||||||
n1 = nstack.pop();
|
n1 = nstack.pop();
|
||||||
|
@ -209,6 +212,7 @@ function expressionToLatex(tokens) {
|
||||||
f = nstack.pop();
|
f = nstack.pop();
|
||||||
// Handling various functions
|
// Handling various functions
|
||||||
nstack.push(functionToLatex(f, args))
|
nstack.push(functionToLatex(f, args))
|
||||||
|
break;
|
||||||
case ExprEval.IFUNDEF:
|
case ExprEval.IFUNDEF:
|
||||||
nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2));
|
nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2));
|
||||||
break;
|
break;
|
||||||
|
@ -235,12 +239,7 @@ function expressionToLatex(tokens) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nstack.length > 1) {
|
if (nstack.length > 1) {
|
||||||
if (toJS) {
|
nstack = [ nstack.join(';') ]
|
||||||
nstack = [ nstack.join(',') ];
|
|
||||||
} else {
|
|
||||||
nstack = [ nstack.join(';') ];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
console.log(nstack[0]);
|
|
||||||
return String(nstack[0]);
|
return String(nstack[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Sequence extends Expr.Expression {
|
||||||
this.calcValues = Object.assign({}, baseValues)
|
this.calcValues = Object.assign({}, baseValues)
|
||||||
for(var n in this.calcValues)
|
for(var n in this.calcValues)
|
||||||
if(['string', 'number'].includes(typeof this.calcValues[n]))
|
if(['string', 'number'].includes(typeof this.calcValues[n]))
|
||||||
this.calcValues[n] = parser.parse(this.calcValues[n].toString()).simplify().evaluate(C.evalVariables)
|
this.calcValues[n] = C.parser.parse(this.calcValues[n].toString()).simplify().evaluate(C.evalVariables)
|
||||||
this.valuePlus = parseInt(valuePlus)
|
this.valuePlus = parseInt(valuePlus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ class Sequence extends Expr.Expression {
|
||||||
|
|
||||||
cache(n = 1) {
|
cache(n = 1) {
|
||||||
var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString())
|
var str = Utils.simplifyExpression(this.calc.substitute('n', n-this.valuePlus).toString())
|
||||||
var expr = parser.parse(str).simplify()
|
var expr = C.parser.parse(str).simplify()
|
||||||
var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions)
|
var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions)
|
||||||
l[this.name] = this.calcValues
|
l[this.name] = this.calcValues
|
||||||
currentVars = Object.assign(l, C.evalVariables)
|
C.currentVars = Object.assign(l, C.evalVariables)
|
||||||
this.calcValues[n] = expr.evaluate(currentVars)
|
this.calcValues[n] = expr.evaluate(C.currentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(forceSign=false) {
|
toString(forceSign=false) {
|
||||||
|
|
|
@ -89,6 +89,18 @@ class DrawableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabel() {
|
getLabel() {
|
||||||
|
switch(this.labelContent) {
|
||||||
|
case 'name':
|
||||||
|
return this.name
|
||||||
|
case 'name + value':
|
||||||
|
return this.getReadableString()
|
||||||
|
case 'null':
|
||||||
|
return ''
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLatexLabel() {
|
||||||
switch(this.labelContent) {
|
switch(this.labelContent) {
|
||||||
case 'name':
|
case 'name':
|
||||||
return this.name
|
return this.name
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
.import "../utils.js" as Utils
|
.import "../utils.js" as Utils
|
||||||
.import "../mathlib.js" as MathLib
|
.import "../mathlib.js" as MathLib
|
||||||
.import "../parameters.js" as P
|
.import "../parameters.js" as P
|
||||||
|
.import "../math/latex.js" as Latex
|
||||||
|
|
||||||
|
|
||||||
class Function extends Common.ExecutableObject {
|
class Function extends Common.ExecutableObject {
|
||||||
|
@ -87,6 +88,14 @@ class Function extends Common.ExecutableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toLatexString() {
|
||||||
|
if(this.displayMode == 'application') {
|
||||||
|
return `${Latex.variableToLatex(this.name)}:\\begin{array}{llll}${this.definitionDomain.latexMarkup} & \\rightarrow & ${this.destinationDomain.latexMarkup}\\\\x & \\mapsto & ${this.expression.latexMarkup}\\end{array}`
|
||||||
|
} else {
|
||||||
|
return `\\begin{array}{l}${Latex.variableToLatex(this.name)}(x) = ${this.expression.latexMarkup}\\\\ D_{${this.name}} = ${this.definitionDomain.latexMarkup}\\end{array}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
return [this.name, this.visible, this.color.toString(), this.labelContent,
|
return [this.name, this.visible, this.color.toString(), this.labelContent,
|
||||||
this.expression.toEditableString(), this.definitionDomain.toString(), this.destinationDomain.toString(),
|
this.expression.toEditableString(), this.definitionDomain.toString(), this.destinationDomain.toString(),
|
||||||
|
@ -117,7 +126,41 @@ class Function extends Common.ExecutableObject {
|
||||||
var textSize = canvas.measureText(ctx, text)
|
var textSize = canvas.measureText(ctx, text)
|
||||||
var posX = canvas.x2px(this.labelX)
|
var posX = canvas.x2px(this.labelX)
|
||||||
var posY = canvas.y2px(this.execute(this.labelX))
|
var posY = canvas.y2px(this.execute(this.labelX))
|
||||||
|
|
||||||
|
let drawLabel = function(canvas, ctx, ltxImg) {
|
||||||
switch(this.labelPosition) {
|
switch(this.labelPosition) {
|
||||||
|
case 'above':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX-ltxImg.width/2, posY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'below':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX-ltxImg.width/2, posY+10, ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'left':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX-(ltxImg.width+10), posY-ltxImg.height/2, ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX+10, posY-ltxImg.height/2, ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'above-left':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX-(ltxImg.width+10), posY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'above-right':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX+10, posY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'below-left':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX-(ltxImg.width+10), posY+10, ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
case 'below-right':
|
||||||
|
canvas.drawVisibleImage(ctx, ltxImg.source, posX+10, posY+10, ltxImg.width, ltxImg.height)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let ltxLabel = this.getLatexLabel();
|
||||||
|
if(ltxLabel != "")
|
||||||
|
canvas.renderLatexImage(ltxLabel, this.color, drawLabel.bind(this))
|
||||||
|
//canvas.drawVisibleImage(ctx, ltxImg.source, posX, posY)
|
||||||
|
|
||||||
|
/*switch(this.labelPosition) {
|
||||||
case 'above':
|
case 'above':
|
||||||
canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height)
|
canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height)
|
||||||
break;
|
break;
|
||||||
|
@ -142,13 +185,13 @@ class Function extends Common.ExecutableObject {
|
||||||
case 'below-right':
|
case 'below-right':
|
||||||
canvas.drawVisibleText(ctx, text, posX, posY+textSize.height)
|
canvas.drawVisibleText(ctx, text, posX, posY+textSize.height)
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static drawFunction(canvas, ctx, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) {
|
static drawFunction(canvas, ctx, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) {
|
||||||
// Reusable in other objects.
|
// Reusable in other objects.
|
||||||
// Drawing small traits every 2px
|
// Drawing small traits every 0.2px
|
||||||
var pxprecision = 0.2
|
var pxprecision = 1
|
||||||
var previousX = canvas.px2x(0)
|
var previousX = canvas.px2x(0)
|
||||||
var previousY;
|
var previousY;
|
||||||
if(definitionDomain instanceof MathLib.SpecialDomain && definitionDomain.moveSupported) {
|
if(definitionDomain instanceof MathLib.SpecialDomain && definitionDomain.moveSupported) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
.import "common.js" as Common
|
.import "common.js" as Common
|
||||||
.import "../mathlib.js" as MathLib
|
.import "../mathlib.js" as MathLib
|
||||||
.import "../parameters.js" as P
|
.import "../parameters.js" as P
|
||||||
|
.import "../math/latex.js" as Latex
|
||||||
|
|
||||||
|
|
||||||
class Point extends Common.DrawableObject {
|
class Point extends Common.DrawableObject {
|
||||||
|
@ -59,7 +60,7 @@ class Point extends Common.DrawableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
toLatexString() {
|
toLatexString() {
|
||||||
return `${this.name} = \\left(${this.x.latexMarkup}, ${this.y.latexMarkup}\\right)`
|
return `${Latex.variableToLatex(this.name)} = \\left(${this.x.latexMarkup}, ${this.y.latexMarkup}\\right)`
|
||||||
}
|
}
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
|
@ -86,41 +87,42 @@ class Point extends Common.DrawableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
let drawLabel = function(canvas, ctx, ltxImg) {
|
let drawLabel = function(canvas, ctx, ltxImg) {
|
||||||
//console.log(JSON.stringify(ltxImg), canvas.isImageLoaded(ltxImg.source), this, this.labelPosition)
|
|
||||||
switch(this.labelPosition) {
|
switch(this.labelPosition) {
|
||||||
case 'top':
|
case 'top':
|
||||||
case 'above':
|
case 'above':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-ltxImg.width/2, canvasY-(ltxImg.height+4), ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-ltxImg.width/2, canvasY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
case 'below':
|
case 'below':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-ltxImg.width/2, canvasY+4, ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-ltxImg.width/2, canvasY+10, ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'left':
|
case 'left':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+4), canvasY+4, ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+10), canvasY-ltxImg.height/2, ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'right':
|
case 'right':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+4, canvasY+4, ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+10, canvasY-ltxImg.height/2, ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'top-left':
|
case 'top-left':
|
||||||
case 'above-left':
|
case 'above-left':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+4), canvasY-(ltxImg.height+4), ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+10), canvasY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'top-right':
|
case 'top-right':
|
||||||
case 'above-right':
|
case 'above-right':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+4, canvasY-(ltxImg.height+4), ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+10, canvasY-(ltxImg.height+10), ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'bottom-left':
|
case 'bottom-left':
|
||||||
case 'below-left':
|
case 'below-left':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+4), canvasY+4, ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX-(ltxImg.width+10), canvasY+10, ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
case 'bottom-right':
|
case 'bottom-right':
|
||||||
case 'below-right':
|
case 'below-right':
|
||||||
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+4, canvasY+4, ltxImg.width, ltxImg.height)
|
canvas.drawVisibleImage(ctx, ltxImg.source, canvasX+10, canvasY+10, ltxImg.width, ltxImg.height)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canvas.renderLatexImage(this.getLabel(), this.color, drawLabel.bind(this))
|
let ltxLabel = this.getLatexLabel();
|
||||||
|
if(ltxLabel != "")
|
||||||
|
canvas.renderLatexImage(ltxLabel, this.color, drawLabel.bind(this))
|
||||||
//canvas.drawVisibleImage(ctx, ltxImg.source, canvasX, canvasY)
|
//canvas.drawVisibleImage(ctx, ltxImg.source, canvasX, canvasY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,14 @@ class Latex(QObject):
|
||||||
if not path.exists(exprpath):
|
if not path.exists(exprpath):
|
||||||
fg = color.convertTo(QColor.Rgb)
|
fg = color.convertTo(QColor.Rgb)
|
||||||
fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}'
|
fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}'
|
||||||
preview('$$' + latexstring + '$$', viewer='file', filename=exprpath, dvioptions=[
|
preview('$${' + latexstring + '}$$', viewer='file', filename=exprpath, dvioptions=[
|
||||||
"-T", "tight",
|
"-T", "tight",
|
||||||
"-z", "0",
|
"-z", "0",
|
||||||
"--truecolor",
|
"--truecolor",
|
||||||
f"-D {font_size * 72.27 / 10}", # See https://linux.die.net/man/1/dvipng#-D for convertion
|
f"-D {int(font_size * 72.27 / 100) * 10}", # See https://linux.die.net/man/1/dvipng#-D for convertion
|
||||||
"-bg", "Transparent",
|
"-bg", "Transparent",
|
||||||
"-fg", fg],
|
"-fg", fg],
|
||||||
euler=True)
|
euler=False)
|
||||||
img = QImage(exprpath);
|
img = QImage(exprpath);
|
||||||
# Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded
|
# Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded
|
||||||
return f'{exprpath},{img.width()},{img.height()}'
|
return f'{exprpath},{img.width()},{img.height()}'
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
LPFv1{"xzoom":100,"yzoom":485,"xmin":-1,"ymax":1,"xaxisstep":"1","yaxisstep":"0.1","xaxislabel":"ω (rad/s)","yaxislabel":"G (dB)","logscalex":false,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":22,"history":[[["EditedProperty",["h","Function","labelX",3,2.5,false]],["EditedProperty",["h","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","labelPosition","above","left",false]],["EditedProperty",["h","Function","labelX",2.5,2,false]],["EditedProperty",["h","Function","labelX",2,2.2,false]],["EditedProperty",["h","Function","labelX",2.2,9,false]]],[]],"width":1908,"height":1005,"objects":{"Sequence":[["u",true,"#ff5500","name + value",true,true,{"1":"cos(u[n])"},{"0":"-1"},"above-left",8]],"Function":[["f",true,"#2b156d","name + value","integral((x + 1), x, \"cos (t)\", \"t\")","ℝ⁺*","ℝ","application","left",7,true,true],["g",true,"#ac539c","name + value","0.739083","ℝ","ℝ","application","below",-1,true,false],["h",true,"#00aa00","name + value","derivative(\"cos t\", \"t\", x)","ℤ","ℝ","application","left",9,true,true]],"Repartition":[["X",true,"#1E1EAF","name",true,true,{"0":"0.2","1":"0.1","2":"0.2"},"above",2.5]],"Point":[["A",true,"#060759","name + value","4","(-0.5)","top","●"]]},"type":"logplotv1"}
|
LPFv1{"xzoom":100,"yzoom":485,"xmin":-1,"ymax":1,"xaxisstep":"1","yaxisstep":"0.1","xaxislabel":"ω (rad/s)","yaxislabel":"G (dB)","logscalex":false,"linewidth":2,"showxgrad":true,"showygrad":true,"textsize":22,"history":[[["EditedProperty",["h","Function","labelX",3,2.5,false]],["EditedProperty",["h","Function","labelPosition","above-left","above",false]],["EditedProperty",["h","Function","labelPosition","above","left",false]],["EditedProperty",["h","Function","labelX",2.5,2,false]],["EditedProperty",["h","Function","labelX",2,2.2,false]],["EditedProperty",["h","Function","labelX",2.2,9,false]],["EditedProperty",["f","Function","labelPosition","left","above-left",false]],["EditedProperty",["f","Function","labelX",7,7.4,false]],["EditedProperty",["A","Point","y","(-0.5)","(-0.6)",true]]],[["EditedProperty",["A","Point","labelPosition","top","above",false]]]],"width":1908,"height":1005,"objects":{"Sequence":[["u",true,"#ff5500","name + value",true,true,{"1":"cos(u[n])"},{"0":"-1"},"above-left",8]],"Function":[["f",true,"#2b156d","name + value","integral((x + 1), x, \"cos (t)\", \"t\")","ℝ⁺*","ℝ","application","above-left",7.4,true,true],["g",true,"#ac539c","null","0.739083","ℝ","ℝ","application","below",-1,true,false],["h",true,"#00aa00","name + value","derivative(\"cos t\", \"t\", x)","ℤ","ℝ","application","left",9,true,true]],"Repartition":[["X",true,"#1E1EAF","name",true,true,{"0":"0.2","1":"0.1","2":"0.2"},"above",2.5]],"Point":[["A",true,"#060759","name + value","4","(-0.6)","top","●"]]},"type":"logplotv1"}
|
||||||
|
|
Loading…
Reference in a new issue