Compare commits
4 commits
3dc69cc9ba
...
1a433eba27
Author | SHA1 | Date | |
---|---|---|---|
1a433eba27 | |||
1ba594c4f7 | |||
6b535dd8a2 | |||
fad5325501 |
21 changed files with 178 additions and 99 deletions
|
@ -249,18 +249,24 @@ ApplicationWindow {
|
||||||
|
|
||||||
// Importing objects
|
// Importing objects
|
||||||
Objects.currentObjects = {}
|
Objects.currentObjects = {}
|
||||||
for(var objType in data['objects']) {
|
Objects.currentObjectsByName = {}
|
||||||
|
for(let objType in data['objects']) {
|
||||||
if(Object.keys(Objects.types).indexOf(objType) > -1) {
|
if(Object.keys(Objects.types).indexOf(objType) > -1) {
|
||||||
Objects.currentObjects[objType] = []
|
Objects.currentObjects[objType] = []
|
||||||
for(var objData of data['objects'][objType]) {
|
for(let objData of data['objects'][objType]) {
|
||||||
var obj = new Objects.types[objType](...objData)
|
let obj = new Objects.types[objType](...objData)
|
||||||
Objects.currentObjects[objType].push(obj)
|
Objects.currentObjects[objType].push(obj)
|
||||||
|
Objects.currentObjectsByName[obj.name] = obj
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
|
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updating object dependencies.
|
||||||
|
for(let objName in Objects.currentObjectsByName)
|
||||||
|
Objects.currentObjectsByName[objName].update()
|
||||||
|
|
||||||
// Importing history
|
// Importing history
|
||||||
if("history" in data)
|
if("history" in data)
|
||||||
history.unserialize(...data["history"])
|
history.unserialize(...data["history"])
|
||||||
|
|
|
@ -74,29 +74,39 @@ D.Dialog {
|
||||||
width: objEditor.width - 20
|
width: objEditor.width - 20
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
|
D.MessageDialog {
|
||||||
|
id: invalidNameDialog
|
||||||
|
title: qsTr("LogarithmPlotter - Invalid object name")
|
||||||
|
text: ""
|
||||||
|
function showDialog(objectName) {
|
||||||
|
text = qsTr("An object with the name '%1' already exists.").arg(objectName)
|
||||||
|
open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
id: nameProperty
|
id: nameProperty
|
||||||
height: 30
|
height: 30
|
||||||
label: qsTr("Name")
|
label: qsTr("Name")
|
||||||
icon: "common/label.svg"
|
icon: "common/label.svg"
|
||||||
min: 1
|
|
||||||
width: dlgProperties.width
|
width: dlgProperties.width
|
||||||
value: objEditor.obj.name
|
value: objEditor.obj.name
|
||||||
onChanged: function(newValue) {
|
onChanged: function(newValue) {
|
||||||
var newName = Utils.parseName(newValue)
|
let newName = Utils.parseName(newValue)
|
||||||
if(newName != '' && objEditor.obj.name != newName) {
|
if(newName != '' && objEditor.obj.name != newName) {
|
||||||
if(Objects.getObjectByName(newName) != null) {
|
if(newName in Objects.currentObjectsByName) {
|
||||||
newName = ObjectsCommons.getNewName(newName)
|
invalidNameDialog.showDialog(newName)
|
||||||
}
|
} else {
|
||||||
history.addToHistory(new HistoryLib.NameChanged(
|
history.addToHistory(new HistoryLib.NameChanged(
|
||||||
objEditor.obj.name, objEditor.objType, newName
|
objEditor.obj.name, objEditor.objType, newName
|
||||||
))
|
))
|
||||||
Objects.currentObjects[objEditor.objType][objEditor.objIndex].name = newName
|
Objects.renameObject(obj.name, newName)
|
||||||
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
||||||
objectListList.update()
|
objectListList.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Setting.ComboBoxSetting {
|
Setting.ComboBoxSetting {
|
||||||
id: labelContentProperty
|
id: labelContentProperty
|
||||||
|
@ -213,7 +223,7 @@ D.Dialog {
|
||||||
[]) :
|
[]) :
|
||||||
modelData[1].values)
|
modelData[1].values)
|
||||||
: []
|
: []
|
||||||
// Translated verison of the model.
|
// Translated version of the model.
|
||||||
model: selectObjMode ? baseModel : modelData[1].translatedValues
|
model: selectObjMode ? baseModel : modelData[1].translatedValues
|
||||||
visible: paramTypeIn(modelData[1], ['ObjectType', 'Enum'])
|
visible: paramTypeIn(modelData[1], ['ObjectType', 'Enum'])
|
||||||
currentIndex: baseModel.indexOf(selectObjMode ? objEditor.obj[modelData[0]].name : objEditor.obj[modelData[0]])
|
currentIndex: baseModel.indexOf(selectObjMode ? objEditor.obj[modelData[0]].name : objEditor.obj[modelData[0]])
|
||||||
|
@ -222,7 +232,7 @@ D.Dialog {
|
||||||
if(selectObjMode) {
|
if(selectObjMode) {
|
||||||
// This is only done when what we're selecting are Objects.
|
// This is only done when what we're selecting are Objects.
|
||||||
// Setting object property.
|
// Setting object property.
|
||||||
var selectedObj = Objects.getObjectByName(baseModel[newIndex], modelData[1].objType)
|
var selectedObj = Objects.currentObjectsByName[baseModel[newIndex]]
|
||||||
if(newIndex != 0) {
|
if(newIndex != 0) {
|
||||||
// Make sure we don't set the object to null.
|
// Make sure we don't set the object to null.
|
||||||
if(selectedObj == null) {
|
if(selectedObj == null) {
|
||||||
|
|
|
@ -193,8 +193,7 @@ ScrollView {
|
||||||
history.addToHistory(new HistoryLib.DeleteObject(
|
history.addToHistory(new HistoryLib.DeleteObject(
|
||||||
obj.name, objType, obj.export()
|
obj.name, objType, obj.export()
|
||||||
))
|
))
|
||||||
Objects.currentObjects[objType][index].delete()
|
Objects.deleteObject(obj.name)
|
||||||
Objects.currentObjects[objType].splice(index, 1)
|
|
||||||
objectListList.update()
|
objectListList.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ Item {
|
||||||
'Expression': () => new MathLib.Expression(newValue),
|
'Expression': () => new MathLib.Expression(newValue),
|
||||||
'number': () => parseFloat(newValue)
|
'number': () => parseFloat(newValue)
|
||||||
}[Objects.types[objType].properties()[propertyX]]()
|
}[Objects.types[objType].properties()[propertyX]]()
|
||||||
let obj = Objects.getObjectByName(objName, objType)
|
let obj = Objects.currentObjectsByName[objName] // getObjectByName(objName, objType)
|
||||||
history.addToHistory(new HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
objName, objType, propertyX, obj[propertyX], newValue
|
objName, objType, propertyX, obj[propertyX], newValue
|
||||||
))
|
))
|
||||||
|
@ -112,7 +112,7 @@ Item {
|
||||||
'Expression': () => new MathLib.Expression(newValue),
|
'Expression': () => new MathLib.Expression(newValue),
|
||||||
'number': () => parseFloat(newValue)
|
'number': () => parseFloat(newValue)
|
||||||
}[Objects.types[objType].properties()[propertyY]]()
|
}[Objects.types[objType].properties()[propertyY]]()
|
||||||
let obj = Objects.getObjectByName(objName, objType)
|
let obj = Objects.currentObjectsByName[objName] // Objects.getObjectByName(objName, objType)
|
||||||
history.addToHistory(new HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
objName, objType, propertyY, obj[propertyY], newValue
|
objName, objType, propertyY, obj[propertyY], newValue
|
||||||
))
|
))
|
||||||
|
|
|
@ -194,6 +194,7 @@ function evaluate(tokens, expr, values) {
|
||||||
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
||||||
}
|
}
|
||||||
} else if (type === IVAR) {
|
} else if (type === IVAR) {
|
||||||
|
// Check for variable value
|
||||||
if (item.value in expr.functions) {
|
if (item.value in expr.functions) {
|
||||||
nstack.push(expr.functions[item.value]);
|
nstack.push(expr.functions[item.value]);
|
||||||
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
||||||
|
@ -219,8 +220,11 @@ function evaluate(tokens, expr, values) {
|
||||||
f = nstack.pop();
|
f = nstack.pop();
|
||||||
if (f.apply && f.call) {
|
if (f.apply && f.call) {
|
||||||
nstack.push(f.apply(undefined, args));
|
nstack.push(f.apply(undefined, args));
|
||||||
|
} else if(f.execute) {
|
||||||
|
// Objects & expressions execution
|
||||||
|
nstack.push(f.execute.apply(f, args));
|
||||||
} else {
|
} else {
|
||||||
throw new Error(f + ' is not a function');
|
throw new Error(f + ' cannot be executed');
|
||||||
}
|
}
|
||||||
} else if (type === IFUNDEF) {
|
} else if (type === IFUNDEF) {
|
||||||
// Create closure to keep references to arguments and expression
|
// Create closure to keep references to arguments and expression
|
||||||
|
|
|
@ -36,9 +36,11 @@ class CreateNewObject extends C.Action {
|
||||||
|
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
var targetIndex = Objects.getObjectsName(this.targetType).indexOf(this.targetName)
|
Objects.deleteObject(this.targetName)
|
||||||
Objects.currentObjects[this.targetType][targetIndex].delete()
|
//let targetIndex = Objects.getObjectsName(this.targetType).indexOf(this.targetName)
|
||||||
Objects.currentObjects[this.targetType].splice(targetIndex, 1)
|
//delete Objects.currentObjectsByName[this.targetName]
|
||||||
|
//Objects.currentObjects[this.targetType][targetIndex].delete()
|
||||||
|
//Objects.currentObjects[this.targetType].splice(targetIndex, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
redo() {
|
redo() {
|
||||||
|
|
|
@ -49,19 +49,21 @@ class EditedProperty extends C.Action {
|
||||||
this.newValue = MathLib.parseDomain(this.newValue);
|
this.newValue = MathLib.parseDomain(this.newValue);
|
||||||
} else {
|
} else {
|
||||||
// Objects
|
// Objects
|
||||||
this.previousValue = Objects.getObjectByName(this.previousValue);
|
this.previousValue = Objects.currentObjectsByName[this.previousValue] // Objects.getObjectByName(this.previousValue);
|
||||||
this.newValue = Objects.getObjectByName(this.newValue);
|
this.newValue = Objects.currentObjectsByName[this.newValue] // Objects.getObjectByName(this.newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setReadableValues()
|
this.setReadableValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
Objects.getObjectByName(this.targetName, this.targetType)[this.targetProperty] = this.previousValue
|
Objects.currentObjectsByName[this.targetName][this.targetProperty] = this.previousValue
|
||||||
|
Objects.currentObjectsByName[this.targetName].update()
|
||||||
}
|
}
|
||||||
|
|
||||||
redo() {
|
redo() {
|
||||||
Objects.getObjectByName(this.targetName, this.targetType)[this.targetProperty] = this.newValue
|
Objects.currentObjectsByName[this.targetName][this.targetProperty] = this.newValue
|
||||||
|
Objects.currentObjectsByName[this.targetName].update()
|
||||||
}
|
}
|
||||||
|
|
||||||
export() {
|
export() {
|
||||||
|
|
|
@ -40,11 +40,15 @@ class NameChanged extends EP.EditedProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
Objects.getObjectByName(this.newValue, this.targetType)['name'] = this.previousValue
|
Objects.renameObject(this.newValue, this.previousValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
redo() {
|
redo() {
|
||||||
Objects.getObjectByName(this.previousValue, this.targetType)['name'] = this.newValue
|
Objects.renameObject(this.previousValue, this.newValue)
|
||||||
|
//let obj = Objects.currentObjectsByName[this.previousValue]
|
||||||
|
//obj.name = this.newValue
|
||||||
|
//Objects.currentObjectsByName[this.newValue] = obj
|
||||||
|
//delete Objects.currentObjectsByName[this.previousValue]
|
||||||
}
|
}
|
||||||
|
|
||||||
getReadableString() {
|
getReadableString() {
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
.import "../utils.js" as Utils
|
.import "../utils.js" as Utils
|
||||||
.import "latex.js" as Latex
|
.import "latex.js" as Latex
|
||||||
|
|
||||||
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manualy
|
const DERIVATION_PRECISION = 0.1
|
||||||
|
|
||||||
|
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manually
|
||||||
"pi": Math.PI,
|
"pi": Math.PI,
|
||||||
"π": Math.PI,
|
"π": Math.PI,
|
||||||
"inf": Infinity,
|
"inf": Infinity,
|
||||||
|
@ -33,18 +35,21 @@ var evalVariables = { // Variables not provided by expr-eval.js, needs to be pro
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentVars = {}
|
var currentVars = {}
|
||||||
|
var currentObjectsByName = {} // Mirror of currentObjectsByName in objects.js
|
||||||
|
|
||||||
const parser = new ExprEval.Parser()
|
const parser = new ExprEval.Parser()
|
||||||
|
|
||||||
|
parser.consts = Object.assign({}, parser.consts, evalVariables)
|
||||||
|
|
||||||
|
// Function definition
|
||||||
parser.functions.integral = function(a, b, f, variable) {
|
parser.functions.integral = function(a, b, f, variable) {
|
||||||
// https://en.wikipedia.org/wiki/Simpson%27s_rule
|
// https://en.wikipedia.org/wiki/Simpson%27s_rule
|
||||||
|
// Simpler, faster than tokenizing the expression
|
||||||
f = parser.parse(f).toJSFunction(variable, currentVars)
|
f = parser.parse(f).toJSFunction(variable, currentVars)
|
||||||
return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b))
|
return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
const DERIVATION_PRECISION = 0.1
|
|
||||||
|
|
||||||
parser.functions.derivative = function(f, variable, x) {
|
parser.functions.derivative = function(f, variable, x) {
|
||||||
f = parser.parse(f).toJSFunction(variable, currentVars)
|
f = parser.parse(f).toJSFunction(variable, currentVars)
|
||||||
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
return (f(x+DERIVATION_PRECISION/2)-f(x-DERIVATION_PRECISION/2))/DERIVATION_PRECISION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,23 +30,42 @@ class Expression {
|
||||||
this.expr = expr
|
this.expr = expr
|
||||||
this.calc = C.parser.parse(expr).simplify()
|
this.calc = C.parser.parse(expr).simplify()
|
||||||
this.cached = this.isConstant()
|
this.cached = this.isConstant()
|
||||||
this.cachedValue = this.cached ? this.calc.evaluate(C.evalVariables) : null
|
this.cachedValue = this.cached && this.allRequirementsFullfilled() ? this.calc.evaluate(C.currentObjectsByName) : null
|
||||||
this.latexMarkup = Latex.expression(this.calc.tokens)
|
this.latexMarkup = Latex.expression(this.calc.tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
isConstant() {
|
isConstant() {
|
||||||
return !this.expr.includes("x") && !this.expr.includes("n")
|
let vars = this.calc.variables()
|
||||||
|
return !vars.includes("x") && !vars.includes("n")
|
||||||
|
}
|
||||||
|
|
||||||
|
requiredObjects() {
|
||||||
|
return this.calc.variables().filter(objName => objName != "x" && objName != "n")
|
||||||
|
}
|
||||||
|
|
||||||
|
allRequirementsFullfilled() {
|
||||||
|
return this.requiredObjects().every(objName => objName in C.currentObjectsByName)
|
||||||
|
}
|
||||||
|
|
||||||
|
recache() {
|
||||||
|
if(this.cached)
|
||||||
|
this.cachedValue = this.calc.evaluate(C.currentObjectsByName)
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(x = 1) {
|
execute(x = 1) {
|
||||||
if(this.cached) return this.cachedValue
|
if(this.cached) {
|
||||||
C.currentVars = Object.assign({'x': x}, C.evalVariables)
|
if(this.cachedValue == null)
|
||||||
|
this.cachedValue = this.calc.evaluate(C.currentObjectsByName)
|
||||||
|
return this.cachedValue
|
||||||
|
}
|
||||||
|
C.currentVars = Object.assign({'x': x}, C.currentObjectsByName)
|
||||||
|
//console.log("Executing", this.expr, "with", JSON.stringify(C.currentVars))
|
||||||
return this.calc.evaluate(C.currentVars)
|
return this.calc.evaluate(C.currentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
simplify(x) {
|
simplify(x) {
|
||||||
var expr = this.calc.substitute('x', x).simplify()
|
var expr = this.calc.substitute('x', x).simplify()
|
||||||
if(expr.evaluate(C.evalVariables) == 0) return '0'
|
if(expr.evaluate() == 0) return '0'
|
||||||
var str = Utils.makeExpressionReadable(expr.toString());
|
var str = Utils.makeExpressionReadable(expr.toString());
|
||||||
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
if(str != undefined && str.match(/^\d*\.\d+$/)) {
|
||||||
if(str.split('.')[1].split('0').length > 7) {
|
if(str.split('.')[1].split('0').length > 7) {
|
||||||
|
@ -66,7 +85,7 @@ class Expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(forceSign=false) {
|
toString(forceSign=false) {
|
||||||
var str = Utils.makeExpressionReadable(this.calc.toString())
|
let str = Utils.makeExpressionReadable(this.calc.toString())
|
||||||
if(str[0] != '-' && forceSign) str = '+' + str
|
if(str[0] != '-' && forceSign) str = '+' + str
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Sequence extends Expr.Expression {
|
||||||
if(['string', 'number'].includes(typeof this.calcValues[n])) {
|
if(['string', 'number'].includes(typeof this.calcValues[n])) {
|
||||||
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
|
let parsed = C.parser.parse(this.calcValues[n].toString()).simplify()
|
||||||
this.latexValues[n] = Latex.expression(parsed.tokens)
|
this.latexValues[n] = Latex.expression(parsed.tokens)
|
||||||
this.calcValues[n] = parsed.evaluate(C.evalVariables)
|
this.calcValues[n] = parsed.evaluate()
|
||||||
}
|
}
|
||||||
this.valuePlus = parseInt(valuePlus)
|
this.valuePlus = parseInt(valuePlus)
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,10 @@ 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 = C.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)
|
C.currentVars = Object.assign(
|
||||||
l[this.name] = this.calcValues
|
{'n': n-this.valuePlus, [this.name]: this.calcValues}, // Just in case, add n (for custom functions)
|
||||||
C.currentVars = Object.assign(l, C.evalVariables)
|
C.currentObjectsByName
|
||||||
|
)
|
||||||
this.calcValues[n] = expr.evaluate(C.currentVars)
|
this.calcValues[n] = expr.evaluate(C.currentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,36 +19,44 @@
|
||||||
.pragma library
|
.pragma library
|
||||||
|
|
||||||
.import "utils.js" as Utils
|
.import "utils.js" as Utils
|
||||||
.import "mathlib.js" as MathLib
|
.import "math/common.js" as MathCommons
|
||||||
.import "parameters.js" as P
|
.import "parameters.js" as P
|
||||||
|
|
||||||
var types = {}
|
var types = {}
|
||||||
|
|
||||||
var currentObjects = {}
|
var currentObjects = {}
|
||||||
|
var currentObjectsByName = {}
|
||||||
|
MathCommons.currentObjectsByName = currentObjectsByName // Required for using objects in variables.
|
||||||
|
|
||||||
function getObjectByName(objName, objType = null) {
|
function renameObject(oldName, newName) {
|
||||||
var objectTypes = Object.keys(currentObjects)
|
/**
|
||||||
if(typeof objType == 'string' && objType != "") {
|
* Renames an object from its old name to the new one.
|
||||||
if(objType == "ExecutableObject") {
|
* @param {string} oldName - Current name of the object.
|
||||||
objectTypes = getExecutableTypes()
|
* @param {string} newName - Name to rename the object to.
|
||||||
} else if(currentObjects[objType] != undefined) {
|
*/
|
||||||
objectTypes = [objType]
|
let obj = currentObjectsByName[oldName]
|
||||||
|
delete currentObjectsByName[oldName]
|
||||||
|
currentObjectsByName[newName] = obj
|
||||||
|
obj.name = newName
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(Array.isArray(objType)) objectTypes = objType
|
function deleteObject(objName) {
|
||||||
var retObj = null
|
/**
|
||||||
if(objName != "" && objName != null) {
|
* Deletes an object by its given name.
|
||||||
objectTypes.forEach(function(objType){
|
* @param {string} objName - Current name of the object.
|
||||||
if(currentObjects[objType] == undefined) return null
|
*/
|
||||||
currentObjects[objType].forEach(function(obj){
|
let obj = currentObjectsByName[objName]
|
||||||
if(obj.name == objName) retObj = obj
|
delete currentObjectsByName[objName]
|
||||||
})
|
currentObjects[obj.type].splice(currentObjects[obj.type].indexOf(obj),1)
|
||||||
})
|
obj.delete()
|
||||||
}
|
|
||||||
return retObj
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjectsName(objType) {
|
function getObjectsName(objType) {
|
||||||
|
/**
|
||||||
|
* Gets a list of all names of a certain object type.
|
||||||
|
* @param {string} objType - Type of the object to query. Can be ExecutableObject for all ExecutableObjects.
|
||||||
|
* @return {array} List of names of the objects.
|
||||||
|
*/
|
||||||
if(objType == "ExecutableObject") {
|
if(objType == "ExecutableObject") {
|
||||||
var types = getExecutableTypes()
|
var types = getExecutableTypes()
|
||||||
var elementNames = ['']
|
var elementNames = ['']
|
||||||
|
@ -62,15 +70,26 @@ function getObjectsName(objType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExecutableTypes() {
|
function getExecutableTypes() {
|
||||||
|
/**
|
||||||
|
* Returns a list of all object types which are executable objects.
|
||||||
|
* @return {array} List of all object types which are executable objects.
|
||||||
|
*/
|
||||||
return Object.keys(currentObjects).filter(objType => types[objType].executable())
|
return Object.keys(currentObjects).filter(objType => types[objType].executable())
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewRegisteredObject(objType, args=[]) {
|
function createNewRegisteredObject(objType, args=[]) {
|
||||||
|
/**
|
||||||
|
* Creates and register an object in the database.
|
||||||
|
* @param {string} objType - Type of the object to create.
|
||||||
|
* @param {string} args - List of arguments for the objects (can be empty).
|
||||||
|
* @return {[objType]} Newly created object.
|
||||||
|
*/
|
||||||
if(Object.keys(types).indexOf(objType) == -1) return null // Object type does not exist.
|
if(Object.keys(types).indexOf(objType) == -1) return null // Object type does not exist.
|
||||||
var newobj = new types[objType](...args)
|
var newobj = new types[objType](...args)
|
||||||
if(Object.keys(currentObjects).indexOf(objType) == -1) {
|
if(Object.keys(currentObjects).indexOf(objType) == -1) {
|
||||||
currentObjects[objType] = []
|
currentObjects[objType] = []
|
||||||
}
|
}
|
||||||
currentObjects[objType].push(newobj)
|
currentObjects[objType].push(newobj)
|
||||||
|
currentObjectsByName[newobj.name] = newobj
|
||||||
return newobj
|
return newobj
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
.import "../utils.js" as Utils
|
.import "../utils.js" as Utils
|
||||||
.import "../objects.js" as Objects
|
.import "../objects.js" as Objects
|
||||||
.import "../math/latex.js" as Latex
|
.import "../math/latex.js" as Latex
|
||||||
|
.import "../parameters.js" as P
|
||||||
|
.import "../math/common.js" as C
|
||||||
|
|
||||||
// This file contains the default data to be imported from all other objects
|
// This file contains the default data to be imported from all other objects
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ function getNewName(allowedLetters) {
|
||||||
var num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length)
|
var num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length)
|
||||||
ret = letter + (num > 0 ? Utils.textsub(num-1) : '')
|
ret = letter + (num > 0 ? Utils.textsub(num-1) : '')
|
||||||
newid += 1
|
newid += 1
|
||||||
} while(Objects.getObjectByName(ret) != null)
|
} while(ret in Objects.currentObjectsByName)
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ class DrawableObject {
|
||||||
this.color = color
|
this.color = color
|
||||||
this.labelContent = labelContent // "null", "name", "name + value"
|
this.labelContent = labelContent // "null", "name", "name + value"
|
||||||
this.requiredBy = []
|
this.requiredBy = []
|
||||||
|
this.requires = []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,18 +190,40 @@ class DrawableObject {
|
||||||
* Callback method when one of the properties of the object is updated.
|
* Callback method when one of the properties of the object is updated.
|
||||||
*/
|
*/
|
||||||
update() {
|
update() {
|
||||||
for(var req of this.requiredBy) {
|
// Refreshing dependencies.
|
||||||
req.update()
|
for(let obj of this.requires)
|
||||||
|
obj.requiredBy = obj.requiredBy.filter(dep => dep != this)
|
||||||
|
// Checking objects this one depends on
|
||||||
|
this.requires = []
|
||||||
|
let properties = this.constructor.properties()
|
||||||
|
for(let property in properties)
|
||||||
|
if(properties[property] == 'Expression' && this[property] != null) {
|
||||||
|
// Expressions with dependencies
|
||||||
|
for(let objName of this[property].requiredObjects()) {
|
||||||
|
this.requires.push(C.currentObjectsByName[objName])
|
||||||
|
C.currentObjectsByName[objName].requiredBy.push(this)
|
||||||
}
|
}
|
||||||
|
if(this[property].cached && this[property].requiredObjects().length > 0)
|
||||||
|
// Recalculate
|
||||||
|
this[property].recache()
|
||||||
|
|
||||||
|
} else if(typeof properties[property] == 'object' && 'type' in properties[property] && properties[property] == 'ObjectType' && this[property] != null) {
|
||||||
|
// Object dependency
|
||||||
|
this.requires.push(this[property])
|
||||||
|
this[property].requiredBy.push(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating objects dependent on this one
|
||||||
|
for(let req of this.requiredBy)
|
||||||
|
req.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback method when the object is about to get deleted.
|
* Callback method when the object is about to get deleted.
|
||||||
*/
|
*/
|
||||||
delete() {
|
delete() {
|
||||||
for(var toRemove of this.requiredBy) {
|
for(let toRemove of this.requiredBy) {
|
||||||
toRemove.delete()
|
Objects.deleteObject(toRemove.name)
|
||||||
Objects.currentObjects[toRemove.type] = Objects.currentObjects[toRemove.type].filter(obj => obj.name != toRemove.name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +286,7 @@ class DrawableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automaticly draw text (by default the label of the object on the \c canvas with
|
* Automatically draw text (by default the label of the object on the \c canvas with
|
||||||
* the 2D context \c ctx depending on user settings.
|
* the 2D context \c ctx depending on user settings.
|
||||||
* This method takes into account both the \c posX and \c posY of where the label
|
* This method takes into account both the \c posX and \c posY of where the label
|
||||||
* should be displayed, including the \c labelPosition relative to it.
|
* should be displayed, including the \c labelPosition relative to it.
|
||||||
|
|
|
@ -49,7 +49,7 @@ class GainBode extends Common.ExecutableObject {
|
||||||
this.type = 'Gain Bode'
|
this.type = 'Gain Bode'
|
||||||
if(typeof om_0 == "string") {
|
if(typeof om_0 == "string") {
|
||||||
// Point name or create one
|
// Point name or create one
|
||||||
om_0 = Objects.getObjectByName(om_0, 'Point')
|
om_0 = Objects.currentObjectsByName[om_0]
|
||||||
if(om_0 == null) {
|
if(om_0 == null) {
|
||||||
// Create new point
|
// Create new point
|
||||||
om_0 = Objects.createNewRegisteredObject('Point')
|
om_0 = Objects.createNewRegisteredObject('Point')
|
||||||
|
|
|
@ -48,7 +48,7 @@ class PhaseBode extends Common.ExecutableObject {
|
||||||
this.phase = phase
|
this.phase = phase
|
||||||
if(typeof om_0 == "string") {
|
if(typeof om_0 == "string") {
|
||||||
// Point name or create one
|
// Point name or create one
|
||||||
om_0 = Objects.getObjectByName(om_0, 'Point')
|
om_0 = Objects.currentObjectsByName[om_0]
|
||||||
if(om_0 == null) {
|
if(om_0 == null) {
|
||||||
// Create new point
|
// Create new point
|
||||||
om_0 = Objects.createNewRegisteredObject('Point')
|
om_0 = Objects.createNewRegisteredObject('Point')
|
||||||
|
|
|
@ -27,14 +27,6 @@ class RepartitionFunction extends Common.ExecutableObject {
|
||||||
static type(){return 'Repartition'}
|
static type(){return 'Repartition'}
|
||||||
static displayType(){return qsTr('Repartition')}
|
static displayType(){return qsTr('Repartition')}
|
||||||
static displayTypeMultiple(){return qsTr('Repartition functions')}
|
static displayTypeMultiple(){return qsTr('Repartition functions')}
|
||||||
/*static properties() {return {
|
|
||||||
'beginIncluded': 'boolean',
|
|
||||||
'drawLineEnds': 'boolean',
|
|
||||||
'comment1': 'Note: Specify the properties for each potential result.',
|
|
||||||
'probabilities': new P.Dictionary('string', 'float', /^-?[\d.,]+$/, /^-?[\d\.,]+$/, 'P({name} = ', ') = '),
|
|
||||||
'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'),
|
|
||||||
'labelX': 'number'
|
|
||||||
}}*/
|
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
||||||
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
||||||
|
|
|
@ -30,10 +30,6 @@ class SommePhasesBode extends Common.ExecutableObject {
|
||||||
static displayType(){return qsTr('Bode Phases Sum')}
|
static displayType(){return qsTr('Bode Phases Sum')}
|
||||||
static displayTypeMultiple(){return qsTr('Bode Phases Sum')}
|
static displayTypeMultiple(){return qsTr('Bode Phases Sum')}
|
||||||
static createable() {return false}
|
static createable() {return false}
|
||||||
/*static properties() {return {
|
|
||||||
'labelPosition': new P.Enum('above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'),
|
|
||||||
'labelX': 'number'
|
|
||||||
}}*/
|
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
||||||
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
||||||
|
|
|
@ -29,12 +29,6 @@ class Text extends Common.DrawableObject {
|
||||||
static type(){return 'Text'}
|
static type(){return 'Text'}
|
||||||
static displayType(){return qsTr('Text')}
|
static displayType(){return qsTr('Text')}
|
||||||
static displayTypeMultiple(){return qsTr('Texts')}
|
static displayTypeMultiple(){return qsTr('Texts')}
|
||||||
/*static properties() {return {
|
|
||||||
'x': 'Expression',
|
|
||||||
'y': 'Expression',
|
|
||||||
'labelPosition': new P.Enum('center', 'above', 'below', 'left', 'right', 'above-left', 'above-right', 'below-left', 'below-right'),
|
|
||||||
'text': 'string',
|
|
||||||
}}*/
|
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
|
||||||
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression',
|
||||||
|
|
|
@ -56,7 +56,7 @@ class XCursor extends Common.DrawableObject {
|
||||||
this.x = x
|
this.x = x
|
||||||
this.targetElement = targetElement
|
this.targetElement = targetElement
|
||||||
if(typeof targetElement == "string") {
|
if(typeof targetElement == "string") {
|
||||||
this.targetElement = Objects.getObjectByName(targetElement, elementTypes)
|
this.targetElement = Objects.currentObjectsByName[targetElement]
|
||||||
}
|
}
|
||||||
this.labelPosition = labelPosition
|
this.labelPosition = labelPosition
|
||||||
this.displayStyle = displayStyle
|
this.displayStyle = displayStyle
|
||||||
|
|
|
@ -129,11 +129,11 @@ function simplifyExpression(str) {
|
||||||
var replacements = [
|
var replacements = [
|
||||||
// Operations not done by parser.
|
// Operations not done by parser.
|
||||||
[// Decomposition way 2
|
[// Decomposition way 2
|
||||||
/(^.?|[+-] |\()([-.\d\w]+) ([*/]) \((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\)(.?$| [+-]|\))/g,
|
/(^|[+-] |\()([-.\d\w]+) ([*/]) \((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\)($| [+-]|\))/g,
|
||||||
"$1$2 $3 $4 $6 $2 $3 $7$9"
|
"$1$2 $3 $4 $6 $2 $3 $7$9"
|
||||||
],
|
],
|
||||||
[ // Decomposition way 2
|
[ // Decomposition way 2
|
||||||
/(^.?|[+-] |\()\((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\) ([*/]) ([-.\d\w]+)(.?$| [+-]|\))/g,
|
/(^|[+-] |\()\((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\) ([*/]) ([-.\d\w]+)($| [+-]|\))/g,
|
||||||
"$1$2 $7 $8 $4 $5 $7 $8$9"
|
"$1$2 $7 $8 $4 $5 $7 $8$9"
|
||||||
],
|
],
|
||||||
[ // Factorisation of π elements.
|
[ // Factorisation of π elements.
|
||||||
|
@ -159,19 +159,19 @@ function simplifyExpression(str) {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[ // Removing parenthesis when content is only added from both sides.
|
[ // Removing parenthesis when content is only added from both sides.
|
||||||
/(^.?|[+-] |\()\(([^)(]+)\)(.?$| [+-]|\))/g,
|
/(^|[+-] |\()\(([^)(]+)\)($| [+-]|\))/g,
|
||||||
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
||||||
],
|
],
|
||||||
[ // Removing parenthesis when content is only multiplied.
|
[ // Removing parenthesis when content is only multiplied.
|
||||||
/(^.?|[*\/] |\()\(([^)(+-]+)\)(.?$| [*\/+-]|\))/g,
|
/(^|[*\/] |\()\(([^)(+-]+)\)($| [*\/+-]|\))/g,
|
||||||
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
||||||
],
|
],
|
||||||
[ // Removing parenthesis when content is only multiplied.
|
[ // Removing parenthesis when content is only multiplied.
|
||||||
/(^.?|[*\/-+] |\()\(([^)(+-]+)\)(.?$| [*\/]|\))/g,
|
/(^|[*\/-+] |\()\(([^)(+-]+)\)($| [*\/]|\))/g,
|
||||||
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
|
||||||
],
|
],
|
||||||
[// Simplification additions/substractions.
|
[// Simplification additions/substractions.
|
||||||
/(^.?|[^*\/] |\()([-.\d]+) (\+|\-) (\([^)(]+\)|[^)(]+) (\+|\-) ([-.\d]+)(.?$| [^*\/]|\))/g,
|
/(^|[^*\/] |\()([-.\d]+) (\+|\-) (\([^)(]+\)|[^)(]+) (\+|\-) ([-.\d]+)($| [^*\/]|\))/g,
|
||||||
function(match, b4, n1, op1, middle, op2, n2, after) {
|
function(match, b4, n1, op1, middle, op2, n2, after) {
|
||||||
var total
|
var total
|
||||||
if(op2 == '+') {
|
if(op2 == '+') {
|
||||||
|
@ -258,7 +258,7 @@ function makeExpressionReadable(str) {
|
||||||
[/\[([^\[\]]+)\]/g, function(match, p1) { return textsub(p1) }],
|
[/\[([^\[\]]+)\]/g, function(match, p1) { return textsub(p1) }],
|
||||||
[/(\d|\))×/g, '$1'],
|
[/(\d|\))×/g, '$1'],
|
||||||
//[/×(\d|\()/g, '$1'],
|
//[/×(\d|\()/g, '$1'],
|
||||||
[/\(([^)(+.\/-]+)\)/g, "$1"],
|
[/[^a-z]\(([^)(+.\/-]+)\)/g, "$1"],
|
||||||
[/integral\((.+),\s?(.+),\s?("|')(.+)("|'),\s?("|')(.+)("|')\)/g, function(match, a, b, p1, body, p2, p3, by, p4) {
|
[/integral\((.+),\s?(.+),\s?("|')(.+)("|'),\s?("|')(.+)("|')\)/g, function(match, a, b, p1, body, p2, p3, by, p4) {
|
||||||
if(a.length < b.length) {
|
if(a.length < b.length) {
|
||||||
return `∫${textsub(a)}${textsup(b)} ${body} d${by}`
|
return `∫${textsub(a)}${textsup(b)} ${body} d${by}`
|
||||||
|
|
|
@ -149,6 +149,7 @@ class Helper(QObject):
|
||||||
@Slot()
|
@Slot()
|
||||||
def fetchChangelog(self):
|
def fetchChangelog(self):
|
||||||
changelog_cache_path = path.join(path.dirname(path.realpath(__file__)), "CHANGELOG.md")
|
changelog_cache_path = path.join(path.dirname(path.realpath(__file__)), "CHANGELOG.md")
|
||||||
|
print(changelog_cache_path)
|
||||||
if path.exists(changelog_cache_path):
|
if path.exists(changelog_cache_path):
|
||||||
# We have a cached version of the changelog, for env that don't have access to the internet.
|
# We have a cached version of the changelog, for env that don't have access to the internet.
|
||||||
f = open(changelog_cache_path);
|
f = open(changelog_cache_path);
|
||||||
|
|
Loading…
Reference in a new issue