From d20b64b396c9673fb71ef203dd649cb42338d073 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 5 Dec 2023 19:19:05 +0100 Subject: [PATCH] Automation: Integrate with Device Orientation API's Automation section Related to w3c/deviceorientation#124. Both the Device Orientation API and the Orientation Sensor specifications provide orientation data. Among other differences, the former provides the data as a set of intrinsic Tait-Bryant Euler angles, whereas the latter uses quaternions. From an automation perspective, though, it makes sense to use the same virtual sensor types for both APIs and take care of the conversions internally. The Device Orientation spec's Automation section defines steps for parsing a user-provided reading as alpha, beta, gamma numbers that adhere to the requirements laid out by the same spec. This commit augments the same "parse orientation data reading" algorithm by also setting a "quaternion" entry in the reading map that is set in two different ways: 1. If the user-provided readings contain a "quaternion" key, it is used as-is via the "parse quaternion reading" algorithm, and it is also converted to Euler angles so that the "alpha"/"beta"/"gamma" reading entries are also set. 2. Otherwise, the user-provider Euler angles are converted to a quaternion that is then used to set the "quaternion" entry in the readings map. The conversions are not trivial, so some new abstract operations have been added to aid in the process. The Euler angles to quaternion algorithm has been copied from Chromium. The quaternion to Euler angles algorithm has been copied from both Chromium and Gecko, both of which need to do this to convert Android's orientation data to a format suitable for their Device Orientation API implementations. --- index.bs | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/index.bs b/index.bs index b17ac3e..2153847 100644 --- a/index.bs +++ b/index.bs @@ -506,26 +506,134 @@ To convert a quaternion to +

Create a quaternion from Euler angles

+ +
+ + +To create a quaternion from Euler angles given a number |alpha|, a number |beta| and a number |gamma|: + + 1. Let |alphaInRadians| be |alpha| converted from degrees to radians. + 1. Let |betaInRadians| be |beta| converted from degrees to radians. + 1. Let |gammaInRadians| be |gamma| converted from degrees to radians. + 1. Let |cosZ| be the cosine of (0.5 * |alphaInRadians|). + 1. Let |sinZ| be the sine of (0.5 * |alphaInRadians|). + 1. Let |cosY| be the cosine of (0.5 * |gammaInRadians|). + 1. Let |sinY| be the sine of (0.5 * |gammaInRadians|). + 1. Let |cosX| be the cosine of (0.5 * |betaInRadians|). + 1. Let |sinX| be the sine of (0.5 * |betaInRadians|). + 1. Let |quaternionX| be (|sinX| * |cosY| * |cosZ| - |cosX| * |sinY| * |sinZ|). + 1. Let |quaternionY| be (|cosX| * |sinY| * |cosZ| + |sinX| * |cosY| * |sinZ|). + 1. Let |quaternionZ| be (|cosX| * |cosY| * |sinZ| + |sinX| * |sinY| * |cosZ|). + 1. Let |quaternionW| be (|cosX| * |cosY| * |cosZ| - |sinX| * |sinY| * |sinZ|). + 1. Return « |quaternionX|, |quaternionY|, |quaternionZ|, |quaternionW| ». + +
+ +

Derive Euler angles from a quaternion

