A lot of changes related to latex:
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:
Ad5001 2022-03-06 00:55:32 +01:00
parent ccf3de5783
commit 0975189615
Signed by: Ad5001
GPG key ID: EF45F9C6AFE20160
11 changed files with 144 additions and 57 deletions

View file

@ -124,14 +124,16 @@ 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()
objectLists.update() if(updateObjectList)
objectLists.update()
redoStack.push(action) redoStack.push(action)
undoCount--; undoCount--;
redoCount++; redoCount++;
@ -140,14 +142,16 @@ 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()
objectLists.update() if(updateObjectList)
objectLists.update()
undoStack.push(action) undoStack.push(action)
undoCount++; undoCount++;
redoCount--; redoCount--;
@ -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;

View file

@ -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)) {

View file

@ -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

View file

@ -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 = []

View file

@ -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]);
} }

View file

@ -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) {

View file

@ -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

View file

@ -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))
switch(this.labelPosition) {
let drawLabel = function(canvas, ctx, ltxImg) {
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) {

View file

@ -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)
} }
} }

View file

@ -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()}'

View file

@ -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"}