feat: implement Vec2 class with basic operations and tests
Signed-off-by: szdytom <szdytom@qq.com>
This commit is contained in:
parent
e1d3725b87
commit
f8a2b0c9eb
@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.27)
|
cmake_minimum_required(VERSION 3.27)
|
||||||
|
|
||||||
# Define util library sources (header-only for now)
|
# Define util library sources
|
||||||
add_library(istd_util INTERFACE)
|
add_library(istd_util STATIC
|
||||||
target_include_directories(istd_util INTERFACE include)
|
src/vec2.cpp
|
||||||
target_compile_features(istd_util INTERFACE cxx_std_23)
|
)
|
||||||
|
target_include_directories(istd_util PUBLIC include)
|
||||||
|
target_compile_features(istd_util PUBLIC cxx_std_23)
|
||||||
|
|
||||||
if (BUILD_TESTS)
|
if (BUILD_TESTS)
|
||||||
add_subdirectory("test/")
|
add_subdirectory("test/")
|
||||||
|
159
util/include/istd_util/vec2.h
Normal file
159
util/include/istd_util/vec2.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#ifndef ISTD_UTIL_VEC2_H
|
||||||
|
#define ISTD_UTIL_VEC2_H
|
||||||
|
|
||||||
|
#include <compare>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace istd {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 2D vector with float components.
|
||||||
|
*
|
||||||
|
* Provides basic arithmetic, comparison, and utility operations for 2D vectors.
|
||||||
|
*/
|
||||||
|
struct Vec2 {
|
||||||
|
/**
|
||||||
|
* @brief X component of the vector.
|
||||||
|
*/
|
||||||
|
float x;
|
||||||
|
/**
|
||||||
|
* @brief Y component of the vector.
|
||||||
|
*/
|
||||||
|
float y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Vec2 object.
|
||||||
|
* @param x X component
|
||||||
|
* @param y Y component
|
||||||
|
*/
|
||||||
|
Vec2(float x, float y) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns a zero vector (0, 0).
|
||||||
|
*/
|
||||||
|
static Vec2 zero() noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns a vector rotated by the given angle.
|
||||||
|
* @param rad Angle in radians
|
||||||
|
* @param len Length of the resulting vector (default 1.0)
|
||||||
|
*/
|
||||||
|
static Vec2 rotated(float rad, float len = 1.0) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Symmetric operations
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief Vector addition.
|
||||||
|
*/
|
||||||
|
friend Vec2 operator+(Vec2 a, Vec2 b) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Vector subtraction.
|
||||||
|
*/
|
||||||
|
friend Vec2 operator-(Vec2 a, Vec2 b) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Unary negation.
|
||||||
|
*/
|
||||||
|
friend Vec2 operator-(Vec2 a) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Scalar multiplication.
|
||||||
|
*/
|
||||||
|
friend Vec2 operator*(Vec2 a, float k) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Scalar division.
|
||||||
|
*/
|
||||||
|
friend Vec2 operator/(Vec2 a, float k) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Three-way comparison operator.
|
||||||
|
*/
|
||||||
|
friend std::strong_ordering operator<=>(Vec2 a, Vec2 b) noexcept;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Assignment operations
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief Adds another vector to this vector.
|
||||||
|
*/
|
||||||
|
Vec2 &operator+=(Vec2 b) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Subtracts another vector from this vector.
|
||||||
|
*/
|
||||||
|
Vec2 &operator-=(Vec2 b) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Multiplies this vector by a scalar.
|
||||||
|
*/
|
||||||
|
Vec2 &operator*=(float k) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Divides this vector by a scalar.
|
||||||
|
*/
|
||||||
|
Vec2 &operator/=(float k) noexcept;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access vector components by index.
|
||||||
|
* @param i Index (0 for x, 1 for y)
|
||||||
|
* @return Reference to the component
|
||||||
|
* @throws std::out_of_range if index is not 0 or 1
|
||||||
|
*/
|
||||||
|
float &operator[](std::size_t i) {
|
||||||
|
if (i == 0) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
if (i == 1) {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
throw std::out_of_range("Index out of range for Vec2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access vector components by index (const).
|
||||||
|
* @param i Index (0 for x, 1 for y)
|
||||||
|
* @return Value of the component
|
||||||
|
* @throws std::out_of_range if index is not 0 or 1
|
||||||
|
*/
|
||||||
|
float operator[](std::size_t i) const {
|
||||||
|
if (i == 0) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
if (i == 1) {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
throw std::out_of_range("Index out of range for Vec2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the length (magnitude) of the vector.
|
||||||
|
*/
|
||||||
|
float length(this const Vec2 self) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns the squared length of the vector.
|
||||||
|
*/
|
||||||
|
float length_squared(this const Vec2 self) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns a normalized (unit length) vector.
|
||||||
|
*/
|
||||||
|
Vec2 normalized(this const Vec2 self) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns a tuple of floored components.
|
||||||
|
*/
|
||||||
|
std::tuple<int, int> floor(this const Vec2 self) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns a tuple of rounded components.
|
||||||
|
*/
|
||||||
|
std::tuple<int, int> round(this const Vec2 self) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the dot product of two vectors.
|
||||||
|
*/
|
||||||
|
friend float dot(Vec2 a, Vec2 b) noexcept;
|
||||||
|
/**
|
||||||
|
* @brief Returns the cross product of two vectors.
|
||||||
|
*/
|
||||||
|
friend float cross(Vec2 a, Vec2 b) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace istd
|
||||||
|
|
||||||
|
#endif
|
115
util/src/vec2.cpp
Normal file
115
util/src/vec2.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
#include "istd_util/vec2.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace istd {
|
||||||
|
|
||||||
|
Vec2::Vec2(float x_, float y_) noexcept: x(x_), y(y_) {}
|
||||||
|
|
||||||
|
Vec2 Vec2::zero() noexcept {
|
||||||
|
return Vec2(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 Vec2::rotated(float rad, float len) noexcept {
|
||||||
|
return Vec2(std::cos(rad) * len, std::sin(rad) * len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator+(Vec2 a, Vec2 b) noexcept {
|
||||||
|
return Vec2(a.x + b.x, a.y + b.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator-(Vec2 a, Vec2 b) noexcept {
|
||||||
|
return Vec2(a.x - b.x, a.y - b.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator-(Vec2 a) noexcept {
|
||||||
|
return Vec2(-a.x, -a.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator*(Vec2 a, float k) noexcept {
|
||||||
|
return Vec2(a.x * k, a.y * k);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 operator/(Vec2 a, float k) noexcept {
|
||||||
|
return Vec2(a.x / k, a.y / k);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::strong_ordering operator<=>(Vec2 a, Vec2 b) noexcept {
|
||||||
|
if (a.x < b.x) {
|
||||||
|
return std::strong_ordering::less;
|
||||||
|
}
|
||||||
|
if (a.x > b.x) {
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
}
|
||||||
|
if (a.y < b.y) {
|
||||||
|
return std::strong_ordering::less;
|
||||||
|
}
|
||||||
|
if (a.y > b.y) {
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
}
|
||||||
|
return std::strong_ordering::equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 &Vec2::operator+=(Vec2 b) noexcept {
|
||||||
|
x += b.x;
|
||||||
|
y += b.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 &Vec2::operator-=(Vec2 b) noexcept {
|
||||||
|
x -= b.x;
|
||||||
|
y -= b.y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 &Vec2::operator*=(float k) noexcept {
|
||||||
|
x *= k;
|
||||||
|
y *= k;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 &Vec2::operator/=(float k) noexcept {
|
||||||
|
x /= k;
|
||||||
|
y /= k;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vec2::length(this const Vec2 self) noexcept {
|
||||||
|
return std::sqrt(self.x * self.x + self.y * self.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vec2::length_squared(this const Vec2 self) noexcept {
|
||||||
|
return self.x * self.x + self.y * self.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 Vec2::normalized(this const Vec2 self) noexcept {
|
||||||
|
float len = self.length();
|
||||||
|
if (len == 0.0f) {
|
||||||
|
return Vec2(0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
return Vec2(self.x / len, self.y / len);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int> Vec2::floor(this const Vec2 self) noexcept {
|
||||||
|
return std::make_tuple(
|
||||||
|
static_cast<int>(std::floor(self.x)),
|
||||||
|
static_cast<int>(std::floor(self.y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int> Vec2::round(this const Vec2 self) noexcept {
|
||||||
|
return std::make_tuple(
|
||||||
|
static_cast<int>(std::round(self.x)),
|
||||||
|
static_cast<int>(std::round(self.y))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot(Vec2 a, Vec2 b) noexcept {
|
||||||
|
return a.x * b.x + a.y * b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float cross(Vec2 a, Vec2 b) noexcept {
|
||||||
|
return a.x * b.y - a.y * b.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace istd
|
@ -1,9 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 3.27)
|
cmake_minimum_required(VERSION 3.27)
|
||||||
|
|
||||||
|
|
||||||
add_executable(test_small_map small_map.cpp)
|
add_executable(test_small_map small_map.cpp)
|
||||||
target_link_libraries(test_small_map PRIVATE istd_util)
|
target_link_libraries(test_small_map PRIVATE istd_util)
|
||||||
target_compile_features(test_small_map PRIVATE cxx_std_23)
|
target_compile_features(test_small_map PRIVATE cxx_std_23)
|
||||||
|
|
||||||
|
add_executable(test_vec2 test_vec2.cpp)
|
||||||
|
target_link_libraries(test_vec2 PRIVATE istd_util)
|
||||||
|
target_compile_features(test_vec2 PRIVATE cxx_std_23)
|
||||||
|
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_test(NAME util_small_map COMMAND test_small_map)
|
add_test(NAME util_small_map COMMAND test_small_map)
|
||||||
|
add_test(NAME util_vec2 COMMAND test_vec2)
|
||||||
|
34
util/test/test_vec2.cpp
Normal file
34
util/test/test_vec2.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "istd_util/vec2.h"
|
||||||
|
#include <cassert>
|
||||||
|
using namespace istd;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Vec2 v1(3.0f, 4.0f);
|
||||||
|
Vec2 v2(1.0f, 2.0f);
|
||||||
|
|
||||||
|
// Test length and length_squared
|
||||||
|
assert(v1.length() == 5.0f);
|
||||||
|
assert(v1.length_squared() == 25.0f);
|
||||||
|
|
||||||
|
// Test normalized
|
||||||
|
Vec2 n = v1.normalized();
|
||||||
|
assert(std::abs(n.length() - 1.0f) < 1e-6);
|
||||||
|
|
||||||
|
// Test addition and subtraction
|
||||||
|
Vec2 v3 = v1 + v2;
|
||||||
|
assert(v3.x == 4.0f && v3.y == 6.0f);
|
||||||
|
Vec2 v4 = v1 - v2;
|
||||||
|
assert(v4.x == 2.0f && v4.y == 2.0f);
|
||||||
|
|
||||||
|
// Test dot and cross
|
||||||
|
assert(dot(v1, v2) == 11.0f);
|
||||||
|
assert(cross(v1, v2) == 2.0f);
|
||||||
|
|
||||||
|
// Test floor and round
|
||||||
|
Vec2 v5(1.7f, -2.3f);
|
||||||
|
auto f = v5.floor();
|
||||||
|
auto r = v5.round();
|
||||||
|
assert(f == std::make_tuple(1, -3));
|
||||||
|
assert(r == std::make_tuple(2, -2));
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user