+ +
+ + +To derive Euler angles from a quaternion given |originalRotationMatrix|, a 4x4 rotation matrix as returned by the [=convert a quaternion to rotation matrix=] algorithm: + + 1. Let **atan2(y, x)** be an [=implementation-defined=] function that returns the arc tangent of the quotient `y` / `x`, between `-π` to `+π` (inclusive), in radians, with the signs of `x` and `y` determining the quadrant of the result. + 1. Let **asin(x)** be an [=implementation-defined=] function that returns the inverse sine of `x`. The result is expressed in radians and is in the interval `-π/2` to `π/2` (inclusive). + 1. Let |r| be « |originalRotationMatrix|[0], |originalRotationMatrix|[1], |originalRotationMatrix|[2], |originalRotationMatrix|[4], |originalRotationMatrix|[5], |originalRotationMatrix|[6], |originalRotationMatrix|[8], |originalRotationMatrix|[9], |originalRotationMatrix|[10] ». + + Note: This removes the last row and the last column from |originalRotationMatrix| for simplicity. + + 1. Let |alphaInRadians| be null. + 1. Let |betaInRadians| be null. + 1. Let |gammaInRadians| be null. + 1. If |r|[8] is greater than 0: + 1. Set |alphaInRadians| to **atan2**(-|r|[1], |r|[4]). + 1. Set |betaInRadians| to **asin**(|r|[7]). + 1. Set |gammaInRadians| to **atan2**(-|r|[6], |r|[8]). + 1. Otherwise, if |r|[8] is less than 0: + 1. Set |alphaInRadians| to **atan2**(|r|[1], -|r|[4]). + 1. Set |betaInRadians| to -**asin**(|r|[7]). + 1. If |betaInRadians| is greater than or equal to 0: + 1. Set |betaInRadians| to |betaInRadians| plus -`π`. + 1. Otherwise: + 1. Set |betaInRadians| to |betaInRadians| plus `π`. + 1. Set |gammaInRadians| to **atan2**(|r|[6], -|r|[8]). + 1. Otherwise: + 1. If |r|[6] is greater than 0: + 1. Set |alphaInRadians| to **atan2**(-|r|[1], |r|[4]). + 1. Set |betaInRadians| to **asin**(|r|[7]). + 1. Set |gammaInRadians| to -`π/2`. + 1. Otherwise, if |r|[6] is less than 0: + 1. Set |alphaInRadians| to **atan2**(|r|[1], -|r|[4]). + 1. Set |betaInRadians| to -**asin**(|r|[7]). + 1. If |betaInRadians| is greater than or equal to 0: + 1. Set |betaInRadians| to |betaInRadians| plus -`π`. + 1. Otherwise: + 1. Set |betaInRadians| to |betaInRadians| plus `π`. + 1. Set |gammaInRadians| to -`π/2`. + 1. Otherwise: + 1. Set |alphaInRadians| to **atan2**(|r|[3], |r|[0]). + 1. If |r|[7] is greater than 0: + 1. Set |betaInRadians| to `π/2`. + 1. Otherwise: + 1. Set |betaInRadians| to -`π/2`. + 1. Set |gammaInRadians| to 0. + 1. If |alphaInRadians| is less than 0: + 1. Set |alphaInRadians| to |alphaInRadians| plus (2 * `π`). + 1. Let |alpha| be |alphaInRadians| converted from radians to degrees. + 1. Let |beta| be |betaInRadians| converted from radians to degrees. + 1. Let |gamma| be |gammaInRadians| converted from radians to degrees. + 1. Return « |alpha|, |beta|, |gamma| ». + +
+ Automation {#automation} ========== This section extends [[GENERIC-SENSOR#automation]] by providing [=Orientation Sensor=]-specific virtual sensor metadata. -

Absolute Orientation Sensor automation

+Modifications to other specifications {#modifications-to-other-specifications} +------------------------------------- + +This specification integrates with [[DEVICE-ORIENTATION#automation]] as follows. + +
+The [=parse orientation data reading=] algorithm given a JSON {{Object}} |parameters| is modified as follows: + + * Prepend the following steps to the beginning of the algorithm: + 1. If ! [$HasOwnProperty$](|parameters|, "`quaternion`") is true: + 1. Let |quaternion| be the result of invoking [=parse quaternion reading=] with |parameters|. + 1. If |quaternion| is **undefined**, return **undefined**. + 1. Let |rotationMatrix| be the result of invoking [=convert a quaternion to rotation matrix=] with |quaternion|[0], |quaternion|[1], |quaternion|[2], and |quaternion|[3]. + 1. Let |eulerAngles| be the result of invoking [=derive Euler angles from a quaternion=] with |rotationMatrix|. + 1. Let |reading| be a new [=map=]. + 1. [=map/Set=] |reading|["`quaternion`"] to |quaternion|. + 1. [=map/Set=] |reading|["`alpha`"] to |eulerAngles|[0]. + 1. [=map/Set=] |reading|["`beta`"] to |eulerAngles|[1]. + 1. [=map/Set=] |reading|["`gamma`"] to |eulerAngles|[2]. + 1. Return |reading|. + * Add the following steps after setting |reading|'s "`alpha`", "`beta`", and "`gamma`" keys and before returning |reading|: + 1. [=map/Set=] |reading|["`quaternion`"] to the result of invoking [=create a quaternion from Euler angles=] with |reading|["`alpha`"], |reading|["`beta`"], and |reading|["`gamma`"]. + +
+ +Absolute Orientation Sensor automation {#absolute-orientation-sensor-automation} +-------------------------------------- -The [=per-type virtual sensor metadata=] [=map=] must have the following [=map/entry=]: -: [=map/key=] -:: "[=absolute-orientation virtual sensor type|absolute-orientation=]" -: [=map/value=] -:: A [=virtual sensor metadata=] whose [=virtual sensor metadata/reading parsing algorithm=] is [=parse quaternion reading=]. +The [=absolute-orientation virtual sensor type=] and its corresponding entry in the [=per-type virtual sensor metadata=] [=map=] are defined in [[DEVICE-ORIENTATION#automation]]. -

Relative Orientation Sensor automation

+Relative Orientation Sensor automation {#relative-orientation-sensor-automation} +-------------------------------------- -The [=per-type virtual sensor metadata=] [=map=] must have the following [=map/entry=]: -: [=map/key=] -:: "[=relative-orientation virtual sensor type|relative-orientation=]" -: [=map/value=] -:: A [=virtual sensor metadata=] whose [=virtual sensor metadata/reading parsing algorithm=] is [=parse quaternion reading=]. +The [=relative-orientation virtual sensor type=] and its corresponding entry in the [=per-type virtual sensor metadata=] [=map=] are defined in [[DEVICE-ORIENTATION#automation]]. Acknowledgements {#acknowledgements} ================