From b89fa2b9f45ce81e0352fc6eb194f12e43946e8d Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 20 Mar 2024 13:55:40 -0700 Subject: [PATCH] port rotate from gl-matrix for vec2, vec3. fixes #23 --- src/vec2-impl.ts | 23 ++++++++++ src/vec3-impl.ts | 98 ++++++++++++++++++++++++++++++++++++++++- test/tests/vec2-test.js | 25 +++++++++++ test/tests/vec3-test.js | 71 +++++++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 1 deletion(-) diff --git a/src/vec2-impl.ts b/src/vec2-impl.ts index 08e4774..db45f51 100644 --- a/src/vec2-impl.ts +++ b/src/vec2-impl.ts @@ -644,3 +644,26 @@ export function transformMat3(v: Vec2, m: Mat3, dst?: Vec2): Vec2 { return dst; } +/** + * Rotate a 2D vector + * + * @param a The vec2 point to rotate + * @param b The origin of the rotation + * @param rad The angle of rotation in radians + * @returns the rotated vector + */ +export function rotate(a: Vec2, b: Vec2, rad: number, dst?: Vec2) { + dst = dst || new VecType(2); + + // Translate point to the origin + const p0 = a[0] - b[0]; + const p1 = a[1] - b[1]; + const sinC = Math.sin(rad); + const cosC = Math.cos(rad); + + //perform rotation and translate to correct position + dst[0] = p0 * cosC - p1 * sinC + b[0]; + dst[1] = p0 * sinC + p1 * cosC + b[1]; + + return dst; +} diff --git a/src/vec3-impl.ts b/src/vec3-impl.ts index 04013b7..a8eb263 100644 --- a/src/vec3-impl.ts +++ b/src/vec3-impl.ts @@ -786,4 +786,100 @@ export function getScaling(m: Mat4, dst: Vec3) { dst[1] = Math.sqrt(yx * yx + yy * yy + yz * yz); dst[2] = Math.sqrt(zx * zx + zy * zy + zz * zz); return dst; -} \ No newline at end of file +} + +/** + * Rotate a 3D vector around the x-axis + * + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @param dst - The vector to set. If not passed a new one is created. + * @returns the rotated vector + */ +export function rotateX(a: Vec3, b: Vec3, rad: number, dst?: Vec3) { + dst = dst || new VecType(3); + const p = []; + const r = []; + + //Translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + //perform rotation + r[0] = p[0]; + r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad); + r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad); + + //translate to correct position + dst[0] = r[0] + b[0]; + dst[1] = r[1] + b[1]; + dst[2] = r[2] + b[2]; + + return dst; +} + +/** + * Rotate a 3D vector around the y-axis + * + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @param dst - The vector to set. If not passed a new one is created. + * @returns the rotated vector + */ +export function rotateY(a: Vec3, b: Vec3, rad: number, dst?: Vec3) { + dst = dst || new VecType(3); + const p = []; + const r = []; + + // translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + // perform rotation + r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad); + r[1] = p[1]; + r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad); + + // translate to correct position + dst[0] = r[0] + b[0]; + dst[1] = r[1] + b[1]; + dst[2] = r[2] + b[2]; + + return dst; +} + +/** + * Rotate a 3D vector around the z-axis + * + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @param dst - The vector to set. If not passed a new one is created. + * @returns {vec3} out + */ +export function rotateZ(a: Vec3, b: Vec3, rad: number, dst?: Vec3) { + dst = dst || new VecType(3); + const p = []; + const r = []; + + // translate point to the origin + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; + + // perform rotation + r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad); + r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad); + r[2] = p[2]; + + // translate to correct position + dst[0] = r[0] + b[0]; + dst[1] = r[1] + b[1]; + dst[2] = r[2] + b[2]; + + return dst; +} diff --git a/test/tests/vec2-test.js b/test/tests/vec2-test.js index c121b7a..1ca4775 100644 --- a/test/tests/vec2-test.js +++ b/test/tests/vec2-test.js @@ -471,5 +471,30 @@ describe('vec2', () => { check(Float32Array); check(Float64Array); + describe('rotate', function() { + describe('rotation around world origin [0, 0, 0]', function() { + let vecA, vecB, result; + beforeEach(function () { + vecA = [0, 1]; + vecB = [0, 0]; + result = vec2.rotate(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [0, -1]); + }); + }); + describe('rotation around an arbitrary origin', function () { + let vecA, vecB, result; + beforeEach(function () { + vecA = [6, -5]; + vecB = [0, -5]; + result = vec2.rotate(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [-6, -5]); + }); + }); + }); + }); diff --git a/test/tests/vec3-test.js b/test/tests/vec3-test.js index 698ef8f..eab266c 100644 --- a/test/tests/vec3-test.js +++ b/test/tests/vec3-test.js @@ -480,5 +480,76 @@ describe('vec3', () => { check(Float32Array); check(Float64Array); + let vecA, vecB, result; + + describe('rotateX', function () { + describe('rotation around world origin [0, 0, 0]', function () { + beforeEach(function () { + vecA = [0, 1, 0]; + vecB = [0, 0, 0]; + result = vec3.rotateX(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [0, -1, 0]); + }); + }); + + describe('rotation around an arbitrary origin', function () { + beforeEach(function () { + vecA = [2, 7, 0]; + vecB = [2, 5, 0]; + result = vec3.rotateX(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [2, 3, 0]); + }); + }); + }); + + describe('rotateY', function () { + describe('rotation around world origin [0, 0, 0]', function () { + beforeEach(function() { + vecA = [1, 0, 0]; + vecB = [0, 0, 0]; + result = vec3.rotateY(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [-1, 0, 0]); + }); + }); + describe('rotation around an arbitrary origin', function () { + beforeEach(function () { + vecA = [-2, 3, 10]; + vecB = [-4, 3, 10]; + result = vec3.rotateY(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [-6, 3, 10]); + }); + }); + }); + + describe('rotateZ', function () { + describe('rotation around world origin [0, 0, 0]', function () { + beforeEach(function () { + vecA = [0, 1, 0]; + vecB = [0, 0, 0]; + result = vec3.rotateZ(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [0, -1, 0]); + }); + }); + describe('rotation around an arbitrary origin', function () { + beforeEach(function () { + vecA = [0, 6, -5]; + vecB = [0, 0, -5]; + result = vec3.rotateZ(vecA, vecB, Math.PI); + }); + it("should return the rotated vector", function () { + assertEqualApproximately(result, [0, -6, -5]); + }); + }); + }); });