Compare commits

..

No commits in common. "1a433eba27f3105023bbae139a0cd240aa94e21a" and "3dc69cc9ba44e2251426b9d5e53b79302d2f0f5f" have entirely different histories.

21 changed files with 99 additions and 178 deletions

View file

@ -249,24 +249,18 @@ ApplicationWindow {
// Importing objects // Importing objects
Objects.currentObjects = {} Objects.currentObjects = {}
Objects.currentObjectsByName = {} for(var objType in data['objects']) {
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(let objData of data['objects'][objType]) { for(var objData of data['objects'][objType]) {
let obj = new Objects.types[objType](...objData) var 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"])

View file

@ -74,39 +74,29 @@ 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) {
let newName = Utils.parseName(newValue) var newName = Utils.parseName(newValue)
if(newName != '' && objEditor.obj.name != newName) { if(newName != '' && objEditor.obj.name != newName) {
if(newName in Objects.currentObjectsByName) { if(Objects.getObjectByName(newName) != null) {
invalidNameDialog.showDialog(newName) newName = ObjectsCommons.getNewName(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.renameObject(obj.name, newName) Objects.currentObjects[objEditor.objType][objEditor.objIndex].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
@ -223,7 +213,7 @@ D.Dialog {
[]) : []) :
modelData[1].values) modelData[1].values)
: [] : []
// Translated version of the model. // Translated verison 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]])
@ -232,7 +222,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.currentObjectsByName[baseModel[newIndex]] var selectedObj = Objects.getObjectByName(baseModel[newIndex], modelData[1].objType)
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) {

View file

@ -193,7 +193,8 @@ ScrollView {
history.addToHistory(new HistoryLib.DeleteObject( history.addToHistory(new HistoryLib.DeleteObject(
obj.name, objType, obj.export() obj.name, objType, obj.export()
)) ))
Objects.deleteObject(obj.name) Objects.currentObjects[objType][index].delete()
Objects.currentObjects[objType].splice(index, 1)
objectListList.update() objectListList.update()
} }
} }

View file

@ -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.currentObjectsByName[objName] // getObjectByName(objName, objType) let obj = Objects.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.currentObjectsByName[objName] // Objects.getObjectByName(objName, objType) let obj = 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
)) ))

View file

@ -194,7 +194,6 @@ 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)) {
@ -220,11 +219,8 @@ 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 + ' cannot be executed'); throw new Error(f + ' is not a function');
} }
} 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

View file

@ -36,11 +36,9 @@ class CreateNewObject extends C.Action {
undo() { undo() {
Objects.deleteObject(this.targetName) var targetIndex = Objects.getObjectsName(this.targetType).indexOf(this.targetName)
//let targetIndex = Objects.getObjectsName(this.targetType).indexOf(this.targetName) Objects.currentObjects[this.targetType][targetIndex].delete()
//delete Objects.currentObjectsByName[this.targetName] Objects.currentObjects[this.targetType].splice(targetIndex, 1)
//Objects.currentObjects[this.targetType][targetIndex].delete()
//Objects.currentObjects[this.targetType].splice(targetIndex, 1)
} }
redo() { redo() {

View file

@ -49,21 +49,19 @@ class EditedProperty extends C.Action {
this.newValue = MathLib.parseDomain(this.newValue); this.newValue = MathLib.parseDomain(this.newValue);
} else { } else {
// Objects // Objects
this.previousValue = Objects.currentObjectsByName[this.previousValue] // Objects.getObjectByName(this.previousValue); this.previousValue = Objects.getObjectByName(this.previousValue);
this.newValue = Objects.currentObjectsByName[this.newValue] // Objects.getObjectByName(this.newValue); this.newValue = Objects.getObjectByName(this.newValue);
} }
} }
this.setReadableValues() this.setReadableValues()
} }
undo() { undo() {
Objects.currentObjectsByName[this.targetName][this.targetProperty] = this.previousValue Objects.getObjectByName(this.targetName, this.targetType)[this.targetProperty] = this.previousValue
Objects.currentObjectsByName[this.targetName].update()
} }
redo() { redo() {
Objects.currentObjectsByName[this.targetName][this.targetProperty] = this.newValue Objects.getObjectByName(this.targetName, this.targetType)[this.targetProperty] = this.newValue
Objects.currentObjectsByName[this.targetName].update()
} }
export() { export() {

View file

@ -40,15 +40,11 @@ class NameChanged extends EP.EditedProperty {
} }
undo() { undo() {
Objects.renameObject(this.newValue, this.previousValue) Objects.getObjectByName(this.newValue, this.targetType)['name'] = this.previousValue
} }
redo() { redo() {
Objects.renameObject(this.previousValue, this.newValue) Objects.getObjectByName(this.previousValue, this.targetType)['name'] = this.newValue
//let obj = Objects.currentObjectsByName[this.previousValue]
//obj.name = this.newValue
//Objects.currentObjectsByName[this.newValue] = obj
//delete Objects.currentObjectsByName[this.previousValue]
} }
getReadableString() { getReadableString() {

View file

@ -22,9 +22,7 @@
.import "../utils.js" as Utils .import "../utils.js" as Utils
.import "latex.js" as Latex .import "latex.js" as Latex
const DERIVATION_PRECISION = 0.1 var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manualy
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,
@ -35,21 +33,18 @@ 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
} }

View file

@ -30,42 +30,23 @@ 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.allRequirementsFullfilled() ? this.calc.evaluate(C.currentObjectsByName) : null this.cachedValue = this.cached ? this.calc.evaluate(C.evalVariables) : null
this.latexMarkup = Latex.expression(this.calc.tokens) this.latexMarkup = Latex.expression(this.calc.tokens)
} }
isConstant() { isConstant() {
let vars = this.calc.variables() return !this.expr.includes("x") && !this.expr.includes("n")
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) { if(this.cached) return this.cachedValue
if(this.cachedValue == null) C.currentVars = Object.assign({'x': x}, C.evalVariables)
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() == 0) return '0' if(expr.evaluate(C.evalVariables) == 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) {
@ -85,7 +66,7 @@ class Expression {
} }
toString(forceSign=false) { toString(forceSign=false) {
let str = Utils.makeExpressionReadable(this.calc.toString()) var str = Utils.makeExpressionReadable(this.calc.toString())
if(str[0] != '-' && forceSign) str = '+' + str if(str[0] != '-' && forceSign) str = '+' + str
return str return str
} }

View file

@ -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() this.calcValues[n] = parsed.evaluate(C.evalVariables)
} }
this.valuePlus = parseInt(valuePlus) this.valuePlus = parseInt(valuePlus)
} }
@ -65,10 +65,9 @@ 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()
C.currentVars = Object.assign( var l = {'n': n-this.valuePlus} // Just in case, add n (for custom functions)
{'n': n-this.valuePlus, [this.name]: this.calcValues}, // Just in case, add n (for custom functions) l[this.name] = this.calcValues
C.currentObjectsByName C.currentVars = Object.assign(l, C.evalVariables)
)
this.calcValues[n] = expr.evaluate(C.currentVars) this.calcValues[n] = expr.evaluate(C.currentVars)
} }

