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]
+ ),
+};