From 0975189615dbfb8e27cf232fe7dec8996027699d Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Sun, 6 Mar 2022 00:55:32 +0100 Subject: [PATCH] A lot of changes related to latex: - 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. --- .../LogarithmPlotter/History/History.qml | 20 +++++--- .../LogarithmPlotter/LogGraphCanvas.qml | 2 +- .../LogarithmPlotter/Setting/TextSetting.qml | 2 +- .../ad5001/LogarithmPlotter/js/math/domain.js | 37 ++++++++++++-- .../ad5001/LogarithmPlotter/js/math/latex.js | 37 +++++++------- .../LogarithmPlotter/js/math/sequence.js | 8 +-- .../ad5001/LogarithmPlotter/js/objs/common.js | 12 +++++ .../LogarithmPlotter/js/objs/function.js | 51 +++++++++++++++++-- .../ad5001/LogarithmPlotter/js/objs/point.js | 24 +++++---- LogarithmPlotter/util/latex.py | 6 +-- ci/test1.lpf | 2 +- 11 files changed, 144 insertions(+), 57 deletions(-) diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml index 99fc4cb..e6caf9d 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml @@ -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. + 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) { var action = undoStack.pop() action.undo() - objectLists.update() + if(updateObjectList) + objectLists.update() redoStack.push(action) undoCount--; 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. + 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) { var action = redoStack.pop() action.redo() - objectLists.update() + if(updateObjectList) + objectLists.update() undoStack.push(action) undoCount++; redoCount--; @@ -186,7 +190,7 @@ Item { property int toUndoCount: 0 onTriggered: { if(toUndoCount > 0) { - historyObj.undo() + historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes. toUndoCount--; } else { running = false; @@ -200,7 +204,7 @@ Item { property int toRedoCount: 0 onTriggered: { if(toRedoCount > 0) { - historyObj.redo() + historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes. toRedoCount--; } else { running = false; diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml index 3009868..a819da1 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml @@ -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. */ 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)); ctx.drawImage(image, x, y, width, height) /*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml index 739f7d8..d9239c8 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/TextSetting.qml @@ -83,7 +83,7 @@ Item { id: iconLabel anchors.top: parent.top anchors.topMargin: icon == "" ? 0 : 3 - source: control.visible ? "../icons/" + control.icon : "" + source: control.visible && icon != "" ? "../icons/" + control.icon : "" width: height height: icon == "" || !visible ? 0 : 24 color: sysPalette.windowText diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js index cdf9902..48c23cf 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/domain.js @@ -152,10 +152,15 @@ class Domain { * Represents an empty set. */ class EmptySet extends Domain { + constructor() { + super() + this.displayName = "∅" + this.latexMarkup = "\\emptyset" + } includes(x) { return false } - toString() { return "∅" } + toString() { return this.displayName } union(domain) { return domain } @@ -177,6 +182,7 @@ class Range extends Domain { this.openBegin = openBegin this.openEnd = openEnd this.displayName = (openBegin ? "]" : "[") + begin.toString() + ";" + end.toString() + (openEnd ? "[" : "]") + this.latexMarkup = `\\mathopen${openBegin ? "]" : "["}${this.begin.latexMarkup};${this.end.latexMarkup}\\mathclose${openEnd ? "[" : "]"}` } includes(x) { @@ -292,6 +298,8 @@ class DomainSet extends SpecialDomain { } this.executedValues.sort((a,b) => a-b) this.values = this.executedValues.map(val => newVals[val]) + this.displayName = "{" + this.values.join(";") + "}" + this.latexMarkup = `\\{${this.values.join(";")}\\}` } includes(x) { @@ -325,7 +333,7 @@ class DomainSet extends SpecialDomain { } toString() { - return "{" + this.values.join(";") + "}" + return this.displayName } union(domain) { @@ -397,6 +405,8 @@ class UnionDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = this.dom1.toString() + " ∪ " + this.dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\cup${dom2.latexMarkup}` } includes(x) { @@ -404,7 +414,7 @@ class UnionDomain extends Domain { } toString() { - return this.dom1.toString() + " ∪ " + this.dom2.toString() + return this.displayName } union(domain) { @@ -441,6 +451,8 @@ class IntersectionDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = dom1.toString() + " ∩ " + dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\cap${dom2.latexMarkup}` } includes(x) { @@ -448,7 +460,7 @@ class IntersectionDomain extends Domain { } toString() { - return this.dom1.toString() + " ∩ " + this.dom2.toString() + return this.displayName } union(domain) { @@ -484,6 +496,8 @@ class MinusDomain extends Domain { super() this.dom1 = dom1 this.dom2 = dom2 + this.displayName = dom1.toString() + "∖" + dom2.toString() + this.latexMarkup = `${dom1.latexMarkup}\\setminus${dom2.latexMarkup}` } includes(x) { @@ -491,7 +505,7 @@ class MinusDomain extends Domain { } toString() { - return this.dom1.toString() + "∖" + this.dom2.toString() + return this.displayName } static import(frm) { @@ -505,33 +519,45 @@ class MinusDomain extends Domain { Domain.RE = new MinusDomain("R", "{0}") Domain.RE.displayName = "ℝ*" +Domain.RE.latexMarkup = "\\mathbb{R}^{*}" Domain.R = new Range(-Infinity,Infinity,true,true) Domain.R.displayName = "ℝ" +Domain.R.latexMarkup = "\\mathbb{R}" Domain.RP = new Range(0,Infinity,true,false) Domain.RP.displayName = "ℝ⁺" +Domain.RP.latexMarkup = "\\mathbb{R}^{+}" Domain.RM = new Range(-Infinity,0,true,false) Domain.RM.displayName = "ℝ⁻" +Domain.RM.latexMarkup = "\\mathbb{R}^{-}" Domain.RPE = new Range(0,Infinity,true,true) Domain.RPE.displayName = "ℝ⁺*" +Domain.RPE.latexMarkup = "\\mathbb{R}^{+*}" Domain.RME = new Range(-Infinity,0,true,true) Domain.RME.displayName = "ℝ⁻*" +Domain.RME.latexMarkup = "\\mathbb{R}^{+*}" Domain.N = new SpecialDomain('ℕ', x => x%1==0 && x >= 0, x => Math.max(Math.floor(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, x => Math.max(Math.floor(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.latexMarkup = "\\mathbb{Z}" 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.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, x => Math.min(Math.floor(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, x => Math.min(Math.floor(x)+1, -1), x => Math.min(Math.ceil(x)-1, -1)) +Domain.ZME.latexMarkup = "\\mathbb{Z}^{-*}" Domain.NLog = new SpecialDomain('ℕˡᵒᵍ', x => x/Math.pow(10, x.toString().length-1) % 1 == 0 && x > 0, function(x) { @@ -542,6 +568,7 @@ Domain.NLog = new SpecialDomain('ℕˡᵒᵍ', var x10pow = Math.pow(10, x.toString().length-1) return Math.max(1, (Math.ceil(x/x10pow)-1)*x10pow) }) +Domain.NLog.latexMarkup = "\\mathbb{N}^{log}" var refedDomains = [] diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js index 099994f..35bc2dc 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/latex.js @@ -53,10 +53,10 @@ function parif(elem, contents) { 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}'; + 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; 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; case "sqrt": return '\\sqrt\\left(' + args.join(', ') + '\\right)'; @@ -92,19 +92,22 @@ function variableToLatex(vari) { "ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ", "ₜ","¹","²","³","⁴","⁵","⁶", "⁷","⁸","⁹","⁰","₁","₂","₃", - "₄","₅","₆","₇","₈","₉","₀"] - 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}", + "₄","₅","₆","₇","₈","₉","₀", + "pi"] + 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}"] + "{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}", + "\\pi"] for(let i = 0; i < unicodechars.length; i++) { + //console.log(vari, unicodechars[i], equivalchars[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; } @@ -140,7 +143,7 @@ function expressionToLatex(tokens) { switch(f) { case '-': case '+': - nstack.push(n1 + this.ope + n2); + nstack.push(n1 + f + n2); break; case '||': case 'or': @@ -148,7 +151,7 @@ function expressionToLatex(tokens) { case 'and': case '==': case '!=': - nstack.push(par(n1) + this.ope + par(n2)); + nstack.push(par(n1) + f + par(n2)); break; case '*': nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-'])); @@ -182,7 +185,7 @@ function expressionToLatex(tokens) { break; case ExprEval.IVAR: case ExprEval.IVARNAME: - nstack.push(variableToLatex(item.value)); + nstack.push(variableToLatex(item.value.toString())); break; case ExprEval.IOP1: // Unary operator n1 = nstack.pop(); @@ -209,6 +212,7 @@ function expressionToLatex(tokens) { f = nstack.pop(); // Handling various functions nstack.push(functionToLatex(f, args)) + break; case ExprEval.IFUNDEF: nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2)); break; @@ -235,12 +239,7 @@ function expressionToLatex(tokens) { } } if (nstack.length > 1) { - if (toJS) { - nstack = [ nstack.join(',') ]; - } else { - nstack = [ nstack.join(';') ]; - } + nstack = [ nstack.join(';') ] } - console.log(nstack[0]); return String(nstack[0]); } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js index 7988949..ced0cfa 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/math/sequence.js @@ -34,7 +34,7 @@ class Sequence extends Expr.Expression { this.calcValues = Object.assign({}, baseValues) for(var n in this.calcValues) 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) } @@ -58,11 +58,11 @@ class Sequence extends Expr.Expression { cache(n = 1) { 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) l[this.name] = this.calcValues - currentVars = Object.assign(l, C.evalVariables) - this.calcValues[n] = expr.evaluate(currentVars) + C.currentVars = Object.assign(l, C.evalVariables) + this.calcValues[n] = expr.evaluate(C.currentVars) } toString(forceSign=false) { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js index d9dc33f..c602224 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js @@ -89,6 +89,18 @@ class DrawableObject { } getLabel() { + switch(this.labelContent) { + case 'name': + return this.name + case 'name + value': + return this.getReadableString() + case 'null': + return '' + + } + } + + getLatexLabel() { switch(this.labelContent) { case 'name': return this.name diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js index 9b474a2..c640a8d 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js @@ -22,6 +22,7 @@ .import "../utils.js" as Utils .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex 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() { return [this.name, this.visible, this.color.toString(), this.labelContent, 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 posX = canvas.x2px(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': canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height) break; @@ -142,13 +185,13 @@ class Function extends Common.ExecutableObject { case 'below-right': canvas.drawVisibleText(ctx, text, posX, posY+textSize.height) break; - } + }*/ } static drawFunction(canvas, ctx, expr, definitionDomain, destinationDomain, drawPoints = true, drawDash = true) { // Reusable in other objects. - // Drawing small traits every 2px - var pxprecision = 0.2 + // Drawing small traits every 0.2px + var pxprecision = 1 var previousX = canvas.px2x(0) var previousY; if(definitionDomain instanceof MathLib.SpecialDomain && definitionDomain.moveSupported) { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js index feb965f..dd1fc1e 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js @@ -21,6 +21,7 @@ .import "common.js" as Common .import "../mathlib.js" as MathLib .import "../parameters.js" as P +.import "../math/latex.js" as Latex class Point extends Common.DrawableObject { @@ -59,7 +60,7 @@ class Point extends Common.DrawableObject { } 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() { @@ -86,41 +87,42 @@ class Point extends Common.DrawableObject { } let drawLabel = function(canvas, ctx, ltxImg) { - //console.log(JSON.stringify(ltxImg), canvas.isImageLoaded(ltxImg.source), this, this.labelPosition) switch(this.labelPosition) { case 'top': 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; case 'bottom': 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; 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; 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; case 'top-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; case 'top-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; case 'bottom-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; case 'bottom-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; } } - 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) } } diff --git a/LogarithmPlotter/util/latex.py b/LogarithmPlotter/util/latex.py index 680613a..07b4b9d 100644 --- a/LogarithmPlotter/util/latex.py +++ b/LogarithmPlotter/util/latex.py @@ -38,14 +38,14 @@ class Latex(QObject): if not path.exists(exprpath): fg = color.convertTo(QColor.Rgb) 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", "-z", "0", "--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", "-fg", fg], - euler=True) + euler=False) 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 return f'{exprpath},{img.width()},{img.height()}' diff --git a/ci/test1.lpf b/ci/test1.lpf index 7785158..b21f304 100644 --- a/ci/test1.lpf +++ b/ci/test1.lpf @@ -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"} \ No newline at end of file +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"}