diff --git a/vlib/math/vec/vec2.v b/vlib/math/vec/vec2.v index 623072f3fa..cf99bbabdd 100644 --- a/vlib/math/vec/vec2.v +++ b/vlib/math/vec/vec2.v @@ -258,6 +258,23 @@ pub fn (v Vec2[T]) project(u Vec2[T]) Vec2[T] { return u.mul_scalar(percent) } +// rotate_around_cw returns the vector `v` rotated *clockwise* `radians` around an origin vector `o` in Cartesian space. +pub fn (v Vec2[T]) rotate_around_cw(o Vec2[T], radians f64) Vec2[T] { + return v.rotate_around_ccw(o, -radians) +} + +// rotate_around_ccw returns the vector `v` rotated *counter-clockwise* `radians` around an origin vector `o` in Cartesian space. +pub fn (v Vec2[T]) rotate_around_ccw(o Vec2[T], radians f64) Vec2[T] { + s := math.sin(radians) + c := math.cos(radians) + dx := v.x - o.x + dy := v.y - o.y + return Vec2[T]{ + x: T(c * dx - s * dy + o.x) + y: T(s * dx + c * dy + o.y) + } +} + // eq returns a bool indicating if the two vectors are equal. @[inline] pub fn (v Vec2[T]) eq(u Vec2[T]) bool { diff --git a/vlib/math/vec/vec2_test.v b/vlib/math/vec/vec2_test.v index 857ebadf05..02b05d50bf 100644 --- a/vlib/math/vec/vec2_test.v +++ b/vlib/math/vec/vec2_test.v @@ -1,4 +1,4 @@ -import math { close, veryclose } +import math { close, radians, veryclose } import math.vec fn test_vec2_int() { @@ -160,3 +160,71 @@ fn test_vec2_angle_towards() { } } } + +fn test_vec2_rotate_around_cw() { + origin := vec.vec2(0.0, 0.0) + mut v := vec.vec2(0.0, 1.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 1.0) + assert close(v.y, 0.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 0.0) + assert close(v.y, -1.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, -1.0) + assert close(v.y, 0.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 0.0) + assert close(v.y, 1.0) +} + +fn test_vec2_rotate_around_ccw() { + origin := vec.vec2(0.0, 0.0) + mut v := vec.vec2(0.0, 1.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, -1.0) + assert close(v.y, 0.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, 0.0) + assert close(v.y, -1.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, 1.0) + assert close(v.y, 0.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, 0.0) + assert close(v.y, 1.0) +} + +fn test_vec2_rotate_around_cw_2() { + origin := vec.vec2(1.0, 1.0) + mut v := vec.vec2(1.0, 2.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 2.0) + assert close(v.y, 1.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 1.0) + assert close(v.y, 0.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 0.0) + assert close(v.y, 1.0) + v = v.rotate_around_cw(origin, radians(90)) + assert close(v.x, 1.0) + assert close(v.y, 2.0) +} + +fn test_vec2_rotate_around_ccw_2() { + origin := vec.vec2(-1.0, 1.0) + mut v := vec.vec2(-1.0, -1.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, 1.0) + assert close(v.y, 1.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, -1.0) + assert close(v.y, 3.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, -3.0) + assert close(v.y, 1.0) + v = v.rotate_around_ccw(origin, radians(90)) + assert close(v.x, -1.0) + assert close(v.y, -1.0) +}