View file

@ -19,44 +19,36 @@
.pragma library .pragma library
.import "utils.js" as Utils .import "utils.js" as Utils
.import "math/common.js" as MathCommons .import "mathlib.js" as MathLib
.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 renameObject(oldName, newName) { function getObjectByName(objName, objType = null) {
/** var objectTypes = Object.keys(currentObjects)
* Renames an object from its old name to the new one. if(typeof objType == 'string' && objType != "") {
* @param {string} oldName - Current name of the object. if(objType == "ExecutableObject") {
* @param {string} newName - Name to rename the object to. objectTypes = getExecutableTypes()
*/ } else if(currentObjects[objType] != undefined) {
let obj = currentObjectsByName[oldName] objectTypes = [objType]
delete currentObjectsByName[oldName]
currentObjectsByName[newName] = obj
obj.name = newName
} }
}
function deleteObject(objName) { if(Array.isArray(objType)) objectTypes = objType
/** var retObj = null
* Deletes an object by its given name. if(objName != "" && objName != null) {
* @param {string} objName - Current name of the object. objectTypes.forEach(function(objType){
*/ if(currentObjects[objType] == undefined) return null
let obj = currentObjectsByName[objName] currentObjects[objType].forEach(function(obj){
delete currentObjectsByName[objName] if(obj.name == objName) retObj = obj
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 = ['']
@ -70,26 +62,15 @@ 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
} }

View file

@ -21,8 +21,6 @@
.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
@ -42,7 +40,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(ret in Objects.currentObjectsByName) } while(Objects.getObjectByName(ret) != null)
return ret return ret
} }
@ -118,7 +116,6 @@ 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 = []
} }
/** /**
@ -190,40 +187,18 @@ 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() {
// Refreshing dependencies. for(var req of this.requiredBy) {
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() 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(let toRemove of this.requiredBy) { for(var toRemove of this.requiredBy) {
Objects.deleteObject(toRemove.name) toRemove.delete()
Objects.currentObjects[toRemove.type] = Objects.currentObjects[toRemove.type].filter(obj => obj.name != toRemove.name)
} }
} }
@ -286,7 +261,7 @@ class DrawableObject {
} }
/** /**
* Automatically draw text (by default the label of the object on the \c canvas with * Automaticly 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.

View file

@ -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.currentObjectsByName[om_0] om_0 = Objects.getObjectByName(om_0, 'Point')
if(om_0 == null) { if(om_0 == null) {
// Create new point // Create new point
om_0 = Objects.createNewRegisteredObject('Point') om_0 = Objects.createNewRegisteredObject('Point')

View file

@ -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.currentObjectsByName[om_0] om_0 = Objects.getObjectByName(om_0, 'Point')
if(om_0 == null) { if(om_0 == null) {
// Create new point // Create new point
om_0 = Objects.createNewRegisteredObject('Point') om_0 = Objects.createNewRegisteredObject('Point')

View file

@ -27,6 +27,14 @@ 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',

View file

@ -30,6 +30,10 @@ 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',

View file

@ -29,6 +29,12 @@ 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',

View file

@ -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.currentObjectsByName[targetElement] this.targetElement = Objects.getObjectByName(targetElement, elementTypes)
} }
this.labelPosition = labelPosition this.labelPosition = labelPosition
this.displayStyle = displayStyle this.displayStyle = displayStyle

View file

@ -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'],
[/[^a-z]\(([^)(+.\/-]+)\)/g, "$1"], [/\(([^)(+.\/-]+)\)/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}`

View file

@ -149,7 +149,6 @@ 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);