feat: implement Vec2 class with basic operations and tests

Signed-off-by: szdytom <szdytom@qq.com>
This commit is contained in:
方而静 2025-08-04 16:18:56 +08:00
parent e1d3725b87
commit f8a2b0c9eb
Signed by: szTom
GPG Key ID: 072D999D60C6473C
5 changed files with 322 additions and 4 deletions

View File

@ -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/")

View 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
View 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

View File

@ -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
View 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;
}