From 26c35b27b4f0253a5997e1a8d46ea3cbe1a02dd0 Mon Sep 17 00:00:00 2001 From: Paul Brinkmeier Date: Mon, 21 Jul 2025 23:37:04 +0200 Subject: [PATCH] Add working translation to sphere coordinates --- gyro/debug.html | 47 ++++++++++++++++++++++++++++++++++++ gyro/debug.js | 38 +++++++++++++++++++++++++++++ gyro/index.html | 38 +++++++++++++---------------- gyro/index.js | 42 +++++++++++++++++++++++++++++++++ gyro/m3.js | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ gyro/util.js | 32 +++++++++++++++++++++++++ gyro/v3.js | 18 ++++++++++++++ 7 files changed, 257 insertions(+), 21 deletions(-) create mode 100644 gyro/debug.html create mode 100644 gyro/debug.js create mode 100644 gyro/index.js create mode 100644 gyro/m3.js create mode 100644 gyro/util.js create mode 100644 gyro/v3.js diff --git a/gyro/debug.html b/gyro/debug.html new file mode 100644 index 0000000..6e4a98a --- /dev/null +++ b/gyro/debug.html @@ -0,0 +1,47 @@ + + + + + + + + +

Is it working?

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
α?x?
β?y?
γ?z?
φ?θ?
+ + + + + + diff --git a/gyro/debug.js b/gyro/debug.js new file mode 100644 index 0000000..a156a8a --- /dev/null +++ b/gyro/debug.js @@ -0,0 +1,38 @@ +"use strict"; + +(() => { + document.querySelector("#perm").addEventListener("click", e => { + util.getGyroPermission() + .then((response) => { + const disp = { + a: document.querySelector("#disp-a"), + b: document.querySelector("#disp-b"), + c: document.querySelector("#disp-c"), + x: document.querySelector("#disp-x"), + y: document.querySelector("#disp-y"), + z: document.querySelector("#disp-z"), + phi: document.querySelector("#disp-phi"), + theta: document.querySelector("#disp-theta"), + }; + + window.addEventListener("deviceorientation", e => { + const alpha = util.deg2rad(e.alpha); + const beta = util.deg2rad(e.beta); + const gamma = util.deg2rad(e.gamma); + + const [screenNormal, phi, theta] = util.toPolarCoordinates(alpha, beta, gamma); + + disp.a.innerHTML = `${Math.round(e.alpha)}`; + disp.b.innerHTML = `${Math.round(e.beta)}`; + disp.c.innerHTML = `${Math.round(e.gamma)}`; + + disp.x.innerHTML = `${Math.round(100 * screenNormal[0])}`; + disp.y.innerHTML = `${Math.round(100 * screenNormal[1])}`; + disp.z.innerHTML = `${Math.round(100 * screenNormal[2])}`; + + disp.phi.innerHTML = `${Math.round(phi / Math.PI * 180)}`; + disp.theta.innerHTML = `${Math.round(theta / Math.PI * 180)}`; + }); + }); + }, { once: true }); +})(); diff --git a/gyro/index.html b/gyro/index.html index c3982ca..d50c7c9 100644 --- a/gyro/index.html +++ b/gyro/index.html @@ -1,26 +1,22 @@ + + + + + -

Is it working?

- -
lalala
- +

Is it working?

