| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title> rotate composition</title> |
| <link rel="help" href="https://drafts.csswg.org/css-transforms-2/#propdef-rotate"> |
| <meta name="assert" content="rotate supports animation"> |
| |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/css/support/interpolation-testcommon.js"></script> |
| |
| <body> |
| <script> |
| // Numerical precision may cause an axis aligned rotation to appear slightly |
| // misaligned. Convert to (x, y, z, angle) form with rounding for comparison. |
| function parseRotation(args) { |
| const array = args.split(' '); |
| if (array.length == 1) { |
| // Angle or 'none'. |
| return !!parseFloat(args) ? roundNumbers('0 0 1 ' + args) : args; |
| } |
| if (array.length == 2) { |
| // Axis name + angle |
| let axis = array[0]; |
| let angle = array[1]; |
| switch (array[0]) { |
| case 'x': |
| axis = '1 0 0 '; |
| break; |
| case 'y': |
| axis = '0 1 0'; |
| break; |
| case 'z': |
| axis = '0 0 1'; |
| break; |
| } |
| return roundNumbers(axis + ' ' + angle); |
| } |
| if (array.length == 4) { |
| // Axis as [x,y,z] triplet + angle. |
| // Normalize the axis (if possible) for comparison. |
| let x = parseFloat(array[0]); |
| let y = parseFloat(array[1]); |
| let z = parseFloat(array[2]); |
| const angle = array[3]; |
| const length = Math.sqrt(x*x + y*y + z*z); |
| if (length > 1e-4) { |
| x /= length; |
| y /= length; |
| z /= length; |
| } |
| return roundNumbers(`${x} ${y} ${z} ${angle}`); |
| } |
| return args; |
| } |
| |
| function compareRotations(actual, expected) { |
| assert_equals(parseRotation(actual), parseRotation(expected)); |
| } |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '100deg', |
| addFrom: '10deg', |
| addTo: '30deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '90deg'}, |
| {at: 0, expect: '110deg'}, |
| {at: 0.25, expect: '115deg'}, |
| {at: 0.75, expect: '125deg'}, |
| {at: 1, expect: '130deg'}, |
| {at: 2, expect: '150deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 0 0 200deg', |
| addFrom: '1 0 0 -100deg', |
| replaceTo: '1 0 0 40deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '1 0 0 160deg'}, |
| {at: 0, expect: '1 0 0 100deg'}, |
| {at: 0.25, expect: '1 0 0 85deg'}, |
| {at: 0.75, expect: '1 0 0 55deg'}, |
| {at: 1, expect: '1 0 0 40deg'}, |
| {at: 2, expect: '1 0 0 -20deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '0 1 0 -40deg', |
| replaceFrom: '0 1 0 50deg', |
| addTo: '0 1 0 10deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0 1 0 130deg'}, |
| {at: 0, expect: '0 1 0 50deg'}, |
| {at: 0.25, expect: '0 1 0 30deg'}, |
| {at: 0.75, expect: '0 1 0 -10deg'}, |
| {at: 1, expect: '0 1 0 -30deg'}, |
| {at: 2, expect: '0 1 0 -110deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 2 3 40deg', |
| addFrom: '2 4 6 10deg', |
| addTo: '3 6 9 50deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0.27 0.53 0.8 10deg'}, |
| {at: 0, expect: '0.27 0.53 0.8 50deg'}, |
| {at: 0.25, expect: '0.27 0.53 0.8 60deg'}, |
| {at: 0.75, expect: '0.27 0.53 0.8 80deg'}, |
| {at: 1, expect: '0.27 0.53 0.8 90deg'}, |
| {at: 2, expect: '0.27 0.53 0.8 130deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 2 3 270deg', |
| addFrom: '1 2 3 90deg', |
| replaceTo: '0 1 0 100deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0 -1 0 100deg'}, |
| // Accept both the SLERP and the common axis solution, which are equivalent. |
| {at: 0, expect: '0.27 0.53 0.8 360deg', option: '0.27 0.53 0.8 0deg'}, |
| {at: 0.25, expect: 'y 25deg'}, |
| {at: 0.75, expect: 'y 75deg'}, |
| {at: 1, expect: 'y 100deg'}, |
| // Accept both the SLERP and the common axis solution, which are equivalent. |
| {at: 2, expect: '0 -1 0 160deg', option: 'y 200deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 2 3 90deg', |
| addFrom: '2 4 6 270deg', |
| replaceTo: '0 1 0 100deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0 -1 0 100deg'}, |
| // Accept both the SLERP and the common axis solution, which are equivalent. |
| {at: 0, expect: '0.27 0.53 0.8 360deg', option: '0.27 0.53 0.8 0deg'}, |
| {at: 0.25, expect: 'y 25deg'}, |
| {at: 0.75, expect: 'y 75deg'}, |
| {at: 1, expect: 'y 100deg'}, |
| // Accept both the SLERP and the common axis solution, which are equivalent. |
| {at: 2, expect: '0 -1 0 160deg', option: 'y 200deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 0 0 0deg', |
| addFrom: '1 1 0 90deg', |
| replaceTo: '0 1 1 135deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0.67 -0.06 -0.74 124.97deg'}, |
| {at: 0, expect: '0.71 0.71 0 90deg'}, |
| {at: 0.25, expect: '0.54 0.8 0.26 94.83deg'}, |
| {at: 0.75, expect: '0.17 0.78 0.61 118.68deg'}, |
| {at: 1, expect: '0 0.71 0.71 135deg'}, |
| {at: 2, expect: '-0.52 0.29 0.81 208.96deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: 'none', |
| addFrom: 'none', |
| replaceTo: '0 1 0 100deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: 'y -100deg'}, |
| {at: 0, expect: 'y 0deg'}, |
| {at: 0.25, expect: 'y 25deg'}, |
| {at: 0.75, expect: 'y 75deg'}, |
| {at: 1, expect: 'y 100deg'}, |
| {at: 2, expect: 'y 200deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: 'none', |
| addFrom: '2 4 6 270deg', |
| replaceTo: 'none', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0.27 0.53 0.8 540deg'}, |
| {at: 0, expect: '0.27 0.53 0.8 270deg'}, |
| {at: 0.25, expect: '0.27 0.53 0.8 202.5deg'}, |
| {at: 0.75, expect: '0.27 0.53 0.8 67.5deg'}, |
| {at: 1, expect: '0.27 0.53 0.8 0deg'}, |
| {at: 2, expect: '0.27 0.53 0.8 -270deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 2 3 90deg', |
| addFrom: 'none', |
| replaceTo: '0 1 0 100deg', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0.31 -0.22 0.92 131.66deg'}, |
| {at: 0, expect: '1 2 3 90deg'}, |
| {at: 0.25, expect: '0.21 0.73 0.64 86.72deg'}, |
| {at: 0.75, expect: '0.07 0.97 0.21 92.05deg'}, |
| {at: 1, expect: '0 1 0 100deg'}, |
| {at: 2, expect: '-0.2 0.79 -0.59 151.11deg'}, |
| ]); |
| |
| test_composition({ |
| property: 'rotate', |
| underlying: '1 2 3 90deg', |
| addFrom: '2 4 6 270deg', |
| replaceTo: 'none', |
| comparisonFunction: compareRotations |
| }, [ |
| {at: -1, expect: '0.27 0.53 0.8 720deg'}, |
| {at: 0, expect: '0.27 0.53 0.8 360deg'}, |
| {at: 0.25, expect: '0.27 0.53 0.8 270deg'}, |
| {at: 0.75, expect: '0.27 0.53 0.8 90deg'}, |
| {at: 1, expect: '0.27 0.53 0.8 0deg'}, |
| {at: 2, expect: '0.27 0.53 0.8 -360deg'}, |
| ]); |
| </script> |
| </body> |