YAxisStep as expression, selection box for X & Y axis labels, simplifications for expressions.
This commit is contained in:
parent
487daa426a
commit
47a4ac67a9
11 changed files with 232 additions and 111 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -14,7 +14,7 @@ dist/
|
||||||
build
|
build
|
||||||
docs/html
|
docs/html
|
||||||
.directory
|
.directory
|
||||||
loggraph.kdev4
|
*.kdev4
|
||||||
*.json
|
*.json
|
||||||
.kdev4
|
.kdev4
|
||||||
AccountFree.pro
|
AccountFree.pro
|
||||||
|
|
|
@ -27,20 +27,20 @@ MenuBar {
|
||||||
text: qsTr("&Load...")
|
text: qsTr("&Load...")
|
||||||
shortcut: StandardKey.Open
|
shortcut: StandardKey.Open
|
||||||
onTriggered: settings.load()
|
onTriggered: settings.load()
|
||||||
icon.name: 'fileopen'
|
icon.name: 'document-open'
|
||||||
|
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Save")
|
text: qsTr("&Save")
|
||||||
shortcut: StandardKey.Save
|
shortcut: StandardKey.Save
|
||||||
onTriggered: settings.save()
|
onTriggered: settings.save()
|
||||||
icon.name: 'filesave'
|
icon.name: 'document-save'
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("Save &As...")
|
text: qsTr("Save &As...")
|
||||||
shortcut: StandardKey.SaveAs
|
shortcut: StandardKey.SaveAs
|
||||||
onTriggered: settings.saveAs()
|
onTriggered: settings.saveAs()
|
||||||
icon.name: 'filesaveas'
|
icon.name: 'document-save-as'
|
||||||
|
|
||||||
}
|
}
|
||||||
MenuSeparator { }
|
MenuSeparator { }
|
||||||
|
@ -57,7 +57,7 @@ MenuBar {
|
||||||
text: qsTr("&Copy diagram")
|
text: qsTr("&Copy diagram")
|
||||||
shortcut: StandardKey.Copy
|
shortcut: StandardKey.Copy
|
||||||
onTriggered: root.copyDiagramToClipboard()
|
onTriggered: root.copyDiagramToClipboard()
|
||||||
icon.name: 'editcopy'
|
icon.name: 'edit-copy'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Menu {
|
Menu {
|
||||||
|
|
|
@ -24,10 +24,16 @@ Item {
|
||||||
height: 30
|
height: 30
|
||||||
|
|
||||||
signal activated(int newIndex)
|
signal activated(int newIndex)
|
||||||
|
signal accepted()
|
||||||
|
|
||||||
property var model: []
|
|
||||||
property string label: ''
|
property string label: ''
|
||||||
|
property alias model: combox.model
|
||||||
|
property alias editable: combox.editable
|
||||||
|
property alias editText: combox.editText
|
||||||
property alias currentIndex: combox.currentIndex
|
property alias currentIndex: combox.currentIndex
|
||||||
|
function find(elementName) {
|
||||||
|
return combox.find(elementName)
|
||||||
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: labelItem
|
id: labelItem
|
||||||
|
@ -43,11 +49,10 @@ Item {
|
||||||
height: 30
|
height: 30
|
||||||
anchors.left: labelItem.right
|
anchors.left: labelItem.right
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
width: control.width - labelItem.width
|
width: control.width - labelItem.width - 5
|
||||||
model: control.model
|
|
||||||
currentIndex: model.indexOf(defValue)
|
|
||||||
onActivated: function(newIndex) {
|
onActivated: function(newIndex) {
|
||||||
control.activated(newIndex)
|
control.activated(newIndex)
|
||||||
}
|
}
|
||||||
|
onAccepted: control.accepted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import "js/objects.js" as Objects
|
import "js/objects.js" as Objects
|
||||||
import "js/utils.js" as Utils
|
import "js/utils.js" as Utils
|
||||||
|
import "js/mathlib.js" as MathLib
|
||||||
|
|
||||||
|
|
||||||
Canvas {
|
Canvas {
|
||||||
|
@ -32,12 +33,18 @@ Canvas {
|
||||||
property double ymax: 0
|
property double ymax: 0
|
||||||
property int xzoom: 10
|
property int xzoom: 10
|
||||||
property int yzoom: 10
|
property int yzoom: 10
|
||||||
property double yaxisstep: 3
|
property string yaxisstep: "3"
|
||||||
property string xlabel: ""
|
property string xlabel: ""
|
||||||
property string ylabel: ""
|
property string ylabel: ""
|
||||||
property int maxgradx: 8
|
property int maxgradx: 8
|
||||||
property int maxgrady: 1000
|
property int maxgrady: 1000
|
||||||
|
|
||||||
|
property var yaxisstepExpr: (new MathLib.Expression(`x*(${yaxisstep})`))
|
||||||
|
property double yaxisstep1: yaxisstepExpr.execute(1)
|
||||||
|
property int drawMaxY: Math.ceil(Math.max(Math.abs(ymax), Math.abs(px2y(canvasSize.height)))/yaxisstep1)
|
||||||
|
|
||||||
|
Component.onCompleted: console.log(yaxisstepExpr.toEditableString())
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
//console.log('Redrawing')
|
//console.log('Redrawing')
|
||||||
var ctx = getContext("2d");
|
var ctx = getContext("2d");
|
||||||
|
@ -71,8 +78,9 @@ Canvas {
|
||||||
drawXLine(ctx, Math.pow(10, xpow)*xmulti)
|
drawXLine(ctx, Math.pow(10, xpow)*xmulti)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(var y = -Math.round(100/yaxisstep)*yaxisstep; y < canvas.ymax; y+=yaxisstep) {
|
for(var y = 0; y < drawMaxY; y+=1) {
|
||||||
drawYLine(ctx, y)
|
drawYLine(ctx, y*yaxisstep1)
|
||||||
|
drawYLine(ctx, -y*yaxisstep1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,16 +107,21 @@ Canvas {
|
||||||
var textSize = ctx.measureText(canvas.xlabel).width
|
var textSize = ctx.measureText(canvas.xlabel).width
|
||||||
ctx.fillText(canvas.xlabel, canvas.canvasSize.width-14-textSize, axisxpx-5)
|
ctx.fillText(canvas.xlabel, canvas.canvasSize.width-14-textSize, axisxpx-5)
|
||||||
// Axis graduation labels
|
// Axis graduation labels
|
||||||
ctx.font = "14px sans-serif"
|
ctx.font = "12px sans-serif"
|
||||||
|
|
||||||
for(var xpow = -maxgradx; xpow <= maxgradx; xpow+=1) {
|
for(var xpow = -maxgradx; xpow <= maxgradx; xpow+=1) {
|
||||||
var textSize = ctx.measureText("10"+Utils.textsup(xpow)).width
|
var textSize = ctx.measureText("10"+Utils.textsup(xpow)).width
|
||||||
if(xpow != 0)
|
if(xpow != 0)
|
||||||
drawVisibleText(ctx, "10"+Utils.textsup(xpow), x2px(Math.pow(10,xpow))-textSize/2, axisxpx+12+(6*(y==0)))
|
drawVisibleText(ctx, "10"+Utils.textsup(xpow), x2px(Math.pow(10,xpow))-textSize/2, axisxpx+16+(6*(y==0)))
|
||||||
}
|
}
|
||||||
for(var y = -Math.round(maxgrady/yaxisstep)*yaxisstep; y < canvas.ymax; y+=yaxisstep) {
|
var txtMinus = ctx.measureText('-').width
|
||||||
var textSize = ctx.measureText(y).width
|
for(var y = 0; y < drawMaxY; y += 1) {
|
||||||
drawVisibleText(ctx, y, axisypx-3-textSize, y2px(y)+6+(6*(y==0)))
|
var drawY = y*yaxisstep1
|
||||||
|
var txtY = yaxisstepExpr.simplify(y)
|
||||||
|
var textSize = ctx.measureText(txtY).width
|
||||||
|
drawVisibleText(ctx, txtY, axisypx-6-textSize, y2px(drawY)+4+(10*(y==0)))
|
||||||
|
if(y != 0)
|
||||||
|
drawVisibleText(ctx, '-'+txtY, axisypx-6-textSize-txtMinus, y2px(-drawY)+4)
|
||||||
}
|
}
|
||||||
ctx.fillStyle = "#FFFFFF"
|
ctx.fillStyle = "#FFFFFF"
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ ListView {
|
||||||
isDouble: modelData[1] == 'number'
|
isDouble: modelData[1] == 'number'
|
||||||
visible: ['Expression', 'Domain', 'string', 'number'].indexOf(modelData[1]) >= 0
|
visible: ['Expression', 'Domain', 'string', 'number'].indexOf(modelData[1]) >= 0
|
||||||
defValue: visible ? {
|
defValue: visible ? {
|
||||||
'Expression': function(){return objEditor.obj[modelData[0]].toEditableString()},
|
'Expression': function(){return Utils.simplifyExpression(objEditor.obj[modelData[0]].toEditableString())},
|
||||||
'Domain': function(){return objEditor.obj[modelData[0]].toString()},
|
'Domain': function(){return objEditor.obj[modelData[0]].toString()},
|
||||||
'string': function(){return objEditor.obj[modelData[0]]},
|
'string': function(){return objEditor.obj[modelData[0]]},
|
||||||
'number': function(){return objEditor.obj[modelData[0]]}
|
'number': function(){return objEditor.obj[modelData[0]]}
|
||||||
|
|
|
@ -20,23 +20,23 @@ import QtQuick.Controls 2.12
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import "js/utils.js" as Utils
|
import "js/utils.js" as Utils
|
||||||
|
|
||||||
Grid {
|
Column {
|
||||||
id: settings
|
id: settings
|
||||||
height: 30*Math.max(1, Math.ceil(7 / columns))
|
height: 30*9 //30*Math.max(1, Math.ceil(7 / columns))
|
||||||
columns: Math.floor(width / settingWidth)
|
//columns: Math.floor(width / settingWidth)
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
signal changed()
|
signal changed()
|
||||||
|
|
||||||
property int settingWidth: 135
|
property int settingWidth: settings.width
|
||||||
|
|
||||||
property int xzoom: 100
|
property int xzoom: 100
|
||||||
property int yzoom: 10
|
property int yzoom: 10
|
||||||
property double xmin: 5/10
|
property double xmin: 5/10
|
||||||
property double ymax: 25
|
property double ymax: 25
|
||||||
property int yaxisstep: 4
|
property string yaxisstep: "4"
|
||||||
property string xaxislabel: "ω (rad/s)"
|
property string xaxislabel: ""
|
||||||
property string yaxislabel: "G (dB)"
|
property string yaxislabel: ""
|
||||||
property string saveFilename: ""
|
property string saveFilename: ""
|
||||||
|
|
||||||
FileDialog {
|
FileDialog {
|
||||||
|
@ -48,6 +48,10 @@ Grid {
|
||||||
root.saveDiagram(filePath)
|
root.saveDiagram(filePath)
|
||||||
} else {
|
} else {
|
||||||
root.loadDiagram(filePath)
|
root.loadDiagram(filePath)
|
||||||
|
if(xAxisLabel.find(settings.xaxislabel) == -1) xAxisLabel.model.append({text: settings.xaxislabel})
|
||||||
|
xAxisLabel.editText = settings.xaxislabel
|
||||||
|
if(yAxisLabel.find(settings.yaxislabel) == -1) yAxisLabel.model.append({text: settings.yaxislabel})
|
||||||
|
yAxisLabel.editText = settings.yaxislabel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +112,7 @@ Grid {
|
||||||
TextSetting {
|
TextSetting {
|
||||||
id: yAxisStep
|
id: yAxisStep
|
||||||
height: 30
|
height: 30
|
||||||
isInt: true
|
//isInt: true
|
||||||
label: "Y Axis Step"
|
label: "Y Axis Step"
|
||||||
width: settings.settingWidth
|
width: settings.settingWidth
|
||||||
defValue: settings.yaxisstep
|
defValue: settings.yaxisstep
|
||||||
|
@ -118,6 +122,58 @@ Grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComboBoxSetting {
|
||||||
|
id: xAxisLabel
|
||||||
|
height: 30
|
||||||
|
width: settings.settingWidth
|
||||||
|
label: 'X Label'
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { text: "" }
|
||||||
|
ListElement { text: "x" }
|
||||||
|
ListElement { text: "ω (rad/s)" }
|
||||||
|
}
|
||||||
|
currentIndex: find(settings.xaxislabel)
|
||||||
|
editable: true
|
||||||
|
onAccepted: function(){
|
||||||
|
editText = Utils.parseName(editText, false)
|
||||||
|
if (find(editText) === -1) model.append({text: editText})
|
||||||
|
settings.xaxislabel = editText
|
||||||
|
settings.changed()
|
||||||
|
}
|
||||||
|
onActivated: function(selectedId) {
|
||||||
|
settings.xaxislabel = model.get(selectedId).text
|
||||||
|
settings.changed()
|
||||||
|
}
|
||||||
|
Component.onCompleted: editText = settings.xaxislabel
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBoxSetting {
|
||||||
|
id: yAxisLabel
|
||||||
|
height: 30
|
||||||
|
width: settings.settingWidth
|
||||||
|
label: 'Y Label'
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { text: "" }
|
||||||
|
ListElement { text: "y" }
|
||||||
|
ListElement { text: "G (dB)" }
|
||||||
|
ListElement { text: "φ (deg)" }
|
||||||
|
ListElement { text: "φ (rad)" }
|
||||||
|
}
|
||||||
|
currentIndex: find(settings.yaxislabel)
|
||||||
|
editable: true
|
||||||
|
onAccepted: function(){
|
||||||
|
editText = Utils.parseName(editText, false)
|
||||||
|
if (find(editText) === -1) model.append({text: editText, yaxisstep: root.yaxisstep})
|
||||||
|
settings.yaxislabel = editText
|
||||||
|
settings.changed()
|
||||||
|
}
|
||||||
|
onActivated: function(selectedId) {
|
||||||
|
settings.yaxislabel = model.get(selectedId).text
|
||||||
|
settings.changed()
|
||||||
|
}
|
||||||
|
Component.onCompleted: editText = settings.yaxislabel
|
||||||
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: copyToClipboard
|
id: copyToClipboard
|
||||||
height: 30
|
height: 30
|
||||||
|
@ -127,30 +183,6 @@ Grid {
|
||||||
onClicked: root.copyDiagramToClipboard()
|
onClicked: root.copyDiagramToClipboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
TextSetting {
|
|
||||||
id: xAxisLabel
|
|
||||||
height: 30
|
|
||||||
label: "X Label"
|
|
||||||
width: settings.settingWidth
|
|
||||||
defValue: settings.xaxislabel
|
|
||||||
onChanged: function(newValue) {
|
|
||||||
settings.xaxislabel = Utils.parseName(newValue, false)
|
|
||||||
settings.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextSetting {
|
|
||||||
id: yAxisLabel
|
|
||||||
height: 30
|
|
||||||
label: "Y Label"
|
|
||||||
width: settings.settingWidth
|
|
||||||
defValue: settings.yaxislabel
|
|
||||||
onChanged: function(newValue) {
|
|
||||||
settings.yaxislabel = Utils.parseName(newValue, false)
|
|
||||||
settings.changed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: saveDiagram
|
id: saveDiagram
|
||||||
height: 30
|
height: 30
|
||||||
|
|
|
@ -31,11 +31,6 @@ Item {
|
||||||
property string label
|
property string label
|
||||||
property string defValue
|
property string defValue
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: labelItem.width + input.width
|
|
||||||
height: Math.max(labelItem.height, input.height)
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: labelItem
|
id: labelItem
|
||||||
height: 30
|
height: 30
|
||||||
|
@ -46,12 +41,12 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextInput {
|
TextField {
|
||||||
id: input
|
id: input
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: labelItem.right
|
anchors.left: labelItem.right
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
width: control.width - labelItem.width
|
width: control.width - labelItem.width - 5
|
||||||
height: 30
|
height: 30
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
@ -66,13 +61,4 @@ Item {
|
||||||
if(value != "") control.changed(value)
|
if(value != "") control.changed(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
color: sysPalette.windowText
|
|
||||||
anchors.left: input.left
|
|
||||||
anchors.right: input.right
|
|
||||||
anchors.bottom: input.bottom
|
|
||||||
height: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,21 @@
|
||||||
|
|
||||||
const parser = new ExprEval.Parser()
|
const parser = new ExprEval.Parser()
|
||||||
|
|
||||||
|
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manualy
|
||||||
|
"pi": Math.PI,
|
||||||
|
"π": Math.PI,
|
||||||
|
"inf": Infinity,
|
||||||
|
"Infinity": Infinity,
|
||||||
|
"∞": Infinity,
|
||||||
|
"e": Math.E
|
||||||
|
}
|
||||||
|
|
||||||
class Expression {
|
class Expression {
|
||||||
constructor(expr) {
|
constructor(expr) {
|
||||||
this.expr = expr
|
this.expr = expr
|
||||||
this.calc = parser.parse(expr).simplify()
|
this.calc = parser.parse(expr).simplify()
|
||||||
|
this.cached = this.isConstant()
|
||||||
|
this.cachedValue = this.cached ? this.calc.evaluate(evalVariables) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() {
|
isConstant() {
|
||||||
|
@ -34,19 +45,14 @@ class Expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(x = 1) {
|
execute(x = 1) {
|
||||||
return this.calc.evaluate({
|
if(this.cached) return this.cachedValue
|
||||||
"x": x,
|
return this.calc.evaluate(Object.assign({'x': x}, evalVariables))
|
||||||
"pi": Math.PI,
|
|
||||||
"π": Math.PI,
|
|
||||||
"inf": Infinity,
|
|
||||||
"Infinity": Infinity,
|
|
||||||
"∞": Infinity,
|
|
||||||
"e": Math.E
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simplify(x = 1) {
|
simplify(x = 1) {
|
||||||
return Utils.makeExpressionReadable(this.calc.substitute('x', x).simplify().toString())
|
var expr = this.calc.substitute('x', x).simplify()
|
||||||
|
if(expr.evaluate(evalVariables) == 0) return '0'
|
||||||
|
return Utils.makeExpressionReadable(expr.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
toEditableString() {
|
toEditableString() {
|
||||||
|
|
|
@ -200,7 +200,7 @@ class Function extends ExecutableObject {
|
||||||
|
|
||||||
getReadableString() {
|
getReadableString() {
|
||||||
if(this.displayMode == 'application') {
|
if(this.displayMode == 'application') {
|
||||||
return `${this.name}: ${this.inDomain} ⸺˃ ${this.outDomain}\n ${' '.repeat(this.name.length)}x ⸺˃ ${this.expression.toString()}`
|
return `${this.name}: ${this.inDomain} ⸺> ${this.outDomain}\n ${' '.repeat(this.name.length)}x ⸺> ${this.expression.toString()}`
|
||||||
} else {
|
} else {
|
||||||
return `${this.name}(x) = ${this.expression.toString()}`
|
return `${this.name}(x) = ${this.expression.toString()}`
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,26 +119,104 @@ function textsub(text) {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function simplifyExpression(str) {
|
||||||
|
var replacements = [
|
||||||
|
// Operations not done by parser.
|
||||||
|
[ // Removing parenthesis when content is only added from both sides.
|
||||||
|
/(^.?|[+-] |\()\(([^)(]+)\)(.?$| [+-]|\))/g,
|
||||||
|
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
||||||
|
],
|
||||||
|
[ // Removing parenthesis when content is only multiplied.
|
||||||
|
/(^.?|[*\/] |\()\(([^)(+-]+)\)(.?$| [*\/]|\))/g,
|
||||||
|
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
||||||
|
],
|
||||||
|
[// Simplification additions/substractions.
|
||||||
|
/(^.?|[^*\/] |\()([-.\d]+) (\+|\-) (\([^)(]+\)|[^)(]+) (\+|\-) ([-.\d]+)(.?$| [^*\/]|\))/g,
|
||||||
|
function(match, b4, n1, op1, middle, op2, n2, after) {
|
||||||
|
var total
|
||||||
|
if(op2 == '+') {
|
||||||
|
total = parseFloat(n1) + parseFloat(n2)
|
||||||
|
} else {
|
||||||
|
total = parseFloat(n1) - parseFloat(n2)
|
||||||
|
}
|
||||||
|
return `${b4}${total} ${op1} ${middle}${after}`
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[// Simplification multiplications/divisions.
|
||||||
|
/([-.\d]+) (\*|\/) (\([^)(]+\)|[^)(+-]+) (\*|\/) ([-.\d]+)/g,
|
||||||
|
function(match, n1, op1, middle, op2, n2) {
|
||||||
|
if(parseInt(n1) == n1 && parseInt(n2) == n2 && op2 == '/' &&
|
||||||
|
(parseInt(n1) / parseInt(n2)) % 1 != 0) {
|
||||||
|
// Non int result for int division.
|
||||||
|
return `(${n1} / ${n2}) ${op1} ${middle}`
|
||||||
|
} else {
|
||||||
|
if(op2 == '*') {
|
||||||
|
return `${parseFloat(n1) * parseFloat(n2)} ${op1} ${middle}`
|
||||||
|
} else {
|
||||||
|
return `${parseFloat(n1) / parseFloat(n2)} ${op1} ${middle}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[// Starting & ending parenthesis if not needed.
|
||||||
|
/^\((.*)\)$/g,
|
||||||
|
function(match, middle) {
|
||||||
|
var str = middle
|
||||||
|
// Replace all groups
|
||||||
|
while(/\([^)(]+\)/g.test(str))
|
||||||
|
str = str.replace(/\([^)(]+\)/g, '')
|
||||||
|
// There shouldn't be any more parenthesis
|
||||||
|
// If there is, that means the 2 parenthesis are needed.
|
||||||
|
if(!str.includes(')') && !str.includes('(')) {
|
||||||
|
return middle
|
||||||
|
} else {
|
||||||
|
return `(${middle})`
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
],
|
||||||
|
// Simple simplifications
|
||||||
|
[/(\s|^|\()0 \* (\([^)(]+\))/g, '$10'],
|
||||||
|
[/(\s|^|\()0 \* ([^)(+-]+)/g, '$10'],
|
||||||
|
[/(\([^)(]\)) \* 0(\s|$|\))/g, '0$2'],
|
||||||
|
[/([^)(+-]) \* 0(\s|$|\))/g, '0$2'],
|
||||||
|
[/(\s|^|\()1 (\*|\/) /g, '$1'],
|
||||||
|
[/(\s|^|\()0 (\+|\-) /g, '$1'],
|
||||||
|
[/ (\*|\/) 1(\s|$|\))/g, '$2'],
|
||||||
|
[/ (\+|\-) 0(\s|$|\))/g, '$2'],
|
||||||
|
[/(^| |\() /g, '$1'],
|
||||||
|
[/ ($|\))/g, '$1'],
|
||||||
|
]
|
||||||
|
|
||||||
|
console.log(str)
|
||||||
|
// Replacements
|
||||||
|
replacements.forEach(function(replacement){
|
||||||
|
while(replacement[0].test(str))
|
||||||
|
str = str.replace(replacement[0], replacement[1])
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
function makeExpressionReadable(str) {
|
function makeExpressionReadable(str) {
|
||||||
var replacements = [
|
var replacements = [
|
||||||
|
// variables
|
||||||
[/pi/g, 'π'],
|
[/pi/g, 'π'],
|
||||||
[/Infinity/g, '∞'],
|
[/Infinity/g, '∞'],
|
||||||
[/inf/g, '∞'],
|
[/inf/g, '∞'],
|
||||||
|
// Other
|
||||||
[/ \* /g, '×'],
|
[/ \* /g, '×'],
|
||||||
[/ \^ /g, '^'],
|
[/ \^ /g, '^'],
|
||||||
[/\^\(([^\^]+)\)/g, function(match, p1) { return textsup(p1) }],
|
[/\^\(([^\^]+)\)/g, function(match, p1) { return textsup(p1) }],
|
||||||
[/\^([^ ]+)/g, function(match, p1) { return textsup(p1) }],
|
[/\^([^ ]+)/g, function(match, p1) { return textsup(p1) }],
|
||||||
[/(\d|\))×/g, '$1'],
|
[/(\d|\))×/g, '$1'],
|
||||||
[/×(\d|\()/g, '$1'],
|
[/×(\d|\()/g, '$1'],
|
||||||
[/\(([^)(+.-]+)\)/g, "$1"],
|
[/\(([^)(+.\/-]+)\)/g, "$1"],
|
||||||
[/\(([^)(+.-]+)\)/g, "$1"],
|
|
||||||
[/\(([^)(+.-]+)\)/g, "$1"],
|
|
||||||
[/\(([^)(+.-]+)\)/g, "$1"],
|
|
||||||
[/\(([^)(+.-]+)\)/g, "$1"],
|
|
||||||
// Doing it 4 times to be recursive until better implementation
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
str = simplifyExpression(str)
|
||||||
// Replacements
|
// Replacements
|
||||||
replacements.forEach(function(replacement){
|
replacements.forEach(function(replacement){
|
||||||
|
while(replacement[0].test(str))
|
||||||
str = str.replace(replacement[0], replacement[1])
|
str = str.replace(replacement[0], replacement[1])
|
||||||
})
|
})
|
||||||
return str
|
return str
|
||||||
|
@ -184,7 +262,7 @@ function parseName(str, removeUnallowed = true) {
|
||||||
[/_\(([^\^]+)\)/g, function(match, p1) { return textsub(p1) }],
|
[/_\(([^\^]+)\)/g, function(match, p1) { return textsub(p1) }],
|
||||||
[/_([^ ]+)/g, function(match, p1) { return textsub(p1) }],
|
[/_([^ ]+)/g, function(match, p1) { return textsub(p1) }],
|
||||||
// Removing
|
// Removing
|
||||||
[/[xπℝℕ\\∪∩\]\[ ()^/÷*×+=\d-]/g , function(match){console.log('removing', match); return ''}],
|
[/[xπℝℕ\\∪∩\]\[ ()^/÷*×+=\d-]/g , ''],
|
||||||
]
|
]
|
||||||
if(!removeUnallowed) replacements.pop()
|
if(!removeUnallowed) replacements.pop()
|
||||||
// Replacements
|
// Replacements
|
||||||
|
@ -194,6 +272,7 @@ function parseName(str, removeUnallowed = true) {
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String.prototype.toLatinUppercase = function() {
|
String.prototype.toLatinUppercase = function() {
|
||||||
return this.replace(/[a-z]/g, function(match){return match.toUpperCase()})
|
return this.replace(/[a-z]/g, function(match){return match.toUpperCase()})
|
||||||
}
|
}
|
||||||
|
|
2
run.py
2
run.py
|
@ -30,7 +30,7 @@ tempfile = tempfile.mkstemp(suffix = '.png')[1]
|
||||||
|
|
||||||
def get_linux_theme():
|
def get_linux_theme():
|
||||||
des = {
|
des = {
|
||||||
"KDE": "org.kde.desktop", # org.kde.desktop resolves to universal in PySide2.
|
"KDE": "fusion", # org.kde.desktop resolves to universal in PySide2.
|
||||||
"gnome": "default",
|
"gnome": "default",
|
||||||
"lxqt": "fusion",
|
"lxqt": "fusion",
|
||||||
"mate": "fusion",
|
"mate": "fusion",
|
||||||
|
|
Loading…
Reference in a new issue