Started CursorX & Executableobjects,
This commit is contained in:
parent
b8431749a3
commit
487daa426a
5 changed files with 167 additions and 41 deletions
|
@ -35,6 +35,8 @@ Canvas {
|
|||
property double yaxisstep: 3
|
||||
property string xlabel: ""
|
||||
property string ylabel: ""
|
||||
property int maxgradx: 8
|
||||
property int maxgrady: 1000
|
||||
|
||||
onPaint: {
|
||||
//console.log('Redrawing')
|
||||
|
@ -99,12 +101,12 @@ Canvas {
|
|||
// Axis graduation labels
|
||||
ctx.font = "14px sans-serif"
|
||||
|
||||
for(var xpow = -10; xpow <= 10; xpow+=1) {
|
||||
for(var xpow = -maxgradx; xpow <= maxgradx; xpow+=1) {
|
||||
var textSize = ctx.measureText("10"+Utils.textsup(xpow)).width
|
||||
if(xpow != 0)
|
||||
drawVisibleText(ctx, "10"+Utils.textsup(xpow), x2px(Math.pow(10,xpow))-textSize/2, axisxpx+12+(6*(y==0)))
|
||||
}
|
||||
for(var y = -Math.round(100/yaxisstep)*yaxisstep; y < canvas.ymax; y+=yaxisstep) {
|
||||
for(var y = -Math.round(maxgrady/yaxisstep)*yaxisstep; y < canvas.ymax; y+=yaxisstep) {
|
||||
var textSize = ctx.measureText(y).width
|
||||
drawVisibleText(ctx, y, axisypx-3-textSize, y2px(y)+6+(6*(y==0)))
|
||||
}
|
||||
|
|
|
@ -84,7 +84,6 @@ ListView {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
console.log('Showing', objType, index, Objects.currentObjects[objType])
|
||||
objEditor.obj = Objects.currentObjects[objType][index]
|
||||
objEditor.objType = objType
|
||||
objEditor.objIndex = index
|
||||
|
@ -278,7 +277,6 @@ ListView {
|
|||
text: modelData
|
||||
width: createRow.width
|
||||
visible: Objects.types[modelData].createable()
|
||||
Component.onCompleted: console.log(modelData, visible, Objects)//, Objects.type[modelData])
|
||||
height: visible ? implicitHeight : 0
|
||||
icon.source: './icons/'+modelData+'.svg' // Default to dark version
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ class Expression {
|
|||
return this.expr.indexOf("x") == -1
|
||||
}
|
||||
|
||||
evaluate(x = 0) {
|
||||
execute(x = 1) {
|
||||
return this.calc.evaluate({
|
||||
"x": x,
|
||||
"pi": Math.PI,
|
||||
|
@ -45,6 +45,10 @@ class Expression {
|
|||
})
|
||||
}
|
||||
|
||||
simplify(x = 1) {
|
||||
return Utils.makeExpressionReadable(this.calc.substitute('x', x).simplify().toString())
|
||||
}
|
||||
|
||||
toEditableString() {
|
||||
return this.calc.toString()
|
||||
}
|
||||
|
@ -83,8 +87,8 @@ class Domain {
|
|||
}
|
||||
|
||||
includes(x) {
|
||||
return ((this.openBegin && x > this.begin.evaluate()) || (!this.openBegin && x >= this.begin.evaluate())) &&
|
||||
((this.openEnd && x < this.end.evaluate()) || (!this.openEnd && x <= this.end.evaluate()))
|
||||
return ((this.openBegin && x > this.begin.execute()) || (!this.openBegin && x >= this.begin.execute())) &&
|
||||
((this.openEnd && x < this.end.execute()) || (!this.openEnd && x <= this.end.execute()))
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
@ -158,10 +162,10 @@ class DomainSet {
|
|||
}
|
||||
|
||||
includes(x) {
|
||||
var xcomputed = new Expression(x.toString()).evaluate()
|
||||
var xcomputed = new Expression(x.toString()).execute()
|
||||
var found = false
|
||||
this.values.forEach(function(value){
|
||||
if(xcomputed == value.evaluate()) {
|
||||
if(xcomputed == value.execute()) {
|
||||
found = true
|
||||
return
|
||||
}
|
||||
|
|
|
@ -32,13 +32,22 @@ function getNewName(allowedLetters, category) {
|
|||
}
|
||||
|
||||
class DrawableObject {
|
||||
// Class to extend for every type of object that
|
||||
// can be drawn on the canvas.
|
||||
static type(){return 'Unknown'}
|
||||
// Label used for the list on the ObjectsList sidebar.
|
||||
static typeMultiple(){return 'Unknown'}
|
||||
// Whether this object can be created by the user
|
||||
// or are instanciated by other objects.
|
||||
static createable() {return true}
|
||||
// Properties are set with key as property name and
|
||||
// value as it's type name (e.g 'Expression', 'string',
|
||||
// 'Point'...) or an array with possibilities for enums.
|
||||
// Used for property modifier in the sidebar.
|
||||
static properties() {return {}}
|
||||
|
||||
constructor(name, visible = true, color = null, labelContent = 'name + value') {
|
||||
if(color == null) color = this.getRandomColor()
|
||||
if(color == null) color = Utils.getRandomColor()
|
||||
this.type = 'Unknown'
|
||||
this.name = name
|
||||
this.visible = visible
|
||||
|
@ -47,15 +56,6 @@ class DrawableObject {
|
|||
this.requiredBy = []
|
||||
}
|
||||
|
||||
getRandomColor() {
|
||||
var x = '0123456789ABCDEF'; // Removing for less flashy colors.
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += x[Math.floor(Math.random() * (16-6*(i%2==0)))];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
getReadableString() {
|
||||
return `${this.name} = Unknown`
|
||||
}
|
||||
|
@ -81,6 +81,18 @@ class DrawableObject {
|
|||
draw(canvas, ctx) {}
|
||||
}
|
||||
|
||||
class ExecutableObject extends DrawableObject {
|
||||
// Class to be extended for every class upon which we
|
||||
// calculate an y for a x with the execute function.
|
||||
// If a value cannot be found during execute, it should
|
||||
// return null. However, theses values should
|
||||
// return false when passed to canExecute.
|
||||
execute(x = 1) {return 0}
|
||||
canExecute(x = 1) {return true}
|
||||
// Simplify returns the simplified string of the expression.
|
||||
simplify(x = 1) {return '0'}
|
||||
}
|
||||
|
||||
class Point extends DrawableObject {
|
||||
static type(){return 'Point'}
|
||||
static typeMultiple(){return 'Points'}
|
||||
|
@ -113,7 +125,7 @@ class Point extends DrawableObject {
|
|||
}
|
||||
|
||||
draw(canvas, ctx) {
|
||||
var [canvasX, canvasY] = [canvas.x2px(this.x.evaluate()), canvas.y2px(this.y.evaluate())]
|
||||
var [canvasX, canvasY] = [canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())]
|
||||
var pointSize = 8
|
||||
switch(this.pointStyle) {
|
||||
case 'dot':
|
||||
|
@ -153,14 +165,13 @@ class Point extends DrawableObject {
|
|||
update() {
|
||||
if(currentObjects['Somme gains Bode'] != undefined && currentObjects['Gain Bode'] != undefined) {
|
||||
for(var i = 0; i < currentObjects['Gain Bode'].length; i++) {
|
||||
console.log(currentObjects['Gain Bode'][i].ω_0.name)
|
||||
if(currentObjects['Gain Bode'][i].ω_0.name == this.name) currentObjects['Gain Bode'][i].update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Function extends DrawableObject {
|
||||
class Function extends ExecutableObject {
|
||||
static type(){return 'Function'}
|
||||
static typeMultiple(){return 'Functions'}
|
||||
static properties() {return {
|
||||
|
@ -201,6 +212,22 @@ class Function extends DrawableObject {
|
|||
this.displayMode, this.labelPos, this.labelX]
|
||||
}
|
||||
|
||||
execute(x = 1) {
|
||||
if(this.inDomain.includes(x))
|
||||
return this.expr.execute(x)
|
||||
return null
|
||||
}
|
||||
|
||||
canExecute(x = 1) {
|
||||
return this.inDomain.includes(x)
|
||||
}
|
||||
|
||||
simplify(x = 1) {
|
||||
if(this.inDomain.includes(x))
|
||||
return this.expr.simplify(x)
|
||||
return ''
|
||||
}
|
||||
|
||||
draw(canvas, ctx) {
|
||||
Function.drawFunction(canvas, ctx, this.expression, this.inDomain, this.outDomain)
|
||||
// Label
|
||||
|
@ -208,7 +235,7 @@ class Function extends DrawableObject {
|
|||
ctx.font = "14px sans-serif"
|
||||
var textSize = canvas.measureText(ctx, text)
|
||||
var posX = canvas.x2px(this.labelX)
|
||||
var posY = canvas.y2px(this.expression.evaluate(this.labelX))
|
||||
var posY = canvas.y2px(this.expression.execute(this.labelX))
|
||||
switch(this.labelPos) {
|
||||
case 'above':
|
||||
canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height)
|
||||
|
@ -225,10 +252,10 @@ class Function extends DrawableObject {
|
|||
// Drawing small traits every 2px
|
||||
var pxprecision = 2
|
||||
var previousX = canvas.px2x(0)
|
||||
var previousY = expr.evaluate(previousX)
|
||||
var previousY = expr.execute(previousX)
|
||||
for(var px = pxprecision; px < canvas.canvasSize.width; px += pxprecision) {
|
||||
var currentX = canvas.px2x(px)
|
||||
var currentY = expr.evaluate(currentX)
|
||||
var currentY = expr.execute(currentX)
|
||||
if((inDomain.includes(currentX) || inDomain.includes(previousX)) &&
|
||||
(outDomain.includes(currentY) || outDomain.includes(previousY)) &&
|
||||
Math.abs(previousY-currentY)<100) { // 100 per 2px is a lot (probably inf to inf issue)
|
||||
|
@ -240,7 +267,7 @@ class Function extends DrawableObject {
|
|||
}
|
||||
}
|
||||
|
||||
class GainBode extends DrawableObject {
|
||||
class GainBode extends ExecutableObject {
|
||||
static type(){return 'Gain Bode'}
|
||||
static typeMultiple(){return 'Gains Bode'}
|
||||
static properties() {return {
|
||||
|
@ -263,9 +290,10 @@ class GainBode extends DrawableObject {
|
|||
// Create new point
|
||||
ω_0 = createNewRegisteredObject('Point')
|
||||
ω_0.name = getNewName('ω', 'Gain Bode')
|
||||
ω_0.color = this.color
|
||||
labelPos = 'below'
|
||||
}
|
||||
}
|
||||
console.log(this, ω_0)
|
||||
this.ω_0 = ω_0
|
||||
this.pass = pass
|
||||
if(typeof gain == 'number' || typeof gain == 'string') gain = new MathLib.Expression(gain.toString())
|
||||
|
@ -284,18 +312,31 @@ class GainBode extends DrawableObject {
|
|||
this.ω_0.name, this.pass.toString(), this.gain.toEditableString(), this.labelPos, this.labelX]
|
||||
}
|
||||
|
||||
evaluate(x=1) {
|
||||
execute(x=1) {
|
||||
if((this.pass == 'high' && x < this.ω_0.x) || (this.pass == 'low' && x > this.ω_0.x)) {
|
||||
var dbfn = new MathLib.Expression(`${this.gain.evaluate()}*(ln(x)-ln(${this.ω_0.x}))/ln(10)+${this.ω_0.y}`)
|
||||
return dbfn.evaluate(x)
|
||||
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(ln(x)-ln(${this.ω_0.x}))/ln(10)+${this.ω_0.y}`)
|
||||
return dbfn.execute(x)
|
||||
} else {
|
||||
return this.ω_0.y.evaluate()
|
||||
return this.ω_0.y.execute()
|
||||
}
|
||||
}
|
||||
|
||||
simplify(x = 1) {
|
||||
if((this.pass == 'high' && x < this.ω_0.x) || (this.pass == 'low' && x > this.ω_0.x)) {
|
||||
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(ln(x)-ln(${this.ω_0.x}))/ln(10)+${this.ω_0.y}`)
|
||||
return dbfn.simplify(x)
|
||||
} else {
|
||||
return this.ω_0.y.toString()
|
||||
}
|
||||
}
|
||||
|
||||
canExecute(x = 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
draw(canvas, ctx) {
|
||||
var base = [canvas.x2px(this.ω_0.x), canvas.y2px(this.ω_0.y)]
|
||||
var dbfn = new MathLib.Expression(`${this.gain.evaluate()}*(ln(x)-ln(${this.ω_0.x}))/ln(10)+${this.ω_0.y}`)
|
||||
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(ln(x)-ln(${this.ω_0.x}))/ln(10)+${this.ω_0.y}`)
|
||||
var inDrawDom = new MathLib.EmptySet()
|
||||
|
||||
if(this.pass == 'high') {
|
||||
|
@ -314,7 +355,7 @@ class GainBode extends DrawableObject {
|
|||
ctx.font = "14px sans-serif"
|
||||
var textSize = canvas.measureText(ctx, text)
|
||||
var posX = canvas.x2px(this.labelX)
|
||||
var posY = canvas.y2px(this.evaluate(this.labelX))
|
||||
var posY = canvas.y2px(this.execute(this.labelX))
|
||||
switch(this.labelPos) {
|
||||
case 'above':
|
||||
canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height)
|
||||
|
@ -360,6 +401,30 @@ class SommeGainsBode extends DrawableObject {
|
|||
return `${this.name} = ${getObjectsName('Gain Bode').join(' + ')}`
|
||||
}
|
||||
|
||||
execute(x = 0) {
|
||||
for(var i=0; i<this.cachedParts.length; i++) {
|
||||
var [dbfn, inDrawDom] = this.cachedParts[i]
|
||||
if(inDrawDom.includes(x)) {
|
||||
return dbfn.execute(x)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
canExecute(x = 1) {
|
||||
return true // Should always be true
|
||||
}
|
||||
|
||||
simplify(x = 1) {
|
||||
for(var i=0; i<this.cachedParts.length; i++) {
|
||||
var [dbfn, inDrawDom] = this.cachedParts[i]
|
||||
if(inDrawDom.includes(x)) {
|
||||
return dbfn.simplify(x)
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
recalculateCache() {
|
||||
this.cachedParts = []
|
||||
// Calculating this is fairly resource expansive so it's cached.
|
||||
|
@ -372,13 +437,13 @@ class SommeGainsBode extends DrawableObject {
|
|||
var ω0xGains = {100000: 0} // To draw the last part
|
||||
var ω0xPass = {100000: 'high'} // To draw the last part
|
||||
currentObjects['Gain Bode'].forEach(function(gainObj) { // Sorting by their ω_0 position.
|
||||
if(ω0xGains[gainObj.ω_0.x.evaluate()] == undefined) {
|
||||
ω0xGains[gainObj.ω_0.x.evaluate()] = gainObj.gain.evaluate()
|
||||
ω0xPass[gainObj.ω_0.x.evaluate()] = gainObj.pass == 'high'
|
||||
if(ω0xGains[gainObj.ω_0.x.execute()] == undefined) {
|
||||
ω0xGains[gainObj.ω_0.x.execute()] = gainObj.gain.execute()
|
||||
ω0xPass[gainObj.ω_0.x.execute()] = gainObj.pass == 'high'
|
||||
} else {
|
||||
ω0xGains[gainObj.ω_0.x.evaluate()+0.0001] = gainObj.gain.evaluate()
|
||||
ω0xGains[gainObj.ω_0.x.execute()+0.0001] = gainObj.gain.execute()
|
||||
}
|
||||
baseY += gainObj.evaluate(drawMin)
|
||||
baseY += gainObj.execute(drawMin)
|
||||
})
|
||||
// Sorting the ω_0x
|
||||
var ω0xList = Object.keys(ω0xGains)
|
||||
|
@ -406,7 +471,7 @@ class SommeGainsBode extends DrawableObject {
|
|||
this.cachedParts.push([dbfn, inDrawDom])
|
||||
previousPallier = ω0xList[pallier]
|
||||
gainTotal += gainsAfterP[pallier] - gainsBeforeP[pallier]
|
||||
baseY = dbfn.evaluate(ω0xList[pallier])
|
||||
baseY = dbfn.execute(ω0xList[pallier])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,7 +487,7 @@ class SommeGainsBode extends DrawableObject {
|
|||
ctx.font = "14px sans-serif"
|
||||
var textSize = canvas.measureText(ctx, text)
|
||||
var posX = canvas.x2px(this.labelX)
|
||||
var posY = canvas.y2px(dbfn.evaluate(this.labelX))
|
||||
var posY = canvas.y2px(dbfn.execute(this.labelX))
|
||||
switch(this.labelPos) {
|
||||
case 'above':
|
||||
canvas.drawVisibleText(ctx, text, posX-textSize.width/2, posY-textSize.height)
|
||||
|
@ -437,11 +502,59 @@ class SommeGainsBode extends DrawableObject {
|
|||
}
|
||||
}
|
||||
|
||||
class PhaseBode extends ExecutableObject {
|
||||
|
||||
}
|
||||
|
||||
class CursorX extends DrawableObject {
|
||||
static type(){return 'CursorX'}
|
||||
static typeMultiple(){return 'CursorX'}
|
||||
static properties() {
|
||||
var elementTypes = Object.keys(currentObjects).filter(objType => types[objType].prototype instanceof ExecutableObject)
|
||||
var elementNames = []
|
||||
elementTypes.forEach(function(elemType){
|
||||
elementNames = elementNames.concat(currentObjects[elemType].map(obj => obj.name))
|
||||
})
|
||||
console.log(currentObjects[elementTypes[0]].map(obj => obj.name), elementNames, elementNames[0], elementTypes, Array.isArray(elementNames))
|
||||
return {
|
||||
'x': 'Expression',
|
||||
'element': elementNames,
|
||||
'labelPos': ['left', 'right'],
|
||||
}
|
||||
}
|
||||
|
||||
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
|
||||
x = 1, element = null, labelPos = 'left') {
|
||||
if(name == null) name = getNewName('ABCDEFJKLMNOPQRSTUVW', 'Point')
|
||||
super(name, visible, color, labelContent)
|
||||
this.type = 'CursorX'
|
||||
if(typeof x == 'number' || typeof x == 'string') x = new MathLib.Expression(x.toString())
|
||||
this.getElement()
|
||||
this.labelPost = labelPos
|
||||
}
|
||||
|
||||
update() {
|
||||
if(typeof this.element == 'string') this.getElement()
|
||||
console.log(this.element)
|
||||
}
|
||||
|
||||
getElement(){
|
||||
var element = this.element
|
||||
var elem = null
|
||||
Object.keys(currentObjects).forEach(function(objType){
|
||||
var ele = getObjectByName(objType, element)
|
||||
if(ele != null) elem = ele
|
||||
})
|
||||
this.element = elem
|
||||
}
|
||||
}
|
||||
|
||||
const types = {
|
||||
'Point': Point,
|
||||
'Function': Function,
|
||||
'Gain Bode': GainBode,
|
||||
'Somme gains Bode': SommeGainsBode
|
||||
'Somme gains Bode': SommeGainsBode,
|
||||
'CursorX': CursorX
|
||||
}
|
||||
|
||||
var currentObjects = {}
|
||||
|
|
|
@ -202,3 +202,12 @@ function camelCase2readable(label) {
|
|||
var parsed = parseName(label, false)
|
||||
return parsed.charAt(0).toLatinUppercase() + parsed.slice(1).replace(/([A-Z])/g," $1")
|
||||
}
|
||||
|
||||
function getRandomColor() {
|
||||
var clrs = '0123456789ABCDEF';
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += clrs[Math.floor(Math.random() * (16-6*(i%2==0)))];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue