Started CursorX & Executableobjects,

This commit is contained in:
Adsooi 2020-12-23 00:23:38 +01:00
parent b8431749a3
commit 487daa426a
5 changed files with 167 additions and 41 deletions

View file

@ -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)))
}

View file

@ -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

View file

@ -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
}

View file

@ -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 = {}

View file

@ -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;
}