+ + + + + + diff --git a/gyro/index.js b/gyro/index.js new file mode 100644 index 0000000..1bd90d9 --- /dev/null +++ b/gyro/index.js @@ -0,0 +1,42 @@ +"use strict"; + +(() => { + const ctx = canvas.getContext("2d"); + const scale = Math.min(canvas.width, canvas.height) / 2; + ctx.setTransform( + scale, 0, + 0, -scale, + canvas.width / 2, canvas.height / 2 + ); + + ctx.fillStyle = util.rgb(1, 0, 0); + ctx.fillRect(-0.5, -0.5, 1, 1); + + perm.addEventListener("click", e => { + util.getGyroPermission() + .then((response) => { + window.addEventListener("deviceorientation", e => { + const alpha = util.deg2rad(e.alpha); + const beta = util.deg2rad(e.beta); + const gamma = util.deg2rad(e.gamma); + + const [screenNormal, phi, theta] = util.toPolarCoordinates(alpha, beta, gamma); + const theta_ = Math.abs(theta - Math.PI / 2) / Math.PI * 2; + const phi_ = phi - Math.PI / 2; + + ctx.clearRect(-1, -1, 2, 2); + + const g = theta_; + ctx.fillStyle = util.rgb(255, g, g); + ctx.fillRect(-1, -1, 2, 2); + + ctx.strokeStyle = "black"; + ctx.lineWidth = 0.01; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(Math.cos(phi_), Math.sin(phi_)); + ctx.stroke(); + }); + }); + }, { once: true }); +})(); diff --git a/gyro/m3.js b/gyro/m3.js new file mode 100644 index 0000000..1b56504 --- /dev/null +++ b/gyro/m3.js @@ -0,0 +1,63 @@ +const m3 = { + xRotation: (phi) => { + const c = Math.cos(phi), s = Math.sin(phi); + return [ + 1, 0, 0, + 0, c, -s, + 0, s, c + ]; + }, + yRotation: (phi) => { + const c = Math.cos(phi), s = Math.sin(phi); + return [ + c, 0, s, + 0, 1, 0, + -s, 0, c + ]; + }, + zRotation: (phi) => { + const c = Math.cos(phi), s = Math.sin(phi); + return [ + c, -s, 0, + s, c, 0, + 0, 0, 1 + ]; + }, + add: (m1, m2) => [ + m1[0] + m2[0], + m1[1] + m2[1], + m1[2] + m2[2], + m1[3] + m2[3], + m1[4] + m2[4], + m1[5] + m2[5], + m1[6] + m2[6], + m1[7] + m2[7], + m1[8] + m2[8], + ], + mul: (m1, m2) => [ + m1[0]*m2[0] + m1[1]*m2[3] + m1[2]*m2[6], + m1[0]*m2[1] + m1[1]*m2[4] + m1[2]*m2[7], + m1[0]*m2[2] + m1[1]*m2[5] + m1[2]*m2[8], + m1[3]*m2[0] + m1[4]*m2[3] + m1[5]*m2[6], + m1[3]*m2[1] + m1[4]*m2[4] + m1[5]*m2[7], + m1[3]*m2[2] + m1[4]*m2[5] + m1[5]*m2[8], + m1[6]*m2[0] + m1[7]*m2[3] + m1[8]*m2[6], + m1[6]*m2[1] + m1[7]*m2[4] + m1[8]*m2[7], + m1[6]*m2[2] + m1[7]*m2[5] + m1[8]*m2[8], + ], + mulV: (m, v) => [ + m[0]*v[0] + m[1]*v[1] + m[2]*v[2], + m[3]*v[0] + m[4]*v[1] + m[5]*v[2], + m[6]*v[0] + m[7]*v[1] + m[8]*v[2] + ], + eq: (m1, m2) => + m1[0] === m2[0] && + m1[1] === m2[1] && + m1[2] === m2[2] && + m1[3] === m2[3] && + m1[4] === m2[4] && + m1[5] === m2[5] && + m1[6] === m2[6] && + m1[7] === m2[7] && + m1[8] === m2[8], +}; diff --git a/gyro/util.js b/gyro/util.js new file mode 100644 index 0000000..3ea4a0f --- /dev/null +++ b/gyro/util.js @@ -0,0 +1,32 @@ +const util = { + getGyroPermission: () => { + if(!DeviceOrientationEvent.requestPermission) { + return Promise.resolve("granted") + } else{ + return DeviceOrientationEvent.requestPermission() + } + }, + round: (x, decimalPlaces) => + Math.round(x * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces), + // parameters in radians + // return values in radians + toPolarCoordinates: (alpha, beta, gamma) => { + const rz = m3.zRotation(alpha); + const rx = m3.xRotation(beta); + const ry = m3.yRotation(gamma); + + const rot = m3.mul(rz, m3.mul(rx, ry)); + + const screenNormal = m3.mulV(rot, [0, 0, 1]); + + const phi = Math.atan2(screenNormal[1], screenNormal[0]); + const r = v3.norm2(screenNormal); + // theta ∈ [0, π] + // where 0 is lying flat and π is upside down + const theta = Math.acos(screenNormal[2] / r); + + return [screenNormal, phi, theta]; + }, + rgb: (r, g, b) => `rgb(${255 * r}, ${255 * g}, ${255 * b})`, + deg2rad: (deg) => deg / 180 * Math.PI, +}; diff --git a/gyro/v3.js b/gyro/v3.js new file mode 100644 index 0000000..dd90dac --- /dev/null +++ b/gyro/v3.js @@ -0,0 +1,18 @@ +const v3 = { + add: (v1, v2) => [ + v1[0] + v2[0], + v1[1] + v2[2], + v1[2] + v2[2], + ], + subtract: (v1, v2) => [ + v1[0] - v2[0], + v1[1] - v2[2], + v1[2] - v2[2], + ], + norm2: (v) => + Math.sqrt( + v[0] * v[0] + + v[1] * v[1] + + v[2] * v[2] + ), +};