From c7231d243e900402068d3d0d0d1897eca9e681c1 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 10:05:50 +0200 Subject: [PATCH 1/6] Use full screen for calibration --- apps/calibration/app.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/calibration/app.js b/apps/calibration/app.js index d3823de63..727a4c349 100644 --- a/apps/calibration/app.js +++ b/apps/calibration/app.js @@ -49,7 +49,7 @@ class BanglejsApp { this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32)); this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80)); - g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); + g.clearRect(0, 0, g.getWidth(), g.getHeight()); g.drawLine(this.x, this.y - 5, this.x, this.y + 5); g.drawLine(this.x - 5, this.y, this.x + 5, this.y); g.setFont('Vector', 10); @@ -64,8 +64,6 @@ class BanglejsApp { E.srand(Date.now()); -Bangle.loadWidgets(); -Bangle.drawWidgets(); calibration = new BanglejsApp(); calibration.load_settings(); From 056adb78732427b1d5bdee048bb770401c76e8a8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 10:53:52 +0200 Subject: [PATCH 2/6] Adds scaling to correct for linear mismatches in coordinates --- apps/calibration/app.js | 87 +++++++++++++++++++++++++++++++--------- apps/calibration/boot.js | 6 +-- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/apps/calibration/app.js b/apps/calibration/app.js index 727a4c349..6227b936a 100644 --- a/apps/calibration/app.js +++ b/apps/calibration/app.js @@ -1,26 +1,24 @@ class BanglejsApp { constructor() { + this.updateFactor = 0.2; this.x = 0; this.y = 0; + this.step = 0; this.settings = { xoffset: 0, yoffset: 0, + xscale: 1, + yscale: 1, }; } load_settings() { let settings = require('Storage').readJSON('calibration.json', true) || {active: false}; - // do nothing if the calibration is deactivated - if (settings.active === true) { - // cancel the calibration offset - Bangle.on('touch', function(button, xy) { - xy.x += settings.xoffset; - xy.y += settings.yoffset; - }); - } if (!settings.xoffset) settings.xoffset = 0; if (!settings.yoffset) settings.yoffset = 0; + if (!settings.xscale) settings.xscale = 1; + if (!settings.yscale) settings.yscale = 1; console.log('loaded settings:'); console.log(settings); @@ -46,19 +44,63 @@ class BanglejsApp { } drawTarget() { - this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32)); - this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80)); + switch (this.step){ + case 0: + this.x = Math.floor(0.2 * g.getWidth()); + this.y = Math.floor(0.2 * g.getHeight()); + break; + case 1: + this.x = Math.floor(0.8 * g.getWidth()); + this.y = Math.floor(0.2 * g.getHeight()); + break; + case 2: + this.x = Math.floor(0.5 * g.getWidth()); + this.y = Math.floor(0.5 * g.getHeight()); + break; + case 3: + this.x = Math.floor(0.2 * g.getWidth()); + this.y = Math.floor(0.8 * g.getHeight()); + break; + case 4: + this.x = Math.floor(0.8 * g.getWidth()); + this.y = Math.floor(0.8 * g.getHeight()); + break; + } - g.clearRect(0, 0, g.getWidth(), g.getHeight()); + g.setColor(g.theme.fg); g.drawLine(this.x, this.y - 5, this.x, this.y + 5); g.drawLine(this.x - 5, this.y, this.x + 5, this.y); g.setFont('Vector', 10); - g.drawString('current offset: ' + this.settings.xoffset + ', ' + this.settings.yoffset, 0, 24); + g.drawString('current offset: ' + this.settings.xoffset.toFixed(3) + ', ' + this.settings.yoffset.toFixed(3), 2, 2); + g.drawString('current scale: ' + this.settings.xscale.toFixed(3) + ', ' + this.settings.yscale.toFixed(3), 2, 12); } - + setOffset(xy) { - this.settings.xoffset = Math.round((this.settings.xoffset + (this.x - Math.floor((this.x + xy.x)/2)))/2); - this.settings.yoffset = Math.round((this.settings.yoffset + (this.y - Math.floor((this.y + xy.y)/2)))/2); + this.last=xy; + switch (this.step){ + case 0: + this.settings.xoffset = this.settings.xoffset * (1-this.updateFactor) + (this.x - xy.x) * this.updateFactor; + this.settings.yoffset = this.settings.yoffset * (1-this.updateFactor) + (this.y - xy.y) * this.updateFactor; + break; + case 1: + this.settings.xscale = this.settings.xscale * (1-this.updateFactor) + ((xy.x + this.settings.xoffset) / this.x) * this.updateFactor; + this.settings.yoffset = this.settings.yoffset * (1-this.updateFactor) + (this.y - xy.y) * this.updateFactor; + break; + case 3: + this.settings.xoffset = this.settings.xoffset * (1-this.updateFactor) + (this.x - xy.x) * this.updateFactor; + this.settings.yscale = this.settings.yscale * (1-this.updateFactor) + ((xy.y + this.settings.yoffset) / this.y) * this.updateFactor; + break; + case 2: + case 4: + this.settings.xscale = this.settings.xscale * (1-this.updateFactor) + ((xy.x + this.settings.xoffset) / this.x) * this.updateFactor; + this.settings.yscale = this.settings.yscale * (1-this.updateFactor) + ((xy.y + this.settings.yoffset) / this.y) * this.updateFactor; + break; + } + } + + nextStep() { + this.step++; + if ( this.step == 5 ) this.step = 0; } } @@ -67,6 +109,14 @@ E.srand(Date.now()); calibration = new BanglejsApp(); calibration.load_settings(); +Bangle.disableCalibration = true; + +function touchHandler (btn, xy){ + g.clearRect(0, 0, g.getWidth(), g.getHeight()); + if (xy) calibration.setOffset(xy); + calibration.drawTarget(); + calibration.nextStep(); +} let modes = { mode : 'custom', @@ -74,10 +124,7 @@ let modes = { calibration.save_settings(this.settings); load(); }, - touch : function(btn, xy) { - calibration.setOffset(xy); - calibration.drawTarget(); - }, + touch : touchHandler, }; Bangle.setUI(modes); -calibration.drawTarget(); +touchHandler(); diff --git a/apps/calibration/boot.js b/apps/calibration/boot.js index 237fb2e0d..2c60de26b 100644 --- a/apps/calibration/boot.js +++ b/apps/calibration/boot.js @@ -1,7 +1,7 @@ let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false}; Bangle.on('touch', function(button, xy) { // do nothing if the calibration is deactivated - if (cal_settings.active === false) return; + if (cal_settings.active === false || Bangle.disableCalibration) return; // reload the calibration offset at each touch event /!\ bad for the flash memory if (cal_settings.reload === true) { @@ -9,6 +9,6 @@ Bangle.on('touch', function(button, xy) { } // apply the calibration offset - xy.x += cal_settings.xoffset; - xy.y += cal_settings.yoffset; + xy.x = Math.round((xy.x + cal_settings.xoffset) * cal_settings.xscale); + xy.y = Math.round((xy.y + cal_settings.yoffset) * cal_settings.yscale); }); From cddaf36f1a7a0566c37018a81d69b2bc69ebf068 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 12:20:09 +0200 Subject: [PATCH 3/6] Use median sample values --- apps/calibration/app.js | 117 +++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/apps/calibration/app.js b/apps/calibration/app.js index 6227b936a..049430d45 100644 --- a/apps/calibration/app.js +++ b/apps/calibration/app.js @@ -1,38 +1,60 @@ class BanglejsApp { constructor() { - this.updateFactor = 0.2; + this.maxSamples = 16; + this.target = { + xMin: Math.floor(0.1 * g.getWidth()), + xMax: Math.floor(0.9 * g.getWidth()), + yMin: Math.floor(0.1 * g.getHeight()), + yMax: Math.floor(0.9 * g.getHeight()), + }; this.x = 0; this.y = 0; this.step = 0; this.settings = { - xoffset: 0, - yoffset: 0, - xscale: 1, - yscale: 1, + xoffset: [0], + yoffset: [0], + xMaxActual: [this.target.xMax], + yMaxActual: [this.target.yMax], }; } load_settings() { let settings = require('Storage').readJSON('calibration.json', true) || {active: false}; - if (!settings.xoffset) settings.xoffset = 0; - if (!settings.yoffset) settings.yoffset = 0; - if (!settings.xscale) settings.xscale = 1; - if (!settings.yscale) settings.yscale = 1; - console.log('loaded settings:'); console.log(settings); return settings; } - save_settings() { - this.settings.active = true; - this.settings.reload = false; - require('Storage').writeJSON('calibration.json', this.settings); + getMedian(array){ + array.sort(); + let i = Math.floor(array.length/2); + if ( array.length % 2 && array.length > 1 ){ + return (array[i]+array[i+1])/2; + } else { + return array[i]; + } + } - console.log('saved settings:'); - console.log(this.settings); + getMedianSettings(){ + let medianSettings = { + xoffset: this.getMedian(this.settings.xoffset), + yoffset: this.getMedian(this.settings.yoffset) + }; + + medianSettings.xscale = this.target.xMax / (medianSettings.xoffset + this.getMedian(this.settings.xMaxActual)); + medianSettings.yscale = this.target.yMax / (medianSettings.yoffset + this.getMedian(this.settings.yMaxActual)); + return medianSettings; + } + + save_settings() { + let settingsToSave = this.getMedianSettings(); + settingsToSave.active = true; + settingsToSave.reload = false; + require('Storage').writeJSON('calibration.json', settingsToSave); + + console.log('saved settings:', settingsToSave); } explain() { @@ -46,61 +68,61 @@ class BanglejsApp { drawTarget() { switch (this.step){ case 0: - this.x = Math.floor(0.2 * g.getWidth()); - this.y = Math.floor(0.2 * g.getHeight()); + this.x = this.target.xMin; + this.y = this.target.yMin; break; case 1: - this.x = Math.floor(0.8 * g.getWidth()); - this.y = Math.floor(0.2 * g.getHeight()); + this.x = this.target.xMax; + this.y = this.target.yMin; break; case 2: - this.x = Math.floor(0.5 * g.getWidth()); - this.y = Math.floor(0.5 * g.getHeight()); + this.x = this.target.xMin; + this.y = this.target.yMax; break; case 3: - this.x = Math.floor(0.2 * g.getWidth()); - this.y = Math.floor(0.8 * g.getHeight()); - break; - case 4: - this.x = Math.floor(0.8 * g.getWidth()); - this.y = Math.floor(0.8 * g.getHeight()); + this.x = this.target.xMax; + this.y = this.target.yMax; break; } + g.clearRect(0, 0, g.getWidth(), g.getHeight()); g.setColor(g.theme.fg); g.drawLine(this.x, this.y - 5, this.x, this.y + 5); g.drawLine(this.x - 5, this.y, this.x + 5, this.y); g.setFont('Vector', 10); - g.drawString('current offset: ' + this.settings.xoffset.toFixed(3) + ', ' + this.settings.yoffset.toFixed(3), 2, 2); - g.drawString('current scale: ' + this.settings.xscale.toFixed(3) + ', ' + this.settings.yscale.toFixed(3), 2, 12); + let medianSettings = this.getMedianSettings(); + g.drawString('current offset: ' + medianSettings.xoffset.toFixed(3) + ', ' + medianSettings.yoffset.toFixed(3), 2, (g.getHeight()/2)-6); + g.drawString('current scale: ' + medianSettings.xscale.toFixed(3) + ', ' + medianSettings.yscale.toFixed(3), 2, (g.getHeight()/2)+6); } - + setOffset(xy) { - this.last=xy; switch (this.step){ case 0: - this.settings.xoffset = this.settings.xoffset * (1-this.updateFactor) + (this.x - xy.x) * this.updateFactor; - this.settings.yoffset = this.settings.yoffset * (1-this.updateFactor) + (this.y - xy.y) * this.updateFactor; + this.settings.xoffset.push(this.x - xy.x); + this.settings.yoffset.push(this.y - xy.y); break; case 1: - this.settings.xscale = this.settings.xscale * (1-this.updateFactor) + ((xy.x + this.settings.xoffset) / this.x) * this.updateFactor; - this.settings.yoffset = this.settings.yoffset * (1-this.updateFactor) + (this.y - xy.y) * this.updateFactor; - break; - case 3: - this.settings.xoffset = this.settings.xoffset * (1-this.updateFactor) + (this.x - xy.x) * this.updateFactor; - this.settings.yscale = this.settings.yscale * (1-this.updateFactor) + ((xy.y + this.settings.yoffset) / this.y) * this.updateFactor; + this.settings.xMaxActual.push(xy.x); + this.settings.yoffset.push(this.y - xy.y); break; case 2: - case 4: - this.settings.xscale = this.settings.xscale * (1-this.updateFactor) + ((xy.x + this.settings.xoffset) / this.x) * this.updateFactor; - this.settings.yscale = this.settings.yscale * (1-this.updateFactor) + ((xy.y + this.settings.yoffset) / this.y) * this.updateFactor; + this.settings.xoffset.push(this.x - xy.x); + this.settings.yMaxActual.push(xy.y); + break; + case 3: + this.settings.xMaxActual.push(xy.x); + this.settings.yMaxActual.push(xy.y); break; } + + for (let c in this.settings){ + if (this.settings[c].length > this.maxSamples) this.settings[c] = this.settings[c].slice(1, this.maxSamples); + } } - + nextStep() { this.step++; - if ( this.step == 5 ) this.step = 0; + if ( this.step == 4 ) this.step = 0; } } @@ -112,10 +134,9 @@ calibration.load_settings(); Bangle.disableCalibration = true; function touchHandler (btn, xy){ - g.clearRect(0, 0, g.getWidth(), g.getHeight()); if (xy) calibration.setOffset(xy); - calibration.drawTarget(); calibration.nextStep(); + calibration.drawTarget(); } let modes = { @@ -127,4 +148,4 @@ let modes = { touch : touchHandler, }; Bangle.setUI(modes); -touchHandler(); +calibration.drawTarget(); From f763cd962f88d5393ee3a91e4b377e82dfb3e2a9 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 13:16:47 +0200 Subject: [PATCH 4/6] Clip values to display range --- apps/calibration/boot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/calibration/boot.js b/apps/calibration/boot.js index 2c60de26b..03b17a03a 100644 --- a/apps/calibration/boot.js +++ b/apps/calibration/boot.js @@ -9,6 +9,6 @@ Bangle.on('touch', function(button, xy) { } // apply the calibration offset - xy.x = Math.round((xy.x + cal_settings.xoffset) * cal_settings.xscale); - xy.y = Math.round((xy.y + cal_settings.yoffset) * cal_settings.yscale); + xy.x = E.clip(Math.round((xy.x + (cal_settings.xoffset || 0)) * (cal_settings.xscale || 1)),0,g.getWidth()); + xy.y = E.clip(Math.round((xy.y + (cal_settings.yoffset || 0)) * (cal_settings.yscale || 1)),0,g.getHeight()); }); From e8c7ea363e17c9d90621239a885e4667f999634b Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 10:54:10 +0200 Subject: [PATCH 5/6] Bump version --- apps/calibration/ChangeLog | 2 ++ apps/calibration/metadata.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 apps/calibration/ChangeLog diff --git a/apps/calibration/ChangeLog b/apps/calibration/ChangeLog new file mode 100644 index 000000000..0e22605af --- /dev/null +++ b/apps/calibration/ChangeLog @@ -0,0 +1,2 @@ +1.00: New App! +1.01: Use fractional numbers and scale the points to keep working consistently on whole screen diff --git a/apps/calibration/metadata.json b/apps/calibration/metadata.json index 122a2c175..b7a719e1c 100644 --- a/apps/calibration/metadata.json +++ b/apps/calibration/metadata.json @@ -2,7 +2,7 @@ "name": "Touchscreen Calibration", "shortName":"Calibration", "icon": "calibration.png", - "version":"1.00", + "version":"1.01", "description": "A simple calibration app for the touchscreen", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", From 0add5a9950830c1896ddffabf1324f5459bacab1 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 27 May 2022 13:20:05 +0200 Subject: [PATCH 6/6] Update readme --- apps/calibration/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/calibration/README.md b/apps/calibration/README.md index 37f637d21..ed1a29d9e 100644 --- a/apps/calibration/README.md +++ b/apps/calibration/README.md @@ -6,6 +6,7 @@ A simple calibration app for the touchscreen Once lauched touch the cross that appear on the screen to make another spawn elsewhere. -each new touch on the screen will help to calibrate the offset -of your finger on the screen. After five or more input, press -the button to save the calibration and close the application. \ No newline at end of file +Each new touch on the screen will help to calibrate the offset +of your finger on the screen. After four or more inputs, press +the button to save the calibration and close the application. Quality +of the calibration gets better with every touch on a cross.