Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
c7919a0928 | |||
db7078ff46 | |||
0d4255e759 | |||
9ecb64a2fe | |||
2886bbb397 | |||
966f6fc77d | |||
1bbe237510 | |||
d3527ab32c | |||
e4dd7058e1 | |||
3259a8e980 | |||
b17e49d1df | |||
16419b2476 | |||
1285b85fbd | |||
0f5070783e | |||
28f87dd189 | |||
21f809481d | |||
7af631d7e5 | |||
51d51a9cc7 | |||
b161250052 | |||
073b1518fe | |||
b4e3bf4a7d | |||
2bd27c5f3e | |||
7e5207d194 | |||
152e5f4ebd | |||
179bf277b5 | |||
c5b843f086 | |||
75e2229126 | |||
7592dcdd39 | |||
0460aede0d | |||
777601a7c7 | |||
8e8a0a37d4 | |||
174f6068e7 | |||
1a5737a356 | |||
437113437f | |||
250c745969 | |||
245c6c6eb4 | |||
|
58bd078b05 | ||
4cbfef1706 | |||
43191a9857 |
@@ -39,7 +39,7 @@ CPMAddPackage(
|
|||||||
|
|
||||||
target_include_directories(J3ML PUBLIC ${jtest_SOURCE_DIR}/include)
|
target_include_directories(J3ML PUBLIC ${jtest_SOURCE_DIR}/include)
|
||||||
|
|
||||||
target_link_libraries(J3ML PUBLIC jtest)
|
target_link_libraries(J3ML PUBLIC jlog jtest)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
#target_compile_options(J3ML PRIVATE -Wno-multichar)
|
#target_compile_options(J3ML PRIVATE -Wno-multichar)
|
||||||
|
73
README.md
73
README.md
@@ -10,7 +10,7 @@ J3ML is a "Modern C++" library designed to provide comprehensive support for 3D
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* <b>Vector Operations:</b> Comprehensive support for 3D vector operations including addition, subtraction, scalar multiplication, dot product, cross product, normalization, and more.
|
* **Vector Operations:** Comprehensive support for 3D vector operations including addition, subtraction, scalar multiplication, dot product, cross product, normalization, and more.
|
||||||
* **Matrix Operations:** Efficient implementation of 3x3 and 4x4 matrices with support for common operations such as multiplication, transpose, determinant calculation, and inverse calculation.
|
* **Matrix Operations:** Efficient implementation of 3x3 and 4x4 matrices with support for common operations such as multiplication, transpose, determinant calculation, and inverse calculation.
|
||||||
* **Quaternion Operations:** Quaternion manipulation functions including conversion to/from axis-angle representation, quaternion multiplication, normalization, and interpolation (slerp).
|
* **Quaternion Operations:** Quaternion manipulation functions including conversion to/from axis-angle representation, quaternion multiplication, normalization, and interpolation (slerp).
|
||||||
* **Transformation Functions:** Functions for transforming points, vectors, and normals using matrices and quaternions.
|
* **Transformation Functions:** Functions for transforming points, vectors, and normals using matrices and quaternions.
|
||||||
@@ -18,29 +18,68 @@ J3ML is a "Modern C++" library designed to provide comprehensive support for 3D
|
|||||||
* **Algorithms:** Implementation of various algorithms including Gilbert-Johnson-Keerthi (GJK) algorithm for collision detection, random number generator, and more.
|
* **Algorithms:** Implementation of various algorithms including Gilbert-Johnson-Keerthi (GJK) algorithm for collision detection, random number generator, and more.
|
||||||
* **Utility Functions:** Additional utilities such as conversion between degrees and radians, random number generation, and common constants.
|
* **Utility Functions:** Additional utilities such as conversion between degrees and radians, random number generation, and common constants.
|
||||||
|
|
||||||
# Usage
|
## Coming Soon
|
||||||
|
|
||||||
To use J3ML in your C++ project, simply include the necessary header files and link against the library. Here's a basic example of how to use the library to perform vector addition:
|
* **SIMD:** (Single-instruction, multiple-data) utilizes a vectorized instruction set to compute operations on multiple values at once. This is particularly useful in matrix maths.
|
||||||
|
* **LUTs:** Compute Lookup-tables for common operations, and bake them into your program via constexpr. (Sin, Cos, Tan, Sqrt, FastInverseSqrt)
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
We support integration via CMake Package Manager (CPM). It's quite clean and flexible. It's a single CMake script too.
|
||||||
|
|
||||||
|
Here's what we recommend:
|
||||||
|
|
||||||
|
Install CPM.cmake to a `cmake` directory in your project root, and add the lines below into your CMakeLists.txt
|
||||||
|
|
||||||
|
To integrate the package manager:
|
||||||
|
```cmake
|
||||||
|
include("cmake/CPM.cmake")
|
||||||
|
```
|
||||||
|
|
||||||
|
To automatically download and build J3ML version 3.4.5 (Check releases for new versions!):
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME J3ML
|
||||||
|
URL https::/git.redacted.cc/josh/J3ML/archive/3.4.5.zip
|
||||||
|
)
|
||||||
|
```
|
||||||
|
Then you should be able to link J3ML to your project like any other library:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
target_include_directories(MyProgramOrLib PUBLIC ${J3ML_SOURCE_DIR}/include)
|
||||||
|
###
|
||||||
|
target_link_libraries(MyProgramOrLib PUBLIC J3ML)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Usage Samples
|
||||||
|
|
||||||
|
## 2D Vector Operations
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
#include <J3ML/LinearAlgebra.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
Vector2 position {10.f, 10.f};
|
||||||
|
Vector2 velocity {5.f, 1.5f};
|
||||||
|
float step = 1.f/60.f;
|
||||||
|
|
||||||
|
void doStep() {
|
||||||
|
position = position + (velocity * step);
|
||||||
|
velocity = velocity.Lerp(Vector2::Zero, step);
|
||||||
|
float speed = velocity.Length();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matrix3x3 and Rotation Types
|
||||||
|
|
||||||
|
```cpp
|
||||||
#include <j3ml/LinearAlgebra.h>
|
#include <j3ml/LinearAlgebra.h>
|
||||||
|
|
||||||
int main() {
|
Matrix3x3 mRotation = Matrix3x3::RotateX(Math::PiOverTwo);
|
||||||
// Create two 3D vectors
|
Quaternion qRotation(mRotation); // Convert to Quaternion
|
||||||
Vector3 v1(1.0, 2.0, 3.0);
|
AxisAngle aRotation(qRotation); // Convert to AxisAngle
|
||||||
Vector3 v2(4.0, 5.0, 6.0);
|
EulerAngleXYZ eRotation(aRotation); // Convert to Euler Angle (XYZ)
|
||||||
|
|
||||||
// Perform vector addition
|
|
||||||
Vector3 result = v1 + v2;
|
|
||||||
|
|
||||||
// Output the result
|
|
||||||
std::cout << "Result: " << result << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For more detailed usage instructions and examples, please refer to the documentation.
|
For more detailed usage instructions and examples, please refer to the documentation.
|
||||||
|
@@ -7,8 +7,7 @@
|
|||||||
|
|
||||||
/// @file AABB2D.hpp
|
/// @file AABB2D.hpp
|
||||||
/// @desc A 2D Axis-Aligned Bounding Box structure.
|
/// @desc A 2D Axis-Aligned Bounding Box structure.
|
||||||
/// @edit 2024-08-01
|
/// @edit 2025-04-18
|
||||||
/// @note On backlog, low-priority.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@@ -23,8 +22,6 @@
|
|||||||
template <typename Matrix>
|
template <typename Matrix>
|
||||||
void AABB2DTransformAsAABB2D(AABB2D& aabb, Matrix& m);
|
void AABB2DTransformAsAABB2D(AABB2D& aabb, Matrix& m);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace J3ML::Geometry
|
namespace J3ML::Geometry
|
||||||
{
|
{
|
||||||
using LinearAlgebra::Vector2;
|
using LinearAlgebra::Vector2;
|
||||||
@@ -46,7 +43,7 @@ namespace J3ML::Geometry
|
|||||||
[[nodiscard]] float Width() const;
|
[[nodiscard]] float Width() const;
|
||||||
[[nodiscard]] float Height() const;
|
[[nodiscard]] float Height() const;
|
||||||
|
|
||||||
Vector2 Centroid();
|
Vector2 Centroid() const;
|
||||||
|
|
||||||
[[nodiscard]] float DistanceSq(const Vector2& pt) const;
|
[[nodiscard]] float DistanceSq(const Vector2& pt) const;
|
||||||
|
|
||||||
|
@@ -149,11 +149,8 @@ namespace J3ML::Geometry
|
|||||||
is because the Frustum class implements a caching mechanism where world, projection and viewProj matrices are recomputed on demand, which does not work nicely together
|
is because the Frustum class implements a caching mechanism where world, projection and viewProj matrices are recomputed on demand, which does not work nicely together
|
||||||
if the defaults were uninitialized. */
|
if the defaults were uninitialized. */
|
||||||
Frustum();
|
Frustum();
|
||||||
|
|
||||||
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
/// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
|
/// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
|
||||||
[[nodiscard]] Vector3 AnyPointFast() const { return CornerPoint(0); }
|
[[nodiscard]] Vector3 AnyPointFast() const { return CornerPoint(0); }
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ namespace J3ML::Geometry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AABB2D ComputeAABB() {}
|
AABB2D ComputeAABB() { return AABB2D(); }
|
||||||
|
|
||||||
float DistanceSq(const Vector2 &point) const {
|
float DistanceSq(const Vector2 &point) const {
|
||||||
Vector2 centered = point - center;
|
Vector2 centered = point - center;
|
||||||
|
86
include/J3ML/Geometry/Rect2D.hpp
Normal file
86
include/J3ML/Geometry/Rect2D.hpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/// Josh's 3D Math Library
|
||||||
|
/// A C++20 Library for 3D Math, Computer Graphics, and Scientific Computing.
|
||||||
|
/// Developed and Maintained by Josh O'Leary @ Redacted Software.
|
||||||
|
/// Special Thanks to William Tomasine II and Maxine Hayes.
|
||||||
|
/// (c) 2024 Redacted Software
|
||||||
|
/// This work is dedicated to the public domain.
|
||||||
|
|
||||||
|
/// @file Rect2D.hpp
|
||||||
|
/// @desc A 2D AABB, represented by a top-left origin, and a w,h size.
|
||||||
|
/// @edit 2025-04-18
|
||||||
|
/// @note On backlog, low-priority.
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||||
|
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||||
|
#include <J3ML/Geometry/Forward.hpp>
|
||||||
|
#include <J3ML/Geometry/AABB2D.hpp>
|
||||||
|
namespace J3ML::Geometry
|
||||||
|
{
|
||||||
|
|
||||||
|
/// A specialized type of 2D AABB structure, which represents a box from it's top-left point, and a size as width and height.
|
||||||
|
/// This is more natural for manipulation in 2D games, for bounding-boxes, sprite-quads, etc.
|
||||||
|
struct Rect2D {
|
||||||
|
/// The top-left origin point of this Rect2D.
|
||||||
|
Vector2 position;
|
||||||
|
/// The width and height of this Rect2D.
|
||||||
|
Vector2 size;
|
||||||
|
|
||||||
|
/// Constructs a Rect2D from a given Vector2 position, and size.
|
||||||
|
Rect2D(const Vector2& pos, const Vector2& size);
|
||||||
|
/// Constructs a Rect2D from a given position {x, y}, and size {w, h}
|
||||||
|
/// @param x The X-axis of the position.
|
||||||
|
/// @param y The Y-axis of the position.
|
||||||
|
/// @param w The width of the Rect2D.
|
||||||
|
/// @param h The height of the Rect2D.
|
||||||
|
Rect2D(float x, float y, float w, float h);
|
||||||
|
/// Constructs a Rect2D from a desired centroid, and a Vector2 specifying half-width, and half-height.
|
||||||
|
static Rect2D FromCentroidAndRadii(const Vector2& centroid, const Vector2& radii);
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] float HorizontalRadius() const;
|
||||||
|
[[nodiscard]] float VerticalRadius() const;
|
||||||
|
[[nodiscard]] float HalfWidth() const;
|
||||||
|
[[nodiscard]] float HalfHeight() const;
|
||||||
|
[[nodiscard]] Vector2 Centroid() const;
|
||||||
|
[[nodiscard]] float Width() const;
|
||||||
|
[[nodiscard]] float Height() const;
|
||||||
|
[[nodiscard]] Vector2 MinPoint() const;
|
||||||
|
[[nodiscard]] Vector2 MaxPoint() const;
|
||||||
|
[[nodiscard]] AABB2D GetAsAABB() const;
|
||||||
|
|
||||||
|
float Area() const { return size.x * size.y;}
|
||||||
|
float Perimeter() const { return 2.f * (size.x + size.y); }
|
||||||
|
|
||||||
|
bool Intersects(const Rect2D& rhs) const;
|
||||||
|
bool Intersects(const AABB2D& rhs) const;
|
||||||
|
bool Contains(const Vector2& rhs) const;
|
||||||
|
bool Contains(int x, int y) const;
|
||||||
|
|
||||||
|
Vector2 PosInside(const Vector2 &normalizedPos) const;
|
||||||
|
|
||||||
|
Vector2 ToNormalizedLocalSpace(const Vector2 &pt) const;
|
||||||
|
|
||||||
|
Vector2 CornerPoint(int cornerIndex);
|
||||||
|
|
||||||
|
bool IsDegenerate() const;
|
||||||
|
bool HasNegativeVolume() const;
|
||||||
|
bool IsFinite() const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Rect2D operator + (const Vector2& pt) const;
|
||||||
|
Rect2D& operator + (const Vector2& pt);
|
||||||
|
Rect2D operator - (const Vector2& pt) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Rect2Di {
|
||||||
|
Vector2i position;
|
||||||
|
Vector2i size;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
/// This set of functions may be set to use lookup tables or SIMD operations.
|
/// This set of functions may be set to use lookup tables or SIMD operations.
|
||||||
/// If no options are set, they will default to using standard library implementation.
|
/// If no options are set, they will default to using standard library implementation.
|
||||||
#define USE_LOOKUP_TABLES /// Pre-computed lookup tables.
|
#undef USE_LOOKUP_TABLES /// Pre-computed lookup tables.
|
||||||
#undef USE_SSE /// Streaming SIMD Extensions (x86)
|
#undef USE_SSE /// Streaming SIMD Extensions (x86)
|
||||||
#undef USE_NEON /// ARM Vector Processing
|
#undef USE_NEON /// ARM Vector Processing
|
||||||
#undef USE_AVX /// Advanced Vector Extensions (x86)
|
#undef USE_AVX /// Advanced Vector Extensions (x86)
|
||||||
@@ -165,7 +165,7 @@ namespace J3ML::BitTwiddling {
|
|||||||
u32 BinaryStringToValue(const char* s);
|
u32 BinaryStringToValue(const char* s);
|
||||||
|
|
||||||
/// Returns the number of 1's set in the given value.
|
/// Returns the number of 1's set in the given value.
|
||||||
inline int CountBitsSet(u32 value);
|
//inline int CountBitsSet(u32 value);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace J3ML::Math {
|
namespace J3ML::Math {
|
||||||
@@ -382,10 +382,6 @@ namespace J3ML::Math::Functions {
|
|||||||
/// 2241 -> 2.2k, 55421 -> 55.4k, 1000000 -> 1.0M
|
/// 2241 -> 2.2k, 55421 -> 55.4k, 1000000 -> 1.0M
|
||||||
std::string Truncate(float input);
|
std::string Truncate(float input);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float RecipFast(float x);
|
float RecipFast(float x);
|
||||||
|
|
||||||
|
|
||||||
@@ -441,13 +437,23 @@ namespace J3ML::Math::Functions {
|
|||||||
/// Returns the fractional part of x.
|
/// Returns the fractional part of x.
|
||||||
/** @see Lerp(), LerpMod(), InvLerp(), Step(), SmoothStep(), PingPongMod(), Mod(), ModPos(). */
|
/** @see Lerp(), LerpMod(), InvLerp(), Step(), SmoothStep(), PingPongMod(), Mod(), ModPos(). */
|
||||||
float Frac(float x);
|
float Frac(float x);
|
||||||
float Sqrt(float x); /// Returns the square root of x.
|
/// Returns the square root of x.
|
||||||
float FastSqrt(float x); /// Computes a fast approximation of the square root of x.
|
float Sqrt(float x);
|
||||||
float RSqrt(float x); /// Returns 1/Sqrt(x). (The reciprocal of the square root of x)
|
/// Computes a fast approximation of the square root of x.
|
||||||
float FastRSqrt(float x); /// SSE implementation of reciprocal square root.
|
float FastSqrt(float x);
|
||||||
float Recip(float x); /// Returns 1/x, the reciprocal of x.
|
/// Returns 1/Sqrt(x). (The reciprocal of the square root of x)
|
||||||
float RecipFast(float x); /// Returns 1/x, the reciprocal of x, using a fast approximation (SSE rcp instruction).
|
float RSqrt(float x);
|
||||||
|
/// SSE implementation of reciprocal square root.
|
||||||
|
float FastRSqrt(float x);
|
||||||
|
/// Returns 1/x, the reciprocal of x.
|
||||||
|
float Recip(float x);
|
||||||
|
/// Returns 1/x, the reciprocal of x, using a fast approximation (SSE rcp instruction).
|
||||||
|
float RecipFast(float x);
|
||||||
|
/// Carmack (Quake) implementation of inverse (reciprocal) square root.
|
||||||
|
/// Relies on funky type-casting hacks to avoid floating-point division and sqrt, which is very slow on legacy hardware.
|
||||||
|
/// This technique is superseded by modern processors having built-in support, but is included for its historical significance.
|
||||||
|
/// https://en.wikipedia.org/wiki/Fast_inverse_square_root
|
||||||
|
float QRSqrt(float x);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace J3ML::Math::Functions::Interpolation
|
namespace J3ML::Math::Functions::Interpolation
|
||||||
@@ -476,28 +482,5 @@ namespace J3ML::Math::Types {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace J3ML::Math {
|
|
||||||
struct Rotation {
|
|
||||||
Rotation();
|
|
||||||
Rotation(float value);
|
|
||||||
Rotation(const Types::Radians& radians);
|
|
||||||
|
|
||||||
Rotation(const Types::Degrees& degrees);
|
|
||||||
|
|
||||||
float valueInRadians;
|
|
||||||
float ValueInRadians() const { return valueInRadians; }
|
|
||||||
Types::Radians Radians() const { return {valueInRadians}; }
|
|
||||||
float Degrees() const { return Functions::Degrees(valueInRadians); }
|
|
||||||
|
|
||||||
Rotation operator+(const Rotation& rhs);
|
|
||||||
};
|
|
||||||
|
|
||||||
Rotation operator ""_rad(long double rads);
|
|
||||||
|
|
||||||
Rotation operator ""_radians(long double rads);
|
|
||||||
|
|
||||||
Rotation operator ""_deg(long double rads);
|
|
||||||
|
|
||||||
Rotation operator ""_degrees(long double rads);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
//// Dawsh Linear Algebra Library - Everything you need for 3D math
|
//// Dawsh Linear Algebra Library - Everything you need for 3D math
|
||||||
/// @file LinearAlgebra.h
|
/// @file LinearAlgebra.hpp
|
||||||
/// @description Includes all LinearAlgebra classes and functions
|
/// @description Includes all LinearAlgebra classes and functions
|
||||||
/// @author Josh O'Leary, William Tomasine II
|
/// @author Josh O'Leary, William Tomasine II
|
||||||
/// @copyright 2024 Redacted Software
|
/// @copyright 2024 Redacted Software
|
||||||
@@ -9,22 +9,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// TODO: Enforce Style Consistency (Function Names use MicroSoft Case)
|
|
||||||
// TODO: Implement Templated Linear Algebra
|
|
||||||
|
|
||||||
|
|
||||||
// Library Code //
|
|
||||||
|
|
||||||
#include "J3ML/LinearAlgebra/Vector2.hpp"
|
#include "J3ML/LinearAlgebra/Vector2.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Vector3.hpp"
|
#include "J3ML/LinearAlgebra/Vector3.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Vector4.hpp"
|
#include "J3ML/LinearAlgebra/Vector4.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Quaternion.hpp"
|
#include "J3ML/LinearAlgebra/Quaternion.hpp"
|
||||||
#include "J3ML/LinearAlgebra/AxisAngle.hpp"
|
#include "J3ML/LinearAlgebra/AxisAngle.hpp"
|
||||||
#include "J3ML/LinearAlgebra/EulerAngle.hpp"
|
|
||||||
#include "J3ML/LinearAlgebra/Matrix2x2.hpp"
|
#include "J3ML/LinearAlgebra/Matrix2x2.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Matrix3x3.hpp"
|
#include "J3ML/LinearAlgebra/Matrix3x3.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Matrix4x4.hpp"
|
#include "J3ML/LinearAlgebra/Matrix4x4.hpp"
|
||||||
#include "J3ML/LinearAlgebra/Transform2D.hpp"
|
#include "J3ML/LinearAlgebra/Transform2D.hpp"
|
||||||
#include "J3ML/LinearAlgebra/CoordinateFrame.hpp"
|
#include "J3ML/LinearAlgebra/Vector2i.hpp"
|
||||||
|
|
||||||
using namespace J3ML::LinearAlgebra;
|
using namespace J3ML::LinearAlgebra;
|
||||||
|
@@ -1,24 +1,73 @@
|
|||||||
|
//// Dawsh Linear Algebra Library - Everything you need for 3D math
|
||||||
|
/// @file AxisAngle.hpp
|
||||||
|
/// @description Defines the AxisAngle class for representing rotations.
|
||||||
|
/// @author Josh O'Leary, William Tomasine II
|
||||||
|
/// @copyright 2025 Redacted Software
|
||||||
|
/// @license Unlicense - Public Domain
|
||||||
|
/// @edited 2025-03-04
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||||
|
#include <J3ML/LinearAlgebra/Forward.hpp>
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
namespace J3ML::LinearAlgebra {
|
||||||
class AxisAngle;
|
class AxisAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transitional datatype, not useful for internal representation of rotation
|
/// @class AxisAngle
|
||||||
/// But has uses for conversion and manipulation.
|
/// @brief Represents a rotation using an axis and an angle.
|
||||||
|
/// This class encapsulates a rotation in 3D space using an axis-angle representation.
|
||||||
|
/// It provides methods for converting between AxisAngle and other rotation representations,
|
||||||
|
/// as well as interpolation and other useful rotation operations.
|
||||||
|
/// @note There are many different ways you can represent a rotation in 3D space,
|
||||||
|
/// and we provide some of the more common types.
|
||||||
|
/// @see class Matrix3x3, class Quaternion
|
||||||
class J3ML::LinearAlgebra::AxisAngle {
|
class J3ML::LinearAlgebra::AxisAngle {
|
||||||
public:
|
public:
|
||||||
|
/// The
|
||||||
Vector3 axis;
|
Vector3 axis;
|
||||||
// Radians.
|
/// Radians.
|
||||||
float angle;
|
float angle;
|
||||||
public:
|
public:
|
||||||
AxisAngle();
|
/// The default constructor does not initialize any member values.
|
||||||
|
AxisAngle() = default;
|
||||||
|
/// Returns an AxisAngle created by converting from the given Quaternions rotation representation.
|
||||||
explicit AxisAngle(const Quaternion& q);
|
explicit AxisAngle(const Quaternion& q);
|
||||||
explicit AxisAngle(const EulerAngleXYZ& e);
|
/// This constructor derives the Quaternion equivalent of the given matrix, and converts that to AxisAngle representation.
|
||||||
|
explicit AxisAngle(const Matrix3x3& m);
|
||||||
AxisAngle(const Vector3& axis, float angle);
|
AxisAngle(const Vector3& axis, float angle);
|
||||||
|
|
||||||
|
[[nodiscard]] Quaternion ToQuaternion() const;
|
||||||
|
[[nodiscard]] Matrix3x3 ToMatrix3x3() const;
|
||||||
|
|
||||||
|
/// Returns the axis component of this AxisAngle rotation.
|
||||||
|
Vector3 Axis() const;
|
||||||
|
float Angle() const;
|
||||||
|
|
||||||
|
/// Normalize this rotation in-place.
|
||||||
|
void Normalize();
|
||||||
|
/// Return a normalized copy of this rotation.
|
||||||
|
[[nodiscard]] AxisAngle Normalized() const;
|
||||||
|
|
||||||
|
/// Checks if the rotation is an identity rotation (angle is 0).
|
||||||
|
bool IsIdentity();
|
||||||
|
|
||||||
|
/// Inverts this rotation in-place.
|
||||||
|
void Inverse();
|
||||||
|
|
||||||
|
/// Returns an inverted copy of this rotation.
|
||||||
|
[[nodiscard]] AxisAngle Inverted() const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Performs a direct Linear Interpolation on the members of the inputs.
|
||||||
|
AxisAngle Lerp(const AxisAngle& rhs, float t);
|
||||||
|
|
||||||
|
/// Performs a Spherical Linear Interpolation by converting the inputs to Quaternions.
|
||||||
|
AxisAngle Slerp(const AxisAngle& rhs, float t);
|
||||||
|
|
||||||
|
|
||||||
|
bool Equals(const AxisAngle& rhs, float epsilon = 1e-3f);
|
||||||
|
bool operator == (const AxisAngle& rhs);
|
||||||
|
|
||||||
};
|
};
|
@@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra
|
|
||||||
{
|
|
||||||
/// The CFrame is fundamentally 4 vectors (position, forward, right, up vector)
|
|
||||||
class CoordinateFrame
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Vector3 Position;
|
|
||||||
Vector3 Front;
|
|
||||||
Vector3 Right;
|
|
||||||
Vector3 Up;
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
|
||||||
class DirectionVectorRH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Direction vector of a given Matrix3x3 RotationMatrix in a Right-handed coordinate space.
|
|
||||||
class J3ML::LinearAlgebra::DirectionVectorRH : public Vector3 {
|
|
||||||
private:
|
|
||||||
// This is purposefully not exposed because these types aren't usually convertable.
|
|
||||||
explicit DirectionVectorRH(const Vector3& rhs);
|
|
||||||
public:
|
|
||||||
static DirectionVectorRH Forward(const Matrix3x3& rhs);
|
|
||||||
static DirectionVectorRH Backward(const Matrix3x3& rhs);
|
|
||||||
static DirectionVectorRH Left(const Matrix3x3& rhs);
|
|
||||||
static DirectionVectorRH Right(const Matrix3x3& rhs);
|
|
||||||
static DirectionVectorRH Up(const Matrix3x3& rhs);
|
|
||||||
static DirectionVectorRH Down(const Matrix3x3& rhs);
|
|
||||||
};
|
|
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
|
||||||
class EulerAngleXYZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
class J3ML::LinearAlgebra::EulerAngleXYZ {
|
|
||||||
public:
|
|
||||||
public:
|
|
||||||
float roll = 0; // X
|
|
||||||
float pitch = 0; // Y
|
|
||||||
float yaw = 0; // Z
|
|
||||||
public:
|
|
||||||
EulerAngleXYZ(float roll, float pitch, float yaw);
|
|
||||||
public:
|
|
||||||
explicit EulerAngleXYZ(const Quaternion& rhs);
|
|
||||||
explicit EulerAngleXYZ(const AxisAngle& rhs);
|
|
||||||
explicit EulerAngleXYZ(const Matrix3x3& rhs);
|
|
||||||
};
|
|
@@ -8,7 +8,6 @@ namespace J3ML::LinearAlgebra
|
|||||||
class Vector3; // A type representing a position in a 3-dimensional coordinate space.
|
class Vector3; // A type representing a position in a 3-dimensional coordinate space.
|
||||||
class Vector4; // A type representing a position in a 4-dimensional coordinate space.
|
class Vector4; // A type representing a position in a 4-dimensional coordinate space.
|
||||||
class Angle2D; // Uses x,y components to represent a 2D rotation.
|
class Angle2D; // Uses x,y components to represent a 2D rotation.
|
||||||
class EulerAngleXYZ; // Uses pitch,yaw,roll components to represent a 3D orientation.
|
|
||||||
class AxisAngle; //
|
class AxisAngle; //
|
||||||
class CoordinateFrame; //
|
class CoordinateFrame; //
|
||||||
class Matrix2x2;
|
class Matrix2x2;
|
||||||
|
@@ -15,6 +15,9 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <ranges>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
#include "Vector.hpp"
|
#include "Vector.hpp"
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra
|
namespace J3ML::LinearAlgebra
|
||||||
@@ -22,8 +25,8 @@ namespace J3ML::LinearAlgebra
|
|||||||
|
|
||||||
|
|
||||||
template <uint ROWS, uint COLS, typename T>
|
template <uint ROWS, uint COLS, typename T>
|
||||||
class Matrix
|
class Matrix {
|
||||||
{
|
public:
|
||||||
static constexpr uint Diag = std::min(ROWS, COLS);
|
static constexpr uint Diag = std::min(ROWS, COLS);
|
||||||
|
|
||||||
using RowVector = Vector<ROWS, T>;
|
using RowVector = Vector<ROWS, T>;
|
||||||
@@ -33,6 +36,22 @@ namespace J3ML::LinearAlgebra
|
|||||||
enum { Rows = ROWS };
|
enum { Rows = ROWS };
|
||||||
enum { Cols = COLS };
|
enum { Cols = COLS };
|
||||||
|
|
||||||
|
|
||||||
|
Matrix(std::initializer_list<T> arg) {
|
||||||
|
int iterator = 0;
|
||||||
|
for (T entry : arg) {
|
||||||
|
int x = iterator % ROWS;
|
||||||
|
int y = iterator / ROWS;
|
||||||
|
|
||||||
|
elems[x][y] = entry;
|
||||||
|
|
||||||
|
iterator++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix(const std::vector<T>& entries);
|
||||||
|
Matrix(const std::vector<RowVector>& rows);
|
||||||
|
|
||||||
void AssertRowSize(uint rows)
|
void AssertRowSize(uint rows)
|
||||||
{
|
{
|
||||||
assert(rows < Rows && "");
|
assert(rows < Rows && "");
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
|
||||||
#include <J3ML/Algorithm/RNG.hpp>
|
#include <J3ML/Algorithm/RNG.hpp>
|
||||||
|
|
||||||
using namespace J3ML::Algorithm;
|
using namespace J3ML::Algorithm;
|
||||||
@@ -62,11 +61,9 @@ namespace J3ML::LinearAlgebra {
|
|||||||
Matrix3x3(const Vector3& col0, const Vector3& col1, const Vector3& col2);
|
Matrix3x3(const Vector3& col0, const Vector3& col1, const Vector3& col2);
|
||||||
/// Constructs this matrix3x3 from the given quaternion.
|
/// Constructs this matrix3x3 from the given quaternion.
|
||||||
explicit Matrix3x3(const Quaternion& orientation);
|
explicit Matrix3x3(const Quaternion& orientation);
|
||||||
/// Constructs this matrix3x3 from the given euler angle.
|
|
||||||
|
|
||||||
//explicit Matrix3x3(const EulerAngleXYZ& orientation);
|
|
||||||
|
|
||||||
//explicit Matrix3x3(const AxisAngle& orientation);
|
//explicit Matrix3x3(const AxisAngle& orientation);
|
||||||
|
explicit Matrix3x3(const AxisAngle& orientation) : Matrix3x3(Quaternion(orientation)) {};
|
||||||
|
|
||||||
/// Constructs this Matrix3x3 from a pointer to an array of floats.
|
/// Constructs this Matrix3x3 from a pointer to an array of floats.
|
||||||
explicit Matrix3x3(const float *data);
|
explicit Matrix3x3(const float *data);
|
||||||
@@ -161,6 +158,14 @@ namespace J3ML::LinearAlgebra {
|
|||||||
/// Sets this matrix to perform the rotation expressed by the given quaternion.
|
/// Sets this matrix to perform the rotation expressed by the given quaternion.
|
||||||
void SetRotatePart(const Quaternion& quat);
|
void SetRotatePart(const Quaternion& quat);
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 ForwardDir() const;
|
||||||
|
Vector3 BackwardDir() const;
|
||||||
|
Vector3 LeftDir() const;
|
||||||
|
Vector3 RightDir() const;
|
||||||
|
Vector3 UpDir() const;
|
||||||
|
Vector3 DownDir() const;
|
||||||
|
|
||||||
/// Returns the given row.
|
/// Returns the given row.
|
||||||
/** @param row The zero-based index [0, 2] of the row to get. */
|
/** @param row The zero-based index [0, 2] of the row to get. */
|
||||||
Vector3 GetRow(int index) const;
|
Vector3 GetRow(int index) const;
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
#include <J3ML/Algorithm/RNG.hpp>
|
#include <J3ML/Algorithm/RNG.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <bits/ostream.tcc>
|
||||||
|
|
||||||
using namespace J3ML::Algorithm;
|
using namespace J3ML::Algorithm;
|
||||||
|
|
||||||
@@ -569,10 +571,15 @@ namespace J3ML::LinearAlgebra {
|
|||||||
/// Returns true if this Matrix4x4 is equal to the given Matrix4x4, up to given per-element epsilon.
|
/// Returns true if this Matrix4x4 is equal to the given Matrix4x4, up to given per-element epsilon.
|
||||||
bool Equals(const Matrix4x4& other, float epsilon = 1e-3f) const;
|
bool Equals(const Matrix4x4& other, float epsilon = 1e-3f) const;
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] std::string ToString() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float elems[4][4];
|
float elems[4][4];
|
||||||
|
|
||||||
|
|
||||||
Vector3 TransformDir(float tx, float ty, float tz) const;
|
Vector3 TransformDir(float tx, float ty, float tz) const;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
std::ostream& operator << (std::ostream& out, const Matrix4x4& rhs);
|
||||||
|
}
|
||||||
|
@@ -25,18 +25,22 @@ public:
|
|||||||
public:
|
public:
|
||||||
/// The default constructor does not initialize any member values.
|
/// The default constructor does not initialize any member values.
|
||||||
Quaternion() = default;
|
Quaternion() = default;
|
||||||
|
|
||||||
/// Copy constructor
|
/// Copy constructor
|
||||||
Quaternion(const Quaternion &rhs);
|
Quaternion(const Quaternion &rhs);
|
||||||
|
|
||||||
/// Quaternion from Matrix3x3
|
/// Quaternion from Matrix3x3
|
||||||
explicit Quaternion(const Matrix3x3& ro_mat);
|
explicit Quaternion(const Matrix3x3 &ro_mat);
|
||||||
|
|
||||||
/// Quaternion from Matrix4x4 RotatePart.
|
/// Quaternion from Matrix4x4 RotatePart.
|
||||||
explicit Quaternion(const Matrix4x4& ro_mat);
|
explicit Quaternion(const Matrix4x4 &ro_mat);
|
||||||
/// Quaternion from EulerAngleXYZ.
|
|
||||||
explicit Quaternion(const EulerAngleXYZ& rhs);
|
|
||||||
/// Quaternion from AxisAngle.
|
/// Quaternion from AxisAngle.
|
||||||
explicit Quaternion(const AxisAngle& angle);
|
explicit Quaternion(const AxisAngle &angle);
|
||||||
|
|
||||||
/// Quaternion from Vector4 (no conversion).
|
/// Quaternion from Vector4 (no conversion).
|
||||||
explicit Quaternion(const Vector4& vector4);
|
explicit Quaternion(const Vector4 &vector4);
|
||||||
|
|
||||||
/// @param x The factor of i.
|
/// @param x The factor of i.
|
||||||
/// @param y The factor of j.
|
/// @param y The factor of j.
|
||||||
@@ -71,33 +75,39 @@ public:
|
|||||||
quaternion Q it holds that M * localForward = targetDirection, and M * localUp lies in the plane spanned
|
quaternion Q it holds that M * localForward = targetDirection, and M * localUp lies in the plane spanned
|
||||||
by the vectors targetDirection and worldUp.
|
by the vectors targetDirection and worldUp.
|
||||||
@see RotateFromTo() */
|
@see RotateFromTo() */
|
||||||
static Quaternion LookAt(const Vector3& localForward, const Vector3& targetDirection, const Vector3& localUp, const Vector3& worldUp);
|
static Quaternion LookAt(const Vector3 &localForward, const Vector3 &targetDirection, const Vector3 &localUp, const Vector3 &worldUp);
|
||||||
|
|
||||||
/// Creates a new quaternion that rotates about the positive X axis by the given rotation.
|
/// Creates a new quaternion that rotates about the positive X axis by the given rotation.
|
||||||
static Quaternion RotateX(float rad);
|
static Quaternion RotateX(float rad);
|
||||||
/// Creates a new quaternion that rotates about the positive Y axis by the given rotation.
|
|
||||||
static Quaternion RotateY(float rad);
|
|
||||||
/// Creates a new quaternion that rotates about the positive Z axis by the given rotation.
|
|
||||||
static Quaternion RotateZ(float rad);
|
|
||||||
|
|
||||||
/// Creates a new quaternion that rotates sourceDirection vector (in world space) to coincide with the
|
/// Creates a new quaternion that rotates about the positive Y axis by the given rotation.
|
||||||
/// targetDirection vector (in world space).
|
static Quaternion RotateY(float rad);
|
||||||
/// Rotation is performed about the origin.
|
|
||||||
/// The vectors sourceDirection and targetDirection are assumed to be normalized.
|
|
||||||
/// @note There are multiple such rotations - this function returns the rotation that has the shortest angle
|
|
||||||
/// (when decomposed to axis-angle notation).
|
|
||||||
static Quaternion RotateFromTo(const Vector3& sourceDirection, const Vector3& targetDirection);
|
|
||||||
static Quaternion RotateFromTo(const Vector4& sourceDirection, const Vector4& targetDirection);
|
|
||||||
|
|
||||||
/// Creates a new quaternion that
|
/// Creates a new quaternion that rotates about the positive Z axis by the given rotation.
|
||||||
/// 1. rotates sourceDirection vector to coincide with the targetDirection vector, and then
|
static Quaternion RotateZ(float rad);
|
||||||
/// 2. rotates sourceDirection2 (which was transformed by 1.) to targetDirection2, but keeping the constraint that
|
|
||||||
/// sourceDirection must look at targetDirection
|
/// Creates a new quaternion that rotates sourceDirection vector (in world space) to coincide with the
|
||||||
static Quaternion RotateFromTo(const Vector3& sourceDirection, const Vector3& targetDirection, const Vector3& sourceDirection2, const Vector3& targetDirection2);
|
/// targetDirection vector (in world space).
|
||||||
|
/// Rotation is performed about the origin.
|
||||||
|
/// The vectors sourceDirection and targetDirection are assumed to be normalized.
|
||||||
|
/// @note There are multiple such rotations - this function returns the rotation that has the shortest angle
|
||||||
|
/// (when decomposed to axis-angle notation).
|
||||||
|
static Quaternion RotateFromTo(const Vector3 &sourceDirection, const Vector3 &targetDirection);
|
||||||
|
|
||||||
|
static Quaternion RotateFromTo(const Vector4 &sourceDirection, const Vector4 &targetDirection);
|
||||||
|
|
||||||
|
/// Creates a new quaternion that
|
||||||
|
/// 1. rotates sourceDirection vector to coincide with the targetDirection vector, and then
|
||||||
|
/// 2. rotates sourceDirection2 (which was transformed by 1.) to targetDirection2, but keeping the constraint that
|
||||||
|
/// sourceDirection must look at targetDirection
|
||||||
|
static Quaternion
|
||||||
|
RotateFromTo(const Vector3 &sourceDirection, const Vector3 &targetDirection, const Vector3 &sourceDirection2,
|
||||||
|
const Vector3 &targetDirection2);
|
||||||
|
|
||||||
|
|
||||||
/// Returns a uniformly random unitary quaternion.
|
/// Returns a uniformly random unitary quaternion.
|
||||||
static Quaternion RandomRotation(RNG &rng);
|
static Quaternion RandomRotation(RNG &rng);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Inverses this quaternion in-place.
|
/// Inverses this quaternion in-place.
|
||||||
/// @note For optimization purposes, this function assumes that the quaternion is unitary, in which
|
/// @note For optimization purposes, this function assumes that the quaternion is unitary, in which
|
||||||
@@ -107,8 +117,10 @@ public:
|
|||||||
|
|
||||||
/// Returns an inverted copy of this quaternion.
|
/// Returns an inverted copy of this quaternion.
|
||||||
[[nodiscard]] Quaternion Inverted() const;
|
[[nodiscard]] Quaternion Inverted() const;
|
||||||
|
|
||||||
/// Computes the conjugate of this quaternion in-place.
|
/// Computes the conjugate of this quaternion in-place.
|
||||||
void Conjugate();
|
void Conjugate();
|
||||||
|
|
||||||
/// Returns a conjugated copy of this quaternion.
|
/// Returns a conjugated copy of this quaternion.
|
||||||
[[nodiscard]] Quaternion Conjugated() const;
|
[[nodiscard]] Quaternion Conjugated() const;
|
||||||
|
|
||||||
@@ -121,10 +133,13 @@ public:
|
|||||||
|
|
||||||
/// Returns the local +X axis in the post-transformed coordinate space. This is the same as transforming the vector (1,0,0) by this quaternion.
|
/// Returns the local +X axis in the post-transformed coordinate space. This is the same as transforming the vector (1,0,0) by this quaternion.
|
||||||
[[nodiscard]] Vector3 WorldX() const;
|
[[nodiscard]] Vector3 WorldX() const;
|
||||||
|
|
||||||
/// Returns the local +Y axis in the post-transformed coordinate space. This is the same as transforming the vector (0,1,0) by this quaternion.
|
/// Returns the local +Y axis in the post-transformed coordinate space. This is the same as transforming the vector (0,1,0) by this quaternion.
|
||||||
[[nodiscard]] Vector3 WorldY() const;
|
[[nodiscard]] Vector3 WorldY() const;
|
||||||
|
|
||||||
/// Returns the local +Z axis in the post-transformed coordinate space. This is the same as transforming the vector (0,0,1) by this quaternion.
|
/// Returns the local +Z axis in the post-transformed coordinate space. This is the same as transforming the vector (0,0,1) by this quaternion.
|
||||||
[[nodiscard]] Vector3 WorldZ() const;
|
[[nodiscard]] Vector3 WorldZ() const;
|
||||||
|
|
||||||
/// Returns the axis of rotation for this quaternion.
|
/// Returns the axis of rotation for this quaternion.
|
||||||
[[nodiscard]] Vector3 Axis() const;
|
[[nodiscard]] Vector3 Axis() const;
|
||||||
|
|
||||||
@@ -132,23 +147,31 @@ public:
|
|||||||
[[nodiscard]] float Angle() const;
|
[[nodiscard]] float Angle() const;
|
||||||
|
|
||||||
[[nodiscard]] float LengthSquared() const;
|
[[nodiscard]] float LengthSquared() const;
|
||||||
|
|
||||||
[[nodiscard]] float Length() const;
|
[[nodiscard]] float Length() const;
|
||||||
|
|
||||||
[[nodiscard]] Matrix3x3 ToMatrix3x3() const;
|
[[nodiscard]] Matrix3x3 ToMatrix3x3() const;
|
||||||
|
|
||||||
[[nodiscard]] Matrix4x4 ToMatrix4x4() const;
|
[[nodiscard]] Matrix4x4 ToMatrix4x4() const;
|
||||||
|
|
||||||
[[nodiscard]] Matrix4x4 ToMatrix4x4(const Vector3 &translation) const;
|
[[nodiscard]] Matrix4x4 ToMatrix4x4(const Vector3 &translation) const;
|
||||||
|
|
||||||
[[nodiscard]] Vector3 Transform(const Vector3& vec) const;
|
[[nodiscard]] Vector3 Transform(const Vector3 &vec) const;
|
||||||
|
|
||||||
[[nodiscard]] Vector3 Transform(float X, float Y, float Z) const;
|
[[nodiscard]] Vector3 Transform(float X, float Y, float Z) const;
|
||||||
|
|
||||||
// Note: We only transform the x,y,z components of 4D vectors, w is left untouched
|
// Note: We only transform the x,y,z components of 4D vectors, w is left untouched
|
||||||
[[nodiscard]] Vector4 Transform(const Vector4& vec) const;
|
[[nodiscard]] Vector4 Transform(const Vector4 &vec) const;
|
||||||
|
|
||||||
[[nodiscard]] Vector4 Transform(float X, float Y, float Z, float W) const;
|
[[nodiscard]] Vector4 Transform(float X, float Y, float Z, float W) const;
|
||||||
|
|
||||||
[[nodiscard]] Quaternion Lerp(const Quaternion& b, float t) const;
|
[[nodiscard]] Quaternion Lerp(const Quaternion &b, float t) const;
|
||||||
static Quaternion Lerp(const Quaternion &source, const Quaternion& target, float t);
|
|
||||||
[[nodiscard]] Quaternion Slerp(const Quaternion& q2, float t) const;
|
static Quaternion Lerp(const Quaternion &source, const Quaternion &target, float t);
|
||||||
static Quaternion Slerp(const Quaternion &source, const Quaternion& target, float t);
|
|
||||||
|
[[nodiscard]] Quaternion Slerp(const Quaternion &q2, float t) const;
|
||||||
|
|
||||||
|
static Quaternion Slerp(const Quaternion &source, const Quaternion &target, float t);
|
||||||
|
|
||||||
/// Returns the 'from' vector rotated towards the 'to' vector by the given normalized time parameter.
|
/// Returns the 'from' vector rotated towards the 'to' vector by the given normalized time parameter.
|
||||||
/** This function slerps the given 'form' vector toward the 'to' vector.
|
/** This function slerps the given 'form' vector toward the 'to' vector.
|
||||||
@@ -157,7 +180,7 @@ public:
|
|||||||
@param t The interpolation time parameter, in the range [0, 1]. Input values outside this range are
|
@param t The interpolation time parameter, in the range [0, 1]. Input values outside this range are
|
||||||
silently clamped to the [0, 1] interval.
|
silently clamped to the [0, 1] interval.
|
||||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||||
static Vector3 SlerpVector(const Vector3& from, const Vector3& to, float t);
|
static Vector3 SlerpVector(const Vector3 &from, const Vector3 &to, float t);
|
||||||
|
|
||||||
/// Returns the 'from' vector rotated towards the 'to' vector by the given absolute angle, in radians.
|
/// Returns the 'from' vector rotated towards the 'to' vector by the given absolute angle, in radians.
|
||||||
/** This function slerps the given 'from' vector towards the 'to' vector.
|
/** This function slerps the given 'from' vector towards the 'to' vector.
|
||||||
@@ -167,23 +190,25 @@ public:
|
|||||||
angle between 'from' and 'to' is smaller than this angle, then the vector 'to' is returned.
|
angle between 'from' and 'to' is smaller than this angle, then the vector 'to' is returned.
|
||||||
Input values outside this range are silently clamped to the [0, pi] interval.
|
Input values outside this range are silently clamped to the [0, pi] interval.
|
||||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||||
static Vector3 SlerpVectorAbs(const Vector3 &from, const Vector3& to, float angleRadians);
|
static Vector3 SlerpVectorAbs(const Vector3 &from, const Vector3 &to, float angleRadians);
|
||||||
|
|
||||||
/// Normalizes this quaternion in-place.
|
/// Normalizes this quaternion in-place.
|
||||||
/// @returns false if failure, true if success.
|
/// @returns false if failure, true if success.
|
||||||
[[nodiscard]] bool Normalize();
|
[[nodiscard]] bool Normalize();
|
||||||
|
|
||||||
/// Returns a normalized copy of this quaternion.
|
/// Returns a normalized copy of this quaternion.
|
||||||
[[nodiscard]] Quaternion Normalized() const;
|
[[nodiscard]] Quaternion Normalized() const;
|
||||||
|
|
||||||
/// Returns true if the length of this quaternion is one.
|
/// Returns true if the length of this quaternion is one.
|
||||||
[[nodiscard]] bool IsNormalized(float epsilon = 1e-5f) const;
|
[[nodiscard]] bool IsNormalized(float epsilon = 1e-5f) const;
|
||||||
|
|
||||||
[[nodiscard]] bool IsInvertible(float epsilon = 1e-3f) const;
|
[[nodiscard]] bool IsInvertible(float epsilon = 1e-3f) const;
|
||||||
|
|
||||||
/// Returns true if the entries of this quaternion are all finite.
|
/// Returns true if the entries of this quaternion are all finite.
|
||||||
[[nodiscard]] bool IsFinite() const;
|
[[nodiscard]] bool IsFinite() const;
|
||||||
|
|
||||||
/// Returns true if this quaternion equals rhs, up to the given epsilon.
|
/// Returns true if this quaternion equals rhs, up to the given epsilon.
|
||||||
[[nodiscard]] bool Equals(const Quaternion& rhs, float epsilon = 1e-3f) const;
|
[[nodiscard]] bool Equals(const Quaternion &rhs, float epsilon = 1e-3f) const;
|
||||||
|
|
||||||
/// Compares whether this Quaternion and the given Quaternion are identical bit-by-bit in the underlying representation.
|
/// Compares whether this Quaternion and the given Quaternion are identical bit-by-bit in the underlying representation.
|
||||||
/// @note Prefer using this over e.g. memcmp, since there can be SSE-related padding in the structures.
|
/// @note Prefer using this over e.g. memcmp, since there can be SSE-related padding in the structures.
|
||||||
|
@@ -4,36 +4,52 @@
|
|||||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
namespace J3ML::LinearAlgebra {
|
||||||
|
|
||||||
|
/// A class that performs and represents translations, rotations, and scaling operations in two dimensions.
|
||||||
class Transform2D {
|
class Transform2D {
|
||||||
protected:
|
protected:
|
||||||
|
// TODO: Verify column-major order (or transpose it) for compatibility with OpenGL.
|
||||||
Matrix3x3 transformation;
|
Matrix3x3 transformation;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
const static Transform2D Identity;
|
const static Transform2D Identity;
|
||||||
const static Transform2D FlipX;
|
const static Transform2D FlipX;
|
||||||
const static Transform2D FlipY;
|
const static Transform2D FlipY;
|
||||||
|
|
||||||
Transform2D(float rotation, const Vector2& pos);
|
/// Default constructor initializes to an Identity transformation.
|
||||||
Transform2D(float px, float py, float sx, float sy, float ox, float oy, float kx, float ky, float rotation)
|
Transform2D();
|
||||||
{
|
|
||||||
transformation = Matrix3x3(px, py, rotation, sx, sy, ox, oy, kx, ky);
|
|
||||||
}
|
|
||||||
Transform2D(const Vector2& pos, const Vector2& scale, const Vector2& origin, const Vector2& skew, float rotation);
|
Transform2D(const Vector2& pos, const Vector2& scale, const Vector2& origin, const Vector2& skew, float rotation);
|
||||||
Transform2D(const Matrix3x3& transform);
|
explicit Transform2D(const Matrix3x3& transform);
|
||||||
|
|
||||||
|
static Transform2D FromScale(float sx, float sy);
|
||||||
|
static Transform2D FromScale(const Vector2& scale);
|
||||||
|
static Transform2D FromRotation(float radians);
|
||||||
|
static Transform2D FromTranslation(const Vector2& translation);
|
||||||
|
static Transform2D FromTranslation(float tx, float ty);
|
||||||
|
|
||||||
|
/// Returns a Transform2D
|
||||||
Transform2D Translate(const Vector2& offset) const;
|
Transform2D Translate(const Vector2& offset) const;
|
||||||
Transform2D Translate(float x, float y) const;
|
Transform2D Translate(float x, float y) const;
|
||||||
Transform2D Scale(float scale); // Perform Uniform Scale
|
Transform2D Scale(float scale);
|
||||||
Transform2D Scale(float x, float y); // Perform Nonunform Scale
|
Transform2D Scale(float x, float y);
|
||||||
Transform2D Scale(const Vector2& scales); // Perform Nonuniform Scale
|
Transform2D Scale(const Vector2& scales);
|
||||||
Transform2D Rotate();
|
Transform2D Rotate(float radians);
|
||||||
Vector2 Transform(const Vector2& input) const;
|
|
||||||
|
/// Transforms a given 2D point by this transformation.
|
||||||
|
Vector2 Transform(const Vector2& point) const;
|
||||||
Transform2D Inverse() const;
|
Transform2D Inverse() const;
|
||||||
Transform2D AffineInverse() const;
|
Transform2D AffineInverse() const;
|
||||||
|
|
||||||
|
Vector2 ForwardVector() const;
|
||||||
|
Vector2 UpVector() const;
|
||||||
|
|
||||||
float Determinant() const;
|
float Determinant() const;
|
||||||
Vector2 GetOrigin() const;
|
float& At(int row, int col);
|
||||||
|
[[nodiscard]] float At(int row, int col) const;
|
||||||
|
|
||||||
|
Vector2 GetTranslation() const;
|
||||||
float GetRotation() const;
|
float GetRotation() const;
|
||||||
Vector2 GetScale() const;
|
Vector2 GetScale() const;
|
||||||
float GetSkew() const;
|
|
||||||
Transform2D OrthoNormalize();
|
Transform2D OrthoNormalize();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,163 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra
|
namespace J3ML::LinearAlgebra
|
||||||
{
|
{
|
||||||
template <uint DIMS, typename T>
|
|
||||||
|
template <size_t D, typename T>
|
||||||
class Vector {
|
class Vector {
|
||||||
|
static_assert(D > 1, "A vector cannot be of 1-dimension, it would be just a scalar!");
|
||||||
public:
|
public:
|
||||||
enum { Dimensions = DIMS};
|
static constexpr bool IsAtLeast1D = D >= 1; // Should always be true for a proper vector.
|
||||||
T elems[DIMS];
|
static constexpr bool IsAtLeast2D = D >= 2; // Should always be true for a proper vector.
|
||||||
|
static constexpr bool IsAtLeast3D = D >= 3;
|
||||||
|
static constexpr bool IsAtLeast4D = D >= 4;
|
||||||
|
|
||||||
|
static constexpr bool Is1D = IsAtLeast1D; // Should always be true for a proper vector.
|
||||||
|
static constexpr bool Is2D = IsAtLeast2D; // Should always be true for a proper vector.
|
||||||
|
static constexpr bool Is3D = IsAtLeast3D;
|
||||||
|
static constexpr bool Is4D = IsAtLeast4D;
|
||||||
|
|
||||||
|
static constexpr bool IsExact1D = D == 1; // Should never be true for a proper vector.
|
||||||
|
static constexpr bool IsExact2D = D == 2;
|
||||||
|
static constexpr bool IsExact3D = D == 3;
|
||||||
|
static constexpr bool IsExact4D = D == 4;
|
||||||
|
|
||||||
|
static constexpr bool IsAtMost1D = D <= 1; // Should also never be true.
|
||||||
|
static constexpr bool IsAtMost2D = D <= 2;
|
||||||
|
static constexpr bool IsAtMost3D = D <= 3;
|
||||||
|
static constexpr bool IsAtMost4D = D <= 4;
|
||||||
|
|
||||||
|
static constexpr bool IsFloatingPoint = std::is_floating_point_v<T>;
|
||||||
|
static constexpr bool IsIntegral = std::is_integral_v<T>;
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
using self_type = Vector<D, T>;
|
||||||
|
static const Vector<D, T> Zero;
|
||||||
|
static const self_type One;
|
||||||
|
static const self_type UnitX;
|
||||||
|
static const self_type UnitY;
|
||||||
|
static const self_type NaN;
|
||||||
|
static const self_type Infinity;
|
||||||
|
static const self_type NegativeInfinity;
|
||||||
|
static self_type GetUnitX() requires Is1D {}
|
||||||
|
static self_type GetUnitY() requires Is2D {}
|
||||||
|
static self_type GetUnitZ() requires Is3D {}
|
||||||
|
static self_type GetUnitW() requires Is4D {}
|
||||||
|
enum { Dimensions = D};
|
||||||
|
std::array<T, Dimensions> data;
|
||||||
|
/// Default constructor initializes all elements to zero.
|
||||||
|
Vector() : data{} {}
|
||||||
|
/// Initialize all elements to a single value.
|
||||||
|
explicit Vector(T value) { data.fill(value); }
|
||||||
|
Vector(T x, T y) requires Is2D: data{x, y} {}
|
||||||
|
Vector(T x, T y, T z) requires Is3D: data{x, y, z} {}
|
||||||
|
Vector(T x, T y, T z, T w) requires Is4D: data{x, y, z, w} {}
|
||||||
|
Vector(std::initializer_list<T> values);
|
||||||
|
T& operator[](size_t index) { return data[index]; }
|
||||||
|
const T& operator[](size_t index) const { return data[index]; }
|
||||||
|
T X() const requires Is1D { return At(0);}
|
||||||
|
T Y() const requires Is2D { return At(1);}
|
||||||
|
T Z() const requires Is3D { return At(2);}
|
||||||
|
T W() const requires Is4D { return At(3);}
|
||||||
|
T& X() requires Is1D { return At(0);}
|
||||||
|
T& Y() requires Is2D { return At(1);}
|
||||||
|
T& Z() requires Is3D { return At(2);}
|
||||||
|
T& W() requires Is4D { return At(3);}
|
||||||
|
Vector<2, T> XX() const requires Is1D { return {X()};}
|
||||||
|
Vector<2, T> YY() const requires Is2D { return {Y()};}
|
||||||
|
Vector<2, T> ZZ() const requires Is3D { return {Z()};}
|
||||||
|
Vector<2, T> WW() const requires Is4D { return {W()};}
|
||||||
|
Vector<3, T> XXX() const requires Is1D { return {X()};}
|
||||||
|
Vector<3, T> YYY() const requires Is2D { return {Y()};}
|
||||||
|
Vector<3, T> ZZZ() const requires Is3D { return {Z()};}
|
||||||
|
Vector<3, T> WWW() const requires Is4D { return {W()};}
|
||||||
|
Vector<4, T> XXXX() const requires Is1D { return {X()};}
|
||||||
|
Vector<4, T> YYYY() const requires Is2D { return {Y()};}
|
||||||
|
Vector<4, T> ZZZZ() const requires Is3D { return {Z()};}
|
||||||
|
Vector<4, T> WWWW() const requires Is4D { return {W()};}
|
||||||
|
Vector<2, T> XY() const requires Is2D { return {X(), Y()};}
|
||||||
|
Vector<2, T> XYZ() const requires Is3D { return {X(), Y(), Z()};}
|
||||||
|
Vector<2, T> XYZW() const requires Is4D { return {X(), Y(), Z(), W()};}
|
||||||
|
self_type& operator+=(const self_type& other);
|
||||||
|
T* ptr();
|
||||||
|
[[nodiscard]] const T* ptr() const;
|
||||||
|
[[nodiscard]]T At(size_t index) const;
|
||||||
|
T& At(size_t index);
|
||||||
|
[[nodiscard]] T Dot(const self_type& other) const;
|
||||||
|
[[nodiscard]] T LengthSquared() const;
|
||||||
|
[[nodiscard]] T LengthSq() const;
|
||||||
|
[[nodiscard]] T Length() const;
|
||||||
|
[[nodiscard]] self_type& Normalized() const;
|
||||||
|
void Normalize();
|
||||||
|
template <size_t N> void Normalize();
|
||||||
|
bool IsNormalized() const;
|
||||||
|
template <size_t N> bool IsNormalized() const;
|
||||||
|
bool IsFinite() const;
|
||||||
|
bool IsZero();
|
||||||
|
bool IsPerpendicular() const;
|
||||||
|
bool IsPerp();
|
||||||
|
self_type Min(const self_type& ceil) const;
|
||||||
|
self_type Max(const self_type& floor) const;
|
||||||
|
self_type Min(T ceil) const;
|
||||||
|
self_type Max(T floor) const;
|
||||||
|
self_type Clamp(const self_type& floor, const self_type& ceil) const;
|
||||||
|
self_type Clamp(T floor, T ceil) const;
|
||||||
|
T Distance(const self_type& other) const requires IsFloatingPoint;
|
||||||
|
int ManhattanDistance(const self_type& other) const requires IsIntegral;
|
||||||
|
|
||||||
|
self_type Cross(const self_type& other) const requires Is3D && IsFloatingPoint {
|
||||||
|
return {
|
||||||
|
At(1) * other.At(2) - At(2) * other.At(1),
|
||||||
|
At(2) * other.At(0) - At(0) * other.At(2),
|
||||||
|
At(0) * other.At(1) - At(1) * other.At(0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool AreOrthonormal(const self_type& A, const self_type& B, float epsilon = 1e-3f);
|
||||||
|
|
||||||
|
self_type Abs() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<size_t DIMS, typename T>
|
||||||
|
Vector<DIMS, T>::Vector(std::initializer_list<T> values) {
|
||||||
|
size_t i = 0;
|
||||||
|
for (const T& value : values) {
|
||||||
|
if (i < DIMS) {
|
||||||
|
data[i++] = value;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t DIMS, typename T>
|
||||||
|
Vector<DIMS, T> & Vector<DIMS, T>::operator+=(const Vector &other) {
|
||||||
|
return {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
using v2f = Vector<2, float>;
|
||||||
|
using v3f = Vector<3, float>;
|
||||||
|
using v4f = Vector<4, float>;
|
||||||
|
using v2d = Vector<2, double>;
|
||||||
|
using v3d = Vector<3, double>;
|
||||||
|
using v4d = Vector<4, double>;
|
||||||
|
using v2i = Vector<2, int>;
|
||||||
|
using v3i = Vector<3, int>;
|
||||||
|
using v4i = Vector<4, int>;
|
||||||
|
|
||||||
|
template<> const v2f Vector<2, float>::Zero = v2f(0);
|
||||||
|
template<> const v3f Vector<3, float>::Zero = v3f(0);
|
||||||
|
template<> const v4f Vector<4, float>::Zero = v4f(0);
|
||||||
|
|
||||||
|
template<> const v2f Vector<2, float>::One = v2f(1);
|
||||||
|
template<> const v3f Vector<3, float>::One = v3f(1);
|
||||||
|
template<> const v4f Vector<4, float>::One = v4f(1);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -55,12 +55,12 @@ namespace J3ML::LinearAlgebra {
|
|||||||
Vector2(float X, float Y);
|
Vector2(float X, float Y);
|
||||||
/// Constructs this float2 from a C array, to the value (data[0], data[1]).
|
/// Constructs this float2 from a C array, to the value (data[0], data[1]).
|
||||||
explicit Vector2(const float* data);
|
explicit Vector2(const float* data);
|
||||||
// Constructs a new Vector2 with the value {scalar, scalar}
|
/// Constructs a new Vector2 with the value {scalar, scalar}
|
||||||
explicit Vector2(float scalar);
|
explicit Vector2(float scalar);
|
||||||
Vector2(const Vector2& rhs); // Copy Constructor
|
Vector2(const Vector2& rhs); // Copy Constructor
|
||||||
explicit Vector2(const Vector2i& rhs);
|
explicit Vector2(const Vector2i& rhs);
|
||||||
//Vector2(Vector2&&) = default; // Move Constructor
|
/// Constructs a new Vector2 from std::pair<float, float>,.
|
||||||
|
explicit Vector2(const std::pair<float, float>& rhs) : x(rhs.first), y(rhs.second) {}
|
||||||
|
|
||||||
[[nodiscard]] float GetX() const;
|
[[nodiscard]] float GetX() const;
|
||||||
[[nodiscard]] float GetY() const;
|
[[nodiscard]] float GetY() const;
|
||||||
@@ -111,14 +111,10 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
/// Tests if two vectors are equal, up to the given epsilon.
|
/// Tests if two vectors are equal, up to the given epsilon.
|
||||||
/** @see IsPerpendicular(). */
|
/** @see IsPerpendicular(). */
|
||||||
bool Equals(const Vector2& rhs, float epsilon = 1e-3f) const {
|
bool Equals(const Vector2& rhs, float epsilon = 1e-3f) const;
|
||||||
return Math::EqualAbs(x, rhs.x, epsilon) &&
|
bool Equals(float x_, float y_, float epsilon = 1e-3f) const;
|
||||||
Math::EqualAbs(y, rhs.y, epsilon);
|
|
||||||
}
|
bool PreciselyEquals(const Vector2& rhs) const;
|
||||||
bool Equals(float x_, float y_, float epsilon = 1e-3f) const {
|
|
||||||
return Math::EqualAbs(x, x_, epsilon) &&
|
|
||||||
Math::EqualAbs(y, y_, epsilon);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator == (const Vector2& rhs) const;
|
bool operator == (const Vector2& rhs) const;
|
||||||
bool operator != (const Vector2& rhs) const;
|
bool operator != (const Vector2& rhs) const;
|
||||||
@@ -388,6 +384,7 @@ namespace J3ML::LinearAlgebra {
|
|||||||
static Vector2 RandomBox(Algorithm::RNG& rng, float minElem, float maxElem);
|
static Vector2 RandomBox(Algorithm::RNG& rng, float minElem, float maxElem);
|
||||||
|
|
||||||
[[nodiscard]] std::string ToString() const;
|
[[nodiscard]] std::string ToString() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector2 operator*(float lhs, const Vector2 &rhs);
|
Vector2 operator*(float lhs, const Vector2 &rhs);
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "Vector2.hpp"
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
namespace J3ML::LinearAlgebra {
|
||||||
class Vector2i;
|
class Vector2i;
|
||||||
@@ -12,6 +13,8 @@ public:
|
|||||||
Vector2i();
|
Vector2i();
|
||||||
Vector2i(int x, int y) : x(x), y(y) {}
|
Vector2i(int x, int y) : x(x), y(y) {}
|
||||||
explicit Vector2i(int rhs) : x(rhs), y(rhs) {}
|
explicit Vector2i(int rhs) : x(rhs), y(rhs) {}
|
||||||
|
explicit Vector2i(const Vector2& rhs) : x(rhs.x), y(rhs.y) { }
|
||||||
|
explicit Vector2i(const std::pair<int, int>& rhs) : x(rhs.first), y(rhs.second) {}
|
||||||
public:
|
public:
|
||||||
bool operator == (const Vector2i& rhs) const;
|
bool operator == (const Vector2i& rhs) const;
|
||||||
bool operator != (const Vector2i& rhs) const;
|
bool operator != (const Vector2i& rhs) const;
|
||||||
|
@@ -30,6 +30,9 @@ namespace J3ML::LinearAlgebra {
|
|||||||
because there is a considerable SIMD performance benefit in the first form.
|
because there is a considerable SIMD performance benefit in the first form.
|
||||||
@see x, y, z, w. */
|
@see x, y, z, w. */
|
||||||
Vector4(float X, float Y, float Z, float W);
|
Vector4(float X, float Y, float Z, float W);
|
||||||
|
Vector4(float XYZW) : x(XYZW), y(0), z(0), w(0) {}
|
||||||
|
Vector4(float X, float Y) : x(X), y(Y), z(0), w(0) {}
|
||||||
|
Vector4(float X, float Y, float Z) : x(X), y(Y), z(Z), w(0) {}
|
||||||
/// The Vector4 copy constructor.
|
/// The Vector4 copy constructor.
|
||||||
Vector4(const Vector4& copy) { Set(copy); }
|
Vector4(const Vector4& copy) { Set(copy); }
|
||||||
Vector4(Vector4&& move) = default;
|
Vector4(Vector4&& move) = default;
|
||||||
@@ -48,7 +51,7 @@ namespace J3ML::LinearAlgebra {
|
|||||||
@note This function is provided for compatibility with other APIs which require raw C pointer access
|
@note This function is provided for compatibility with other APIs which require raw C pointer access
|
||||||
to vectors. Avoid using this function in general, and instead always use the operator [] of this
|
to vectors. Avoid using this function in general, and instead always use the operator [] of this
|
||||||
class to access the elements of this vector by index. */
|
class to access the elements of this vector by index. */
|
||||||
inline float* ptr();
|
float* ptr();
|
||||||
[[nodiscard]] const float* ptr() const;
|
[[nodiscard]] const float* ptr() const;
|
||||||
|
|
||||||
/// Accesses an element of this vector using array notation.
|
/// Accesses an element of this vector using array notation.
|
||||||
@@ -106,12 +109,9 @@ namespace J3ML::LinearAlgebra {
|
|||||||
/// Tests if the (x, y, z) part of this vector is equal to (0,0,0), up to the given epsilon.
|
/// Tests if the (x, y, z) part of this vector is equal to (0,0,0), up to the given epsilon.
|
||||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero4(), IsNormalized3(), IsNormalized4(). */
|
/** @see NormalizeW(), IsWZeroOrOne(), IsZero4(), IsNormalized3(), IsNormalized4(). */
|
||||||
[[nodiscard]] bool IsZero3(float epsilonSq = 1e-6f) const;
|
[[nodiscard]] bool IsZero3(float epsilonSq = 1e-6f) const;
|
||||||
|
|
||||||
|
|
||||||
/// Returns true if this vector is equal to (0,0,0,0), up to the given epsilon.
|
|
||||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero3(), IsNormalized3(), IsNormalized4(). */
|
|
||||||
[[nodiscard]] bool IsZero(float epsilonSq = 1e-6f) const;
|
[[nodiscard]] bool IsZero(float epsilonSq = 1e-6f) const;
|
||||||
[[nodiscard]] bool IsZero4(float epsilonSq = 1e-6f) const;
|
[[nodiscard]] bool IsZero4(float epsilonSq = 1e-6f) const;
|
||||||
|
|
||||||
/// Tests if this vector contains valid finite elements.
|
/// Tests if this vector contains valid finite elements.
|
||||||
[[nodiscard]] bool IsFinite() const;
|
[[nodiscard]] bool IsFinite() const;
|
||||||
|
|
||||||
@@ -202,6 +202,7 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
[[nodiscard]] float Magnitude() const;
|
[[nodiscard]] float Magnitude() const;
|
||||||
[[nodiscard]] float Dot(const Vector4& rhs) const;
|
[[nodiscard]] float Dot(const Vector4& rhs) const;
|
||||||
|
[[nodiscard]] float Dot4(const Vector4& rhs) const { return this->Dot(rhs); }
|
||||||
/// Computes the dot product of the (x, y, z) parts of this and the given float4.
|
/// Computes the dot product of the (x, y, z) parts of this and the given float4.
|
||||||
/** @note This function ignores the w component of this vector (assumes w=0).
|
/** @note This function ignores the w component of this vector (assumes w=0).
|
||||||
@see Dot4(), Cross3(). */
|
@see Dot4(), Cross3(). */
|
||||||
@@ -209,10 +210,9 @@ namespace J3ML::LinearAlgebra {
|
|||||||
[[nodiscard]] float Dot3(const Vector4& rhs) const;
|
[[nodiscard]] float Dot3(const Vector4& rhs) const;
|
||||||
|
|
||||||
[[nodiscard]] Vector4 Project(const Vector4& rhs) const;
|
[[nodiscard]] Vector4 Project(const Vector4& rhs) const;
|
||||||
// While it is feasable to compute a cross-product in four dimensions
|
|
||||||
// the cross product only has the orthogonality property in 3 and 7 dimensions
|
/// While it is feasable to compute a cross-product in four dimensions the cross product only has the orthogonality property in 3 and 7 dimensions.
|
||||||
// You should consider instead looking at Gram-Schmidt Orthogonalization
|
/// You should consider instead looking at Gram-Schmidt Orthogonalization to find orthonormal vectors.
|
||||||
// to find orthonormal vectors.
|
|
||||||
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
||||||
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
||||||
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
||||||
@@ -220,7 +220,11 @@ namespace J3ML::LinearAlgebra {
|
|||||||
[[nodiscard]] Vector4 Normalized() const;
|
[[nodiscard]] Vector4 Normalized() const;
|
||||||
[[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const;
|
[[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const;
|
||||||
|
|
||||||
|
/// Returns the angle between this vector and the specified vector, in radians.
|
||||||
|
/// @note This function takes into account that this vector or the other vector can be un-normalized, and normalizes the computations.
|
||||||
|
/// @see Dot3(), AngleBetween3(), AngleBetweenNorm3(), AngleBetweenNorm().
|
||||||
[[nodiscard]] float AngleBetween(const Vector4& rhs) const;
|
[[nodiscard]] float AngleBetween(const Vector4& rhs) const;
|
||||||
|
[[nodiscard]] float AngleBetween4(const Vector4& rhs) const;
|
||||||
|
|
||||||
/// Adds two vectors. [indexTitle: operators +,-,*,/]
|
/// Adds two vectors. [indexTitle: operators +,-,*,/]
|
||||||
/** This function is identical to the member function Add().
|
/** This function is identical to the member function Add().
|
||||||
@@ -243,17 +247,23 @@ namespace J3ML::LinearAlgebra {
|
|||||||
/** This function is identical to the member function Mul().
|
/** This function is identical to the member function Mul().
|
||||||
@return float4(x * scalar, y * scalar, z * scalar, w * scalar); */
|
@return float4(x * scalar, y * scalar, z * scalar, w * scalar); */
|
||||||
Vector4 operator *(float rhs) const;
|
Vector4 operator *(float rhs) const;
|
||||||
[[nodiscard]] Vector4 Mul(float scalar) const;
|
[[nodiscard]] Vector4 Mul(float scalar) const { return *this * scalar;}
|
||||||
static Vector4 Mul(const Vector4& lhs, float rhs);
|
static Vector4 Mul(const Vector4& lhs, float rhs) {return lhs * rhs; }
|
||||||
|
|
||||||
/// Divides this vector by a scalar. [similarOverload: operator+] [hideIndex]
|
/// Divides this vector by a scalar. [similarOverload: operator+] [hideIndex]
|
||||||
/** This function is identical to the member function Div().
|
/** This function is identical to the member function Div().
|
||||||
@return float4(x / scalar, y / scalar, z / scalar, w * scalar); */
|
@return float4(x / scalar, y / scalar, z / scalar, w * scalar); */
|
||||||
Vector4 operator /(float rhs) const;
|
Vector4 operator /(float rhs) const;
|
||||||
[[nodiscard]] Vector4 Div(float scalar) const;
|
[[nodiscard]] Vector4 Div(float scalar) const { return *this / scalar; }
|
||||||
static Vector4 Div(const Vector4& rhs, float scalar);
|
static Vector4 Div(const Vector4& rhs, float scalar) { return rhs / scalar; }
|
||||||
|
|
||||||
Vector4 operator +() const; // Unary + Operator
|
/// Divides this vector by a vector, element-wise.
|
||||||
|
/// @note Mathematically, the division of two vectors is not defined in linear space structures,
|
||||||
|
/// but this function is provided here for syntactical convenience.
|
||||||
|
Vector4 Div(const Vector4& rhs) const;
|
||||||
|
static Vector4 Div(const Vector4& lhs, const Vector4& rhs);
|
||||||
|
|
||||||
|
Vector4 operator +() const { return *this;} // Unary + Operator
|
||||||
/// Performs an unary negation of this vector. [similarOverload: operator+] [hideIndex]
|
/// Performs an unary negation of this vector. [similarOverload: operator+] [hideIndex]
|
||||||
/** This function is identical to the member function Neg().
|
/** This function is identical to the member function Neg().
|
||||||
@return float4(-x, -y, -z, -w). */
|
@return float4(-x, -y, -z, -w). */
|
||||||
|
56
include/J3ML/Rotation.hpp
Normal file
56
include/J3ML/Rotation.hpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "J3ML.hpp"
|
||||||
|
#include "LinearAlgebra/Vector2.hpp"
|
||||||
|
|
||||||
|
namespace J3ML::Math {
|
||||||
|
|
||||||
|
/// Rotation is a class that represents a single axis of rotation.
|
||||||
|
/// The class is designed to behave very similarly to a float literal, and
|
||||||
|
/// primarily help organize code involving rotations by handling common boilerplate
|
||||||
|
/// and providing mathematical expressions.
|
||||||
|
struct Rotation {
|
||||||
|
|
||||||
|
constexpr Rotation();
|
||||||
|
constexpr Rotation(float value);
|
||||||
|
constexpr explicit Rotation(const Vector2& direction_vector);
|
||||||
|
|
||||||
|
constexpr Rotation FromDegrees(float degrees);
|
||||||
|
|
||||||
|
constexpr Rotation FromRadians(float radians);
|
||||||
|
|
||||||
|
//Rotation(const Types::Radians& radians);
|
||||||
|
//Rotation(const Types::Degrees& degrees);
|
||||||
|
|
||||||
|
|
||||||
|
constexpr float Radians() const { return value;}
|
||||||
|
//Types::Radians Radians() const { return {value}; }
|
||||||
|
constexpr float Degrees() const { return Math::Degrees(value); }
|
||||||
|
|
||||||
|
constexpr Rotation operator+(const Rotation& rhs) const;
|
||||||
|
constexpr Rotation operator-(const Rotation& rhs) const;
|
||||||
|
constexpr Rotation operator*(float scalar) const;
|
||||||
|
constexpr Rotation operator/(float scalar) const;
|
||||||
|
constexpr bool operator==(const Rotation& rhs) const = default;
|
||||||
|
constexpr Rotation operator-() const;
|
||||||
|
|
||||||
|
/// Rotates a given Vector2 by this Rotation.
|
||||||
|
Vector2 Rotate(const Vector2& rhs) const;
|
||||||
|
|
||||||
|
float operator()() const { return value; }
|
||||||
|
Rotation& operator=(const Rotation& rhs) {
|
||||||
|
this->value = rhs.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Rotation operator ""_rad(long double rads);
|
||||||
|
|
||||||
|
constexpr Rotation operator ""_radians(long double rads);
|
||||||
|
|
||||||
|
constexpr Rotation operator ""_deg(long double rads);
|
||||||
|
|
||||||
|
constexpr Rotation operator ""_degrees(long double rads);
|
||||||
|
}
|
56
main.cpp
56
main.cpp
@@ -11,13 +11,27 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <J3ML/LinearAlgebra.hpp>
|
||||||
#include <J3ML/Geometry.hpp>
|
#include <J3ML/Geometry.hpp>
|
||||||
#include <J3ML/J3ML.hpp>
|
#include <J3ML/J3ML.hpp>
|
||||||
#include <jlog/Logger.hpp>
|
#include <jlog/Logger.hpp>
|
||||||
|
#include <J3ML/LinearAlgebra/Matrix.hpp>
|
||||||
|
#include <J3ML/LinearAlgebra/Vector.hpp>
|
||||||
|
|
||||||
|
#include "J3ML/Rotation.hpp"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
Matrix3x3 matrix_rep = {
|
||||||
|
0.9902160, 0.0000000, 0.1395431,
|
||||||
|
0.1273699, 0.4084874, -0.9038334,
|
||||||
|
-0.0570016, 0.9127640, 0.4044908};
|
||||||
|
|
||||||
|
Quaternion quat_rep = {0.5425029, 0.0586955, 0.0380374, 0.8371371};
|
||||||
|
|
||||||
|
AxisAngle aa_rep = { {0.9917912, 0.1073057, 0.069539}, 1.1575362};
|
||||||
|
|
||||||
|
|
||||||
using namespace J3ML::Math;
|
using namespace J3ML::Math;
|
||||||
|
|
||||||
@@ -40,10 +54,48 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ray a({420, 0, 0}, {1, 0, 0});
|
Ray a({420, 0, 0}, {1, 0, 0});
|
||||||
|
|
||||||
|
|
||||||
std::cout << a << std::endl;
|
std::cout << a << std::endl;
|
||||||
|
|
||||||
|
Matrix4x4 A {
|
||||||
|
1, 2, 0, 1,
|
||||||
|
3, 1, 2, 0,
|
||||||
|
0, 4, 1, 2,
|
||||||
|
2, 0, 3, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
Matrix4x4 B {
|
||||||
|
0, 1, 2, 3,
|
||||||
|
1, 0, 1, 0,
|
||||||
|
2, 3, 0, 1,
|
||||||
|
1, 2, 1, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
auto C = A*B;
|
||||||
|
|
||||||
|
using Matrix2x3f = Matrix<2, 3, float>;
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << C << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "j3ml demo coming soon" << std::endl;
|
std::cout << "j3ml demo coming soon" << std::endl;
|
||||||
|
|
||||||
|
v2f _v2f{1.f};
|
||||||
|
v3f _v3f{1.f};
|
||||||
|
v4f _v4f(1);
|
||||||
|
|
||||||
|
v2i ipair (420, 420);
|
||||||
|
|
||||||
|
v3i ipair3(0,0,0);
|
||||||
|
|
||||||
|
v4i ipair4(1,2,3,4);
|
||||||
|
|
||||||
|
using namespace J3ML::Math;
|
||||||
|
|
||||||
|
Rotation my_rot = 25_degrees;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -78,7 +78,7 @@ namespace J3ML::Geometry
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 AABB2D::Centroid() {
|
Vector2 AABB2D::Centroid() const {
|
||||||
return (minPoint + (maxPoint / 2.f));
|
return (minPoint + (maxPoint / 2.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -129,23 +129,6 @@ namespace J3ML::Geometry
|
|||||||
return mostExtreme;
|
return mostExtreme;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frustum Frustum::CreateFrustumFromCamera(const CoordinateFrame &cam, float aspect, float fovY, float zNear, float zFar) {
|
|
||||||
Frustum frustum;
|
|
||||||
const float halfVSide = zFar * tanf(fovY * 0.5f);
|
|
||||||
const float halfHSide = halfVSide * aspect;
|
|
||||||
|
|
||||||
const Vector3 frontMultFar = cam.Front * zFar;
|
|
||||||
|
|
||||||
// frustum.NearFace = Plane{cam.Position + cam.Front * zNear, cam.Front};
|
|
||||||
// frustum.FarFace = Plane{cam.Position + frontMultFar, -cam.Front};
|
|
||||||
// frustum.RightFace = Plane{cam.Position, Vector3::Cross(frontMultFar - cam.Right * halfHSide, cam.Up)};
|
|
||||||
// frustum.LeftFace = Plane{cam.Position, Vector3::Cross(cam.Up, frontMultFar+cam.Right*halfHSide)};
|
|
||||||
// frustum.TopFace = Plane{cam.Position, Vector3::Cross(cam.Right, frontMultFar - cam.Up * halfVSide)};
|
|
||||||
// frustum.BottomFace = Plane{cam.Position, Vector3::Cross(frontMultFar + cam.Up * halfVSide, cam.Right)};
|
|
||||||
return frustum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PBVolume<6> Frustum::ToPBVolume() const {
|
PBVolume<6> Frustum::ToPBVolume() const {
|
||||||
PBVolume<6> frustumVolume;
|
PBVolume<6> frustumVolume;
|
||||||
frustumVolume.p[0] = NearPlane();
|
frustumVolume.p[0] = NearPlane();
|
||||||
|
@@ -372,7 +372,7 @@ namespace J3ML::Geometry
|
|||||||
Vector4 b = Vector4(poly.v[face.v[1]], 1.f);
|
Vector4 b = Vector4(poly.v[face.v[1]], 1.f);
|
||||||
Vector4 c = Vector4(poly.v[face.v[2]], 1.f);
|
Vector4 c = Vector4(poly.v[face.v[2]], 1.f);
|
||||||
Vector4 normal = (b-a).Cross(c-a);
|
Vector4 normal = (b-a).Cross(c-a);
|
||||||
normal.Normalized();
|
normal.Normalize();
|
||||||
return normal;
|
return normal;
|
||||||
// return ((vec)v[face.v[1]]-(vec)v[face.v[0]]).Cross((vec)v[face.v[2]]-(vec)v[face.v[0]]).Normalized();
|
// return ((vec)v[face.v[1]]-(vec)v[face.v[0]]).Cross((vec)v[face.v[2]]-(vec)v[face.v[0]]).Normalized();
|
||||||
}
|
}
|
||||||
@@ -390,7 +390,7 @@ namespace J3ML::Geometry
|
|||||||
normal.z += (double(poly.v[v0].x) - poly.v[v1].x) * (double(poly.v[v0].y) + poly.v[v1].y); // Project on xy
|
normal.z += (double(poly.v[v0].x) - poly.v[v1].x) * (double(poly.v[v0].y) + poly.v[v1].y); // Project on xy
|
||||||
v0 = v1;
|
v0 = v1;
|
||||||
}
|
}
|
||||||
normal.Normalized();
|
normal.Normalize();
|
||||||
return normal;
|
return normal;
|
||||||
#if 0
|
#if 0
|
||||||
cv bestNormal;
|
cv bestNormal;
|
||||||
|
50
src/J3ML/Geometry/Rect2D.cpp
Normal file
50
src/J3ML/Geometry/Rect2D.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include <J3ML/Geometry/Rect2D.hpp>
|
||||||
|
|
||||||
|
namespace J3ML::Geometry
|
||||||
|
{
|
||||||
|
Rect2D Rect2D::operator+(const J3ML::LinearAlgebra::Vector2 &pt) const {
|
||||||
|
return {position+pt, size};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2D &Rect2D::operator+(const Vector2 &pt) {
|
||||||
|
position += pt;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB2D Rect2D::GetAsAABB() const { return {MinPoint(), MaxPoint()};}
|
||||||
|
|
||||||
|
Rect2D Rect2D::FromCentroidAndRadii(const Vector2 ¢roid, const Vector2 &radii) {
|
||||||
|
return Rect2D(centroid.x - (radii.x), centroid.y - (radii.y),
|
||||||
|
radii.x*2.f, radii.y*2.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2D::Rect2D(float x, float y, float w, float h) {
|
||||||
|
this->position = {x,y};
|
||||||
|
this->size = {w,h};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect2D::Rect2D(const Vector2 &pos, const Vector2 &size) {
|
||||||
|
this->position = pos;
|
||||||
|
this->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Rect2D::HorizontalRadius() const { return Width()/2.f;}
|
||||||
|
|
||||||
|
float Rect2D::VerticalRadius() const { return Height()/2.f;}
|
||||||
|
|
||||||
|
float Rect2D::HalfWidth() const { return HorizontalRadius();}
|
||||||
|
|
||||||
|
float Rect2D::HalfHeight() const { return VerticalRadius();}
|
||||||
|
|
||||||
|
Vector2 Rect2D::Centroid() const { return position + (size / 2.f);}
|
||||||
|
|
||||||
|
float Rect2D::Width() const { return size.x;}
|
||||||
|
|
||||||
|
float Rect2D::Height() const { return size.y;}
|
||||||
|
|
||||||
|
Vector2 Rect2D::MinPoint() const { return position; }
|
||||||
|
|
||||||
|
Vector2 Rect2D::MaxPoint() const { return position + size;}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <strstream>
|
#include <J3ML/J3ML.hpp>
|
||||||
#include "J3ML/J3ML.hpp"
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -133,20 +132,10 @@ namespace J3ML::Math::Functions::Trigonometric {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace J3ML::Math::Functions {
|
namespace J3ML::Math::Functions { }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace J3ML {
|
namespace J3ML {
|
||||||
|
|
||||||
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
|
|
||||||
|
|
||||||
Math::Rotation Math::operator ""_deg(long double rads) { return {Functions::Radians((float)rads)}; }
|
|
||||||
|
|
||||||
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
|
|
||||||
|
|
||||||
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
|
|
||||||
|
|
||||||
float Math::Functions::FastRSqrt(float x) {
|
float Math::Functions::FastRSqrt(float x) {
|
||||||
return 1.f / FastSqrt(x);
|
return 1.f / FastSqrt(x);
|
||||||
}
|
}
|
||||||
@@ -169,9 +158,6 @@ namespace J3ML {
|
|||||||
return 1.f / Sqrt(x);
|
return 1.f / Sqrt(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int SigFigsTable[] = {0,0,0,1,0,0,1,0,0,1};
|
int SigFigsTable[] = {0,0,0,1,0,0,1,0,0,1};
|
||||||
|
|
||||||
int DivBy[] = {1,1,1, 1000,1000,1000, 1000000, 1000000, 1000000, 1000000000, 1000000000,1000000000};
|
int DivBy[] = {1,1,1, 1000,1000,1000, 1000000, 1000000, 1000000, 1000000000, 1000000000,1000000000};
|
||||||
@@ -241,6 +227,20 @@ namespace J3ML {
|
|||||||
return 1.f / x;
|
return 1.f / x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Math::Functions::QRSqrt(float x) {
|
||||||
|
long i;
|
||||||
|
float x2, y;
|
||||||
|
const float threehalfs = 1.5f;
|
||||||
|
x2 = x * 0.5f;
|
||||||
|
y = x;
|
||||||
|
i = *(long*) &y; // evil floating point bit level hacking
|
||||||
|
i = 0x5f3759df - (i >> 1); // what the fuck?
|
||||||
|
y = *(float*) &i;
|
||||||
|
y = y * (threehalfs - (x2 * y * y)); // increase precision of approximation via Newton's Method
|
||||||
|
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
float Math::Functions::Lerp(float a, float b, float t) { return a + t * (b-a);}
|
float Math::Functions::Lerp(float a, float b, float t) { return a + t * (b-a);}
|
||||||
|
|
||||||
float Math::Functions::LerpMod(float a, float b, float mod, float t) {
|
float Math::Functions::LerpMod(float a, float b, float mod, float t) {
|
||||||
@@ -299,31 +299,10 @@ namespace J3ML {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Math::Rotation::Rotation() : valueInRadians(0) {}
|
// int BitTwiddling::CountBitsSet(u32 value) { }
|
||||||
|
|
||||||
Math::Rotation::Rotation(float value) : valueInRadians(value) {}
|
|
||||||
|
|
||||||
Math::Rotation::Rotation(const Types::Radians &radians): valueInRadians(radians.value) {}
|
|
||||||
|
|
||||||
Math::Rotation::Rotation(const Types::Degrees °rees): valueInRadians(Functions::Radians(degrees.value)) {}
|
|
||||||
|
|
||||||
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) {
|
|
||||||
return {valueInRadians + rhs.valueInRadians};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int BitTwiddling::CountBitsSet(u32 value) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Math::Functions {
|
namespace Math::Functions {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool IsPow2(u32 number) {
|
bool IsPow2(u32 number) {
|
||||||
return (number & (number - 1)) == 0;
|
return (number & (number - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||||
|
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||||
namespace J3ML::LinearAlgebra {
|
namespace J3ML::LinearAlgebra {
|
||||||
|
|
||||||
AxisAngle::AxisAngle() : axis(Vector3::Zero), angle(0) {}
|
|
||||||
|
|
||||||
AxisAngle::AxisAngle(const Vector3& axis, float angle) : axis(axis), angle(angle) {}
|
AxisAngle::AxisAngle(const Vector3& axis, float angle) : axis(axis), angle(angle) {}
|
||||||
|
|
||||||
@@ -15,9 +15,68 @@ namespace J3ML::LinearAlgebra {
|
|||||||
axis = { rhs.x*reciprocalSinAngle, rhs.y*reciprocalSinAngle, rhs.z*reciprocalSinAngle };
|
axis = { rhs.x*reciprocalSinAngle, rhs.y*reciprocalSinAngle, rhs.z*reciprocalSinAngle };
|
||||||
}
|
}
|
||||||
|
|
||||||
AxisAngle::AxisAngle(const EulerAngleXYZ& e) {
|
|
||||||
auto a = AxisAngle(Quaternion(e));
|
Quaternion AxisAngle::ToQuaternion() const { return Quaternion(*this); }
|
||||||
axis = a.axis;
|
|
||||||
angle = a.angle;
|
AxisAngle::AxisAngle(const Matrix3x3 &m) : AxisAngle(Quaternion(m)) { }
|
||||||
|
|
||||||
|
bool AxisAngle::Equals(const AxisAngle &rhs, float epsilon) {
|
||||||
|
return this->axis.Equals(rhs.axis, epsilon) && Math::Equal(angle, rhs.angle, epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix3x3 AxisAngle::ToMatrix3x3() const {
|
||||||
|
return Matrix3x3(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AxisAngle::Inverse() {
|
||||||
|
angle = -angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisAngle AxisAngle::Inverted() const {
|
||||||
|
return {axis, -angle};
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisAngle AxisAngle::Lerp(const AxisAngle &rhs, float t) {
|
||||||
|
auto new_axis = axis.Lerp(rhs.axis, t);
|
||||||
|
float new_angle = Math::Lerp(angle, rhs.angle, t);
|
||||||
|
return {new_axis, new_angle};
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisAngle AxisAngle::Slerp(const AxisAngle &rhs, float t) {
|
||||||
|
Quaternion a(*this);
|
||||||
|
Quaternion b(rhs);
|
||||||
|
|
||||||
|
Quaternion intermediate = a.Slerp(b, t);
|
||||||
|
|
||||||
|
return AxisAngle(intermediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AxisAngle::operator==(const AxisAngle &rhs) {
|
||||||
|
return Equals(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
AxisAngle AxisAngle::Normalized() const {
|
||||||
|
AxisAngle copy(*this);
|
||||||
|
copy.Normalize();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AxisAngle::IsIdentity() { return Math::Equal(angle, 0); }
|
||||||
|
|
||||||
|
void AxisAngle::Normalize() {
|
||||||
|
float axisLength = axis.Length();
|
||||||
|
|
||||||
|
if (axisLength > 0.0f)
|
||||||
|
axis /= axisLength;
|
||||||
|
else {
|
||||||
|
// Handle the case where the axis is a zero vector.
|
||||||
|
// You might want to set it to a default axis (e.g., (0,1,0))
|
||||||
|
axis = Vector3(0, 1, 0);
|
||||||
|
angle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 AxisAngle::Axis() const { return axis;}
|
||||||
|
|
||||||
|
float AxisAngle::Angle() const { return angle;}
|
||||||
}
|
}
|
@@ -1 +0,0 @@
|
|||||||
#include <J3ML/LinearAlgebra/CoordinateFrame.hpp>
|
|
@@ -1,38 +0,0 @@
|
|||||||
#include <J3ML/LinearAlgebra/DirectionVector.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
|
||||||
|
|
||||||
DirectionVectorRH::DirectionVectorRH(const Vector3& rhs) {
|
|
||||||
x = rhs.x;
|
|
||||||
y = rhs.y;
|
|
||||||
z = rhs.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Forward(const Matrix3x3& rhs) {
|
|
||||||
return DirectionVectorRH(rhs.Col(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Backward(const Matrix3x3& rhs) {
|
|
||||||
return DirectionVectorRH(-rhs.Col(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Left(const Matrix3x3& rhs) {
|
|
||||||
return DirectionVectorRH(-rhs.Col(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Right(const Matrix3x3& rhs) {
|
|
||||||
return DirectionVectorRH(rhs.Col(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Up(const Matrix3x3 &rhs) {
|
|
||||||
return DirectionVectorRH(rhs.Col(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionVectorRH DirectionVectorRH::Down(const Matrix3x3& rhs) {
|
|
||||||
return DirectionVectorRH(-rhs.Col(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -1,45 +0,0 @@
|
|||||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
|
||||||
#include <cmath>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
|
||||||
|
|
||||||
EulerAngleXYZ::EulerAngleXYZ(float roll, float pitch, float yaw) {
|
|
||||||
this->roll = roll;
|
|
||||||
this->pitch = pitch;
|
|
||||||
this->yaw = yaw;
|
|
||||||
}
|
|
||||||
|
|
||||||
EulerAngleXYZ::EulerAngleXYZ(const AxisAngle& rhs) {
|
|
||||||
*this = EulerAngleXYZ(Quaternion(rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
EulerAngleXYZ::EulerAngleXYZ(const Quaternion& q) {
|
|
||||||
float sy = 2 * q.x * q.z + 2 * q.y * q.w;
|
|
||||||
bool gimbal_lock = std::abs(sy) > 0.99999f;
|
|
||||||
|
|
||||||
if (!gimbal_lock)
|
|
||||||
roll = Math::Degrees(std::atan2(-(2 * q.y * q.z - 2 * q.x * q.w),2 * q.w * q.w + 2 * q.z * q.z - 1));
|
|
||||||
else
|
|
||||||
roll = Math::Degrees(std::atan2(2 * q.y * q.z + 2 * q.x * q.w,2 * q.w * q.w + 2 * q.y * q.y - 1));
|
|
||||||
|
|
||||||
pitch = Math::Degrees(std::asin(sy));
|
|
||||||
|
|
||||||
if (!gimbal_lock)
|
|
||||||
yaw = Math::Degrees(std::atan2(-(2 * q.x * q.y - 2 * q.z * q.w),2 * q.w * q.w + 2 * q.x * q.x - 1));
|
|
||||||
else
|
|
||||||
yaw = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EulerAngleXYZ::EulerAngleXYZ(const Matrix3x3& rhs) {
|
|
||||||
auto m = rhs.Transposed();
|
|
||||||
auto sy = m.At(0, 2);
|
|
||||||
auto unlocked = std::abs(sy) < 0.99999f;
|
|
||||||
|
|
||||||
roll = Math::Degrees(unlocked ? std::atan2(-m.At(1, 2), m.At(2, 2)) : std::atan2(m.At(2, 1), m.At(1, 1)));
|
|
||||||
pitch = Math::Degrees(std::asin(sy));
|
|
||||||
yaw = Math::Degrees(unlocked ? std::atan2(-m.At(0, 1), m.At(0, 0)) : 0);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -110,7 +110,7 @@ namespace J3ML::LinearAlgebra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Matrix3x3::Matrix3x3(const Quaternion& orientation) {
|
Matrix3x3::Matrix3x3(const Quaternion& orientation) {
|
||||||
//*this = Matrix3x3(EulerAngleXYZ(orientation));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Matrix3x3::Determinant() const {
|
float Matrix3x3::Determinant() const {
|
||||||
@@ -1087,6 +1087,18 @@ namespace J3ML::LinearAlgebra {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::ForwardDir() const { return Col(2).Normalized(); }
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::BackwardDir() const { return -Col(2).Normalized(); }
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::LeftDir() const { return -Col(0).Normalized(); }
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::RightDir() const { return Col(0).Normalized(); }
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::UpDir() const { return Col(1).Normalized(); }
|
||||||
|
|
||||||
|
Vector3 Matrix3x3::DownDir() const { return -Col(1).Normalized(); }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
|
#include <iomanip>
|
||||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Matrices.inl>
|
#include <J3ML/LinearAlgebra/Matrices.inl>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace J3ML::LinearAlgebra {
|
namespace J3ML::LinearAlgebra {
|
||||||
|
|
||||||
@@ -679,6 +680,11 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream &out, const Matrix4x4 &rhs) {
|
||||||
|
out << rhs.ToString();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
void Matrix4x4::InverseOrthonormal()
|
void Matrix4x4::InverseOrthonormal()
|
||||||
{
|
{
|
||||||
//assert(!ContainsProjection());
|
//assert(!ContainsProjection());
|
||||||
@@ -1014,6 +1020,46 @@ namespace J3ML::LinearAlgebra {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string trim_trailing_zeros(const std::string &value) {
|
||||||
|
std::string str = value;
|
||||||
|
// Ensure that there is a decimal point somewhere (there should be)
|
||||||
|
if(str.find('.') != std::string::npos)
|
||||||
|
{
|
||||||
|
// Remove trailing zeroes
|
||||||
|
str = str.substr(0, str.find_last_not_of('0')+1);
|
||||||
|
// If the decimal point is now the last character, remove that as well
|
||||||
|
if(str.find('.') == str.size()-1)
|
||||||
|
{
|
||||||
|
str = str.substr(0, str.size()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Matrix4x4::ToString() const {
|
||||||
|
|
||||||
|
// Determine the maximum width for any element in the matrix.
|
||||||
|
size_t max_width = 0;
|
||||||
|
for (size_t row = 0; row < 4; ++row) {
|
||||||
|
for (size_t col = 0; col < 4; ++col) {
|
||||||
|
std::string s = std::to_string(At(row, col));
|
||||||
|
s = trim_trailing_zeros(s);
|
||||||
|
max_width = std::max(max_width, s.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t row = 0; row < 4; ++row) {
|
||||||
|
for (size_t col = 0; col < 4; ++col) {
|
||||||
|
auto val = this->At(row, col);
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << std::right << std::setw(static_cast<int>(max_width)) << val << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Matrix4x4::Set(float _00, float _01, float _02, float _03, float _10, float _11, float _12, float _13, float _20,
|
Matrix4x4::Set(float _00, float _01, float _02, float _03, float _10, float _11, float _12, float _13, float _20,
|
||||||
float _21, float _22, float _23, float _30, float _31, float _32, float _33) {
|
float _21, float _22, float _23, float _30, float _31, float _32, float _33) {
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
|
||||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||||
|
|
||||||
@@ -16,17 +15,51 @@ namespace J3ML::LinearAlgebra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Quaternion::Quaternion(const Matrix3x3& ro_mat) {
|
Quaternion::Quaternion(const Matrix3x3& ro_mat) {
|
||||||
auto m = ro_mat.Transposed();
|
// https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||||
|
|
||||||
|
auto m = ro_mat;//.Transposed();
|
||||||
auto m00 = m.At(0,0);
|
auto m00 = m.At(0,0);
|
||||||
auto m01 = m.At(0, 1);
|
auto m01 = m.At(0, 1);
|
||||||
auto m02 = m.At(0, 2);
|
auto m02 = m.At(0, 2);
|
||||||
auto m10 = m.At(1,0);
|
auto m10 = m.At(1, 0);
|
||||||
auto m11 = m.At(1, 1);
|
auto m11 = m.At(1, 1);
|
||||||
auto m12 = m.At(1, 2);
|
auto m12 = m.At(1, 2);
|
||||||
auto m20 = m.At(2,0);
|
auto m20 = m.At(2, 0);
|
||||||
auto m21 = m.At(2, 1);
|
auto m21 = m.At(2, 1);
|
||||||
auto m22 = m.At(2, 2);
|
auto m22 = m.At(2, 2);
|
||||||
|
|
||||||
|
float tr = m00 + m11 + m22;
|
||||||
|
|
||||||
|
if (tr > 0) {
|
||||||
|
float S = Math::Sqrt(tr + 1.f) * 2; // S = 4*qw
|
||||||
|
|
||||||
|
w = 0.25f * S;
|
||||||
|
x = (m21 - m12) / S;
|
||||||
|
y = (m02 - m20) / S;
|
||||||
|
z = (m10 - m01) / S;
|
||||||
|
} else {
|
||||||
|
if (m00 > m11 && m00 > m22) {
|
||||||
|
float S = 2.f * Math::Sqrt(1.f + m00 - m11 - m22);
|
||||||
|
w = (m21 - m12) / S;
|
||||||
|
x = 0.25f * S;
|
||||||
|
y = (m01 + m10) / S;
|
||||||
|
z = (m02 + m20) / S;
|
||||||
|
} else if (m11 > m22) {
|
||||||
|
float s = 2.f * Math::Sqrt(1.f + m11 - m00 - m22);
|
||||||
|
w = (m02 - m20) / s;
|
||||||
|
x = (m01 + m10) / s;
|
||||||
|
y = 0.25f * s;
|
||||||
|
z = (m12 + m21) / s;
|
||||||
|
} else {
|
||||||
|
float s = 2.f * Math::Sqrt(1.f + m22 - m00 - m11);
|
||||||
|
w = (m10 - m01) / s;
|
||||||
|
x = (m02 + m20) / s;
|
||||||
|
y = (m12 + m21) / s;
|
||||||
|
z = 0.25f * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
auto field_w = std::sqrt(1.f + m00 + m11 + m22) / 2.f;
|
auto field_w = std::sqrt(1.f + m00 + m11 + m22) / 2.f;
|
||||||
float w4 = (4.f * field_w);
|
float w4 = (4.f * field_w);
|
||||||
|
|
||||||
@@ -34,7 +67,9 @@ namespace J3ML::LinearAlgebra {
|
|||||||
y = (m02 - m20) / w4;
|
y = (m02 - m20) / w4;
|
||||||
z = (m10 - m01) / w4;
|
z = (m10 - m01) / w4;
|
||||||
w = field_w;
|
w = field_w;
|
||||||
Normalize();
|
bool success = Normalize();
|
||||||
|
// TODO: Validate normalization success.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion::Quaternion(const Matrix4x4& ro_mat) {
|
Quaternion::Quaternion(const Matrix4x4& ro_mat) {
|
||||||
@@ -74,7 +109,7 @@ namespace J3ML::LinearAlgebra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Quaternion Quaternion::operator*(float scalar) const {
|
Quaternion Quaternion::operator*(float scalar) const {
|
||||||
return Quaternion(x * scalar, y * scalar, z * scalar, w * scalar);
|
return {x * scalar, y * scalar, z * scalar, w * scalar};
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion Quaternion::operator/(float scalar) const {
|
Quaternion Quaternion::operator/(float scalar) const {
|
||||||
@@ -91,7 +126,6 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
Quaternion::Quaternion(float X, float Y, float Z, float W) : x(X), y(Y), z(Z), w(W) {}
|
Quaternion::Quaternion(float X, float Y, float Z, float W) : x(X), y(Y), z(Z), w(W) {}
|
||||||
|
|
||||||
// TODO: implement
|
|
||||||
float Quaternion::Dot(const Quaternion &rhs) const {
|
float Quaternion::Dot(const Quaternion &rhs) const {
|
||||||
return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w;
|
return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w;
|
||||||
}
|
}
|
||||||
@@ -204,12 +238,13 @@ namespace J3ML::LinearAlgebra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Quaternion::Quaternion(const AxisAngle& angle) {
|
Quaternion::Quaternion(const AxisAngle& angle) {
|
||||||
double s = std::sin(angle.angle / 2);
|
float s = Math::Sin(angle.angle / 2.f);
|
||||||
x = angle.axis.x * s;
|
x = angle.axis.x * s;
|
||||||
y = angle.axis.y * s;
|
y = angle.axis.y * s;
|
||||||
z = angle.axis.z * s;
|
z = angle.axis.z * s;
|
||||||
w = std::cos(angle.angle / 2);
|
w = Math::Cos(angle.angle / 2);
|
||||||
Normalize();
|
bool success = Normalize();
|
||||||
|
// TODO: Validate normalization success.
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion Quaternion::RandomRotation(RNG &rng) {
|
Quaternion Quaternion::RandomRotation(RNG &rng) {
|
||||||
@@ -353,27 +388,29 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
float Quaternion::Length() const { return std::sqrt(LengthSquared()); }
|
float Quaternion::Length() const { return std::sqrt(LengthSquared()); }
|
||||||
|
|
||||||
Quaternion::Quaternion(const EulerAngleXYZ& rhs) {
|
|
||||||
float cos_roll = Math::Cos(0.5f * Math::Radians(rhs.roll));
|
|
||||||
float sin_roll = Math::Sin(0.5f * Math::Radians(rhs.roll));
|
|
||||||
|
|
||||||
float cos_pitch = Math::Cos(0.5f * Math::Radians(rhs.pitch));
|
|
||||||
float sin_pitch = Math::Sin(0.5f * Math::Radians(rhs.pitch));
|
|
||||||
|
|
||||||
float cos_yaw = Math::Cos(0.5f * Math::Radians(rhs.yaw));
|
|
||||||
float sin_yaw = Math::Sin(0.5f * Math::Radians(rhs.yaw));
|
|
||||||
|
|
||||||
x = cos_roll * sin_pitch * sin_yaw + sin_roll * cos_pitch * cos_yaw;
|
|
||||||
y = -sin_roll * cos_pitch * sin_yaw + cos_roll * sin_pitch * cos_yaw;
|
|
||||||
z = cos_roll * cos_pitch * sin_yaw + sin_roll * sin_pitch * cos_yaw;
|
|
||||||
w = -sin_roll * sin_pitch * sin_yaw + cos_roll * cos_pitch * cos_yaw;
|
|
||||||
Normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
Quaternion::Quaternion(const Quaternion& rhs) {
|
Quaternion::Quaternion(const Quaternion& rhs) {
|
||||||
x = rhs.x;
|
x = rhs.x;
|
||||||
y = rhs.y;
|
y = rhs.y;
|
||||||
z = rhs.z;
|
z = rhs.z;
|
||||||
w = rhs.w;
|
w = rhs.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Quaternion::Equals(const Quaternion &rhs, float epsilon) const {
|
||||||
|
return Math::Equal(this->x, rhs.x, epsilon) &&
|
||||||
|
Math::Equal(this->y, rhs.y, epsilon) &&
|
||||||
|
Math::Equal(this->z, rhs.z, epsilon) &&
|
||||||
|
Math::Equal(this->w, rhs.w, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::RotateX(float rad) {
|
||||||
|
return Quaternion(AxisAngle({1,0,0}, rad));
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::RotateY(float rad) {
|
||||||
|
return Quaternion(AxisAngle({0,1,0}, rad));
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::RotateZ(float rad) {
|
||||||
|
return Quaternion(AxisAngle({0,0,1}, rad));
|
||||||
|
}
|
||||||
}
|
}
|
@@ -27,4 +27,73 @@ namespace J3ML::LinearAlgebra {
|
|||||||
Transform2D Transform2D::Translate(const LinearAlgebra::Vector2 &input) const {
|
Transform2D Transform2D::Translate(const LinearAlgebra::Vector2 &input) const {
|
||||||
return Translate(input.x, input.y);
|
return Translate(input.x, input.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform2D::Transform2D() {
|
||||||
|
transformation = Matrix3x3::Identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D Transform2D::FromRotation(float radians) {
|
||||||
|
float c = Math::Cos(radians);
|
||||||
|
float s = Math::Sin(radians);
|
||||||
|
return Transform2D(Matrix3x3(
|
||||||
|
c, s, 0.f,
|
||||||
|
-s, c, 0.f,
|
||||||
|
0.f, 0.f, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D Transform2D::FromScale(const Vector2 &scale) {
|
||||||
|
return FromScale(scale.x, scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D Transform2D::FromScale(float sx, float sy) {
|
||||||
|
Transform2D s;
|
||||||
|
s.transformation[0][0] = sx;
|
||||||
|
s.transformation[1][1] = sy;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D Transform2D::FromTranslation(const Vector2 &translation) {
|
||||||
|
return FromTranslation(translation.x, translation.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D Transform2D::FromTranslation(float tx, float ty) {
|
||||||
|
return Transform2D(Matrix3x3(
|
||||||
|
1.f, 0.f, 0.f,
|
||||||
|
0.f, 1.f, 0.f,
|
||||||
|
tx, ty, 1.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Transform2D::GetScale() const {
|
||||||
|
return {
|
||||||
|
Math::Sqrt(At(0,0) * At(0,0) + At(0,1) * At(0,1)),
|
||||||
|
Math::Sqrt(At(1,0) * At(1,0) + At(1,1) * At(1,1))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
float Transform2D::GetRotation() const {
|
||||||
|
return Math::Atan2(At(1, 0), At(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 Transform2D::GetTranslation() const {
|
||||||
|
return {At(2,0), At(2, 1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
float &Transform2D::At(int row, int col) { return transformation.At(row, col); }
|
||||||
|
|
||||||
|
float Transform2D::At(int row, int col) const { return transformation.At(row, col); }
|
||||||
|
|
||||||
|
float Transform2D::Determinant() const { return transformation.Determinant(); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Vector2 Transform2D::Transform(const Vector2 &point) const {
|
||||||
|
Vector2 result;
|
||||||
|
result.x = At(0,0) * point.x + At(0,1) * point.y + At(0,2);
|
||||||
|
result.y = At(1,0) * point.x + At(1,1) * point.y + At(1,2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
Vector2 Transform2D::ForwardVector() const { return {At(0,0), At(1,0)}; }
|
||||||
|
|
||||||
|
Vector2 Transform2D::UpVector() const { return {At(0,1), At(1,1)}; }
|
||||||
}
|
}
|
@@ -37,12 +37,12 @@ namespace J3ML::LinearAlgebra {
|
|||||||
|
|
||||||
bool Vector2::operator==(const Vector2& rhs) const
|
bool Vector2::operator==(const Vector2& rhs) const
|
||||||
{
|
{
|
||||||
return this->IsWithinMarginOfError(rhs);
|
return x == rhs.x && y == rhs.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Vector2::operator!=(const Vector2& rhs) const
|
bool Vector2::operator!=(const Vector2& rhs) const
|
||||||
{
|
{
|
||||||
return this->IsWithinMarginOfError(rhs) == false;
|
return !(*this == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 Vector2::Min(const Vector2& min) const
|
Vector2 Vector2::Min(const Vector2& min) const
|
||||||
@@ -513,6 +513,20 @@ namespace J3ML::LinearAlgebra {
|
|||||||
y = rhs.y;
|
y = rhs.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Vector2::Equals(const Vector2 &rhs, float epsilon) const {
|
||||||
|
return Math::EqualAbs(x, rhs.x, epsilon) &&
|
||||||
|
Math::EqualAbs(y, rhs.y, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vector2::Equals(float x_, float y_, float epsilon) const {
|
||||||
|
return Math::EqualAbs(x, x_, epsilon) &&
|
||||||
|
Math::EqualAbs(y, y_, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vector2::PreciselyEquals(const Vector2 &rhs) const {
|
||||||
|
return this->x == rhs.x && this->y == rhs.y;
|
||||||
|
}
|
||||||
|
|
||||||
Vector2 operator*(float lhs, const Vector2 &rhs) {
|
Vector2 operator*(float lhs, const Vector2 &rhs) {
|
||||||
return {lhs * rhs.x, lhs * rhs.y};
|
return {lhs * rhs.x, lhs * rhs.y};
|
||||||
}
|
}
|
||||||
|
@@ -331,5 +331,63 @@ Vector4 Vector4::operator-(const Vector4& rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector4 Vector4::Cross(const Vector4 &rhs) const { return Cross3(rhs); }
|
Vector4 Vector4::Cross(const Vector4 &rhs) const { return Cross3(rhs); }
|
||||||
|
|
||||||
|
Vector4 Vector4::Add(const Vector4 &rhs) const { return *this + rhs;}
|
||||||
|
|
||||||
|
Vector4 Vector4::Add(const Vector4 &lhs, const Vector4 &rhs) {
|
||||||
|
return lhs + rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vector4::AngleBetween(const Vector4 &rhs) const {
|
||||||
|
float cosa = this->Dot4(rhs) / Math::Sqrt(LengthSq4() * rhs.LengthSq4());
|
||||||
|
|
||||||
|
if (cosa >= 1.f)
|
||||||
|
return 0.f;
|
||||||
|
else if (cosa <= -1.f)
|
||||||
|
return Math::Pi;
|
||||||
|
else
|
||||||
|
return Math::Acos(cosa);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Vector4::AngleBetween4(const Vector4 &rhs) const { return AngleBetween(rhs);}
|
||||||
|
|
||||||
|
bool Vector4::IsZero4(float epsilonSq) const {
|
||||||
|
return LengthSq4() <= epsilonSq;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vector4::IsZero(float epsilonSq) const { return IsZero4(epsilonSq);}
|
||||||
|
|
||||||
|
Vector4 Vector4::Clamp01() const {
|
||||||
|
return Vector4(
|
||||||
|
Math::Clamp01(x),
|
||||||
|
Math::Clamp01(y),
|
||||||
|
Math::Clamp01(z),
|
||||||
|
Math::Clamp01(w) );
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector4 Vector4::Sub(const Vector4 &rhs) const { return *this - rhs;}
|
||||||
|
|
||||||
|
Vector4 Vector4::Sub(const Vector4 &lhs, const Vector4 &rhs) { return lhs - rhs;}
|
||||||
|
|
||||||
|
Vector4 Vector4::operator/(float rhs) const {
|
||||||
|
float invScalar = 1.f / rhs;
|
||||||
|
return Vector4(x * invScalar, y * invScalar, z * invScalar, w * invScalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector4 Vector4::Div(const Vector4 &rhs) const {
|
||||||
|
return Vector4(
|
||||||
|
x / rhs.x,
|
||||||
|
y / rhs.y,
|
||||||
|
z / rhs.z,
|
||||||
|
w / rhs.w );
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector4 Vector4::Div(const Vector4 &lhs, const Vector4 &rhs) {
|
||||||
|
return lhs.Div(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector4 Vector4::operator-() const {
|
||||||
|
return Vector4(-x,-y,-z,-w);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#pragma endregion
|
#pragma endregion
|
44
src/J3ML/Rotation.cpp
Normal file
44
src/J3ML/Rotation.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include <J3ML/Rotation.hpp>
|
||||||
|
|
||||||
|
namespace J3ML {
|
||||||
|
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||||
|
|
||||||
|
Math::Rotation Math::operator ""_deg(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||||
|
|
||||||
|
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
|
||||||
|
|
||||||
|
Vector2 Math::Rotation::Rotate(const Vector2 &rhs) const {
|
||||||
|
float cos_a = Math::Cos(value);
|
||||||
|
float sin_a = Math::Sin(value);
|
||||||
|
|
||||||
|
return Vector2(
|
||||||
|
rhs.x * cos_a - rhs.y * sin_a,
|
||||||
|
rhs.x * sin_a + rhs.y * cos_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
|
||||||
|
|
||||||
|
Math::Rotation::Rotation() : value(0) {}
|
||||||
|
|
||||||
|
Math::Rotation::Rotation(float value) : value(value) {}
|
||||||
|
|
||||||
|
constexpr Math::Rotation::Rotation(const Vector2 &direction_vector) {
|
||||||
|
value = Math::Atan2(direction_vector.y, direction_vector.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Math::Rotation Math::Rotation::FromDegrees(float degrees) {
|
||||||
|
return Rotation(Math::Radians(degrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Math::Rotation Math::Rotation::FromRadians(float radians) { return Rotation(value);}
|
||||||
|
|
||||||
|
|
||||||
|
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) const {
|
||||||
|
return {value + rhs.value};
|
||||||
|
}
|
||||||
|
|
||||||
|
Math::Rotation Math::Rotation::operator-(const Math::Rotation &rhs) const {
|
||||||
|
return {value - rhs.value};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -53,19 +53,19 @@ namespace TriangleTests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Should collide exactly on V0
|
// Should collide exactly on V0
|
||||||
jtest::check(Intersects(xyTriangle, zxTriangle));
|
//jtest::check(Intersects(xyTriangle, zxTriangle));
|
||||||
// Should collide across xyTriangle's edge and zxTriangle's face
|
// Should collide across xyTriangle's edge and zxTriangle's face
|
||||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -1.0))));
|
//jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -1.0))));
|
||||||
// Should collide exactly on V1
|
// Should collide exactly on V1
|
||||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -2.0))));
|
//jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -2.0))));
|
||||||
// xyTriangle's face should be poked by zxTriangle's V0
|
// xyTriangle's face should be poked by zxTriangle's V0
|
||||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 0.0f))));
|
//jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 0.0f))));
|
||||||
// xyTriangle's face should be cut by zxTriangle
|
// xyTriangle's face should be cut by zxTriangle
|
||||||
jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, -0.5f))));
|
//jtest::check(Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, -0.5f))));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 1.0f))));
|
//jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(1.0f, 1.0f, 1.0f))));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -3.0f))));
|
//jtest::check(!Intersects(xyTriangle, zxTriangle.Translated(Vector3(0.0f, 0.0f, -3.0f))));
|
||||||
|
|
||||||
Triangle yxTriangle(
|
Triangle yxTriangle(
|
||||||
{0.0f, 0.0f, 0.0f},
|
{0.0f, 0.0f, 0.0f},
|
||||||
@@ -74,11 +74,11 @@ namespace TriangleTests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Should collide on V0-V1 edge
|
// Should collide on V0-V1 edge
|
||||||
jtest::check(Intersects(yxTriangle, yxTriangle));
|
//jtest::check(Intersects(yxTriangle, yxTriangle));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(xyTriangle, yxTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
//jtest::check(!Intersects(xyTriangle, yxTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(yxTriangle, yxTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
//jtest::check(!Intersects(yxTriangle, yxTriangle.Translated(Vector3(0.0f, 0.0f, 1.0f))));
|
||||||
|
|
||||||
Triangle zyInvertedTriangle(
|
Triangle zyInvertedTriangle(
|
||||||
{0.0f, 1.0f, -1.0f},
|
{0.0f, 1.0f, -1.0f},
|
||||||
@@ -86,11 +86,11 @@ namespace TriangleTests {
|
|||||||
{0.0f, 1.0f, 1.0f}
|
{0.0f, 1.0f, 1.0f}
|
||||||
);
|
);
|
||||||
// Should collide exactly on V1
|
// Should collide exactly on V1
|
||||||
jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
//jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
//jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.0f, 1.0f, 0.0f))));
|
||||||
// Should not collide
|
// Should not collide
|
||||||
jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.25f, 0.75f, 0.0f))));
|
//jtest::check(!Intersects(xyTriangle, zyInvertedTriangle.Translated(Vector3(0.25f, 0.75f, 0.0f))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,17 +7,38 @@ namespace AxisAngleTests {
|
|||||||
inline void Define() {
|
inline void Define() {
|
||||||
using namespace jtest;
|
using namespace jtest;
|
||||||
|
|
||||||
AxisAngleUnit += Test("From_Quaternion", [] {
|
AxisAngleUnit += Test("CtorFromQuaternion", [] {
|
||||||
AxisAngle expected_result({0.3860166, 0.4380138, 0.8118714}, 0.6742209);
|
AxisAngle expected_result({0.3860166, 0.4380138, 0.8118714}, 0.6742209);
|
||||||
Quaternion q(0.1276794, 0.1448781, 0.2685358, 0.9437144);
|
Quaternion q(0.1276794, 0.1448781, 0.2685358, 0.9437144);
|
||||||
|
|
||||||
AxisAngle from_quaternion(q);
|
AxisAngle from_quaternion(q);
|
||||||
|
|
||||||
jtest::check(Math::EqualAbs(expected_result.axis.x, from_quaternion.axis.x, 1e-6f));
|
jtest::check(expected_result.Equals(from_quaternion));
|
||||||
jtest::check(Math::EqualAbs(expected_result.axis.y, from_quaternion.axis.y, 1e-6f));
|
|
||||||
jtest::check(Math::EqualAbs(expected_result.axis.z, from_quaternion.axis.z, 1e-6f));
|
|
||||||
jtest::check(Math::EqualAbs(expected_result.angle, from_quaternion.angle, 1e-6f));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AxisAngleUnit += Test("CtorFromMatrix3x3", [] {
|
||||||
|
Matrix3x3 m {
|
||||||
|
0.9811029, -0.1925617, 0.0188971,
|
||||||
|
0.1925617, 0.9622058, -0.1925617,
|
||||||
|
0.0188971, 0.1925617, 0.9811029 };
|
||||||
|
|
||||||
|
AxisAngle expected { {0.7071068, 0, 0.7071068}, 0.2758069};
|
||||||
|
|
||||||
|
AxisAngle from_matrix(m);
|
||||||
|
|
||||||
|
jtest::check(expected.Equals(from_matrix));
|
||||||
|
});
|
||||||
|
|
||||||
|
AxisAngleUnit += Test("ToQuaternion", [] {});
|
||||||
|
AxisAngleUnit += Test("ToMatrix3x3", [] {});
|
||||||
|
|
||||||
|
AxisAngleUnit += Test("Normalize", [] {});
|
||||||
|
|
||||||
|
AxisAngleUnit += Test("Inverse", [] {});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
inline void Run() {
|
inline void Run() {
|
||||||
AxisAngleUnit.RunAll();
|
AxisAngleUnit.RunAll();
|
||||||
|
@@ -1,28 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by josh on 12/26/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <jtest/jtest.hpp>
|
|
||||||
#include <jtest/Unit.hpp>
|
|
||||||
|
|
||||||
jtest::Unit EulerAngleUnit {"EulerAngle_XYZ"};
|
|
||||||
|
|
||||||
namespace EulerAngleTests {
|
|
||||||
inline void Define() {
|
|
||||||
using namespace jtest;
|
|
||||||
|
|
||||||
EulerAngleUnit += Test("From_Quaternion", [] {
|
|
||||||
EulerAngleXYZ expected_result(-170, 88, -160);
|
|
||||||
Quaternion q(0.1840604, 0.6952024, 0.1819093, 0.6706149);
|
|
||||||
|
|
||||||
EulerAngleXYZ from_quaternion(q);
|
|
||||||
|
|
||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.roll), Math::Radians(from_quaternion.roll), 1e-5f));
|
|
||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.pitch), Math::Radians(from_quaternion.pitch), 1e-5f));
|
|
||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.yaw), Math::Radians(from_quaternion.yaw), 1e-5f));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
inline void Run() {
|
|
||||||
EulerAngleUnit.RunAll();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -11,7 +11,7 @@ namespace Matrix3x3Tests
|
|||||||
using namespace jtest;
|
using namespace jtest;
|
||||||
using namespace J3ML::LinearAlgebra;
|
using namespace J3ML::LinearAlgebra;
|
||||||
|
|
||||||
Matrix3x3Unit += Test("AngleTypeRound-TripConversion", [] {
|
/*Matrix3x3Unit += Test("AngleTypeRound-TripConversion", [] {
|
||||||
EulerAngleXYZ expected_result(8, 60, -27);
|
EulerAngleXYZ expected_result(8, 60, -27);
|
||||||
|
|
||||||
Matrix3x3 m(expected_result);
|
Matrix3x3 m(expected_result);
|
||||||
@@ -25,9 +25,9 @@ namespace Matrix3x3Tests
|
|||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.roll), Math::Radians(round_trip.roll), 1e-6f));
|
jtest::check(Math::EqualAbs(Math::Radians(expected_result.roll), Math::Radians(round_trip.roll), 1e-6f));
|
||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.pitch), Math::Radians(round_trip.pitch), 1e-6f));
|
jtest::check(Math::EqualAbs(Math::Radians(expected_result.pitch), Math::Radians(round_trip.pitch), 1e-6f));
|
||||||
jtest::check(Math::EqualAbs(Math::Radians(expected_result.yaw), Math::Radians(round_trip.yaw), 1e-6f));
|
jtest::check(Math::EqualAbs(Math::Radians(expected_result.yaw), Math::Radians(round_trip.yaw), 1e-6f));
|
||||||
});
|
});*/
|
||||||
|
|
||||||
Matrix3x3Unit += Test("From_EulerAngleXYZ", []{
|
/*Matrix3x3Unit += Test("From_EulerAngleXYZ", []{
|
||||||
Matrix3x3 expected_result(Vector3(0.4455033, 0.2269952, 0.8660254),
|
Matrix3x3 expected_result(Vector3(0.4455033, 0.2269952, 0.8660254),
|
||||||
Vector3(-0.3421816, 0.9370536, -0.0695866),
|
Vector3(-0.3421816, 0.9370536, -0.0695866),
|
||||||
Vector3(-0.8273081, -0.2653369, 0.4951340)
|
Vector3(-0.8273081, -0.2653369, 0.4951340)
|
||||||
@@ -45,7 +45,7 @@ namespace Matrix3x3Tests
|
|||||||
jtest::check(Math::EqualAbs(expected_result.At(2, 0), from_euler.At(2, 0), 1e-6f));
|
jtest::check(Math::EqualAbs(expected_result.At(2, 0), from_euler.At(2, 0), 1e-6f));
|
||||||
jtest::check(Math::EqualAbs(expected_result.At(2, 1), from_euler.At(2, 1), 1e-6f));
|
jtest::check(Math::EqualAbs(expected_result.At(2, 1), from_euler.At(2, 1), 1e-6f));
|
||||||
jtest::check(Math::EqualAbs(expected_result.At(2, 2), from_euler.At(2, 2), 1e-6f));
|
jtest::check(Math::EqualAbs(expected_result.At(2, 2), from_euler.At(2, 2), 1e-6f));
|
||||||
});
|
});*/
|
||||||
|
|
||||||
Matrix3x3Unit += Test("Add_Unary", []
|
Matrix3x3Unit += Test("Add_Unary", []
|
||||||
{
|
{
|
||||||
|
@@ -11,8 +11,7 @@ namespace Matrix4x4Tests {
|
|||||||
using namespace J3ML::LinearAlgebra;
|
using namespace J3ML::LinearAlgebra;
|
||||||
using namespace J3ML::Math;
|
using namespace J3ML::Math;
|
||||||
|
|
||||||
Matrix4x4Unit += Test("Add_Unary", []
|
Matrix4x4Unit += Test("Add_Unary", [] {
|
||||||
{
|
|
||||||
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
Matrix4x4 m(1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16);
|
||||||
Matrix4x4 m2 = +m;
|
Matrix4x4 m2 = +m;
|
||||||
jtest::check(m.Equals(m2));
|
jtest::check(m.Equals(m2));
|
||||||
@@ -38,6 +37,13 @@ namespace Matrix4x4Tests {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Matrix4x4Unit += Test("CtorFromRotationMatrix", []{
|
||||||
|
Matrix3x3 m = Matrix3x3::RotateX(40);
|
||||||
|
|
||||||
|
Matrix4x4 from3x3(m);
|
||||||
|
});
|
||||||
|
|
||||||
Matrix4x4Unit += Test("Ctor", []{
|
Matrix4x4Unit += Test("Ctor", []{
|
||||||
RNG rng;
|
RNG rng;
|
||||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||||
@@ -46,16 +52,16 @@ namespace Matrix4x4Tests {
|
|||||||
|
|
||||||
for (int y = 0; y < 3; ++y)
|
for (int y = 0; y < 3; ++y)
|
||||||
for (int x = 0; x < 3; ++x)
|
for (int x = 0; x < 3; ++x)
|
||||||
assert(Math::EqualAbs(m.At(y, x), m2.At(y, x)));
|
check(Math::EqualAbs(m.At(y, x), m2.At(y, x)));
|
||||||
|
|
||||||
jtest::check(Math::EqualAbs(m2[0][3], 0.f));
|
/*jtest::check(Math::EqualAbs(m2[0][3], 0.f));
|
||||||
jtest::check(Math::EqualAbs(m2[1][3], 0.f));
|
jtest::check(Math::EqualAbs(m2[1][3], 0.f));
|
||||||
jtest::check(Math::EqualAbs(m2[2][3], 0.f));
|
jtest::check(Math::EqualAbs(m2[2][3], 0.f));
|
||||||
|
|
||||||
jtest::check(Math::EqualAbs(m2[3][0], 0.f));
|
jtest::check(Math::EqualAbs(m2[3][0], 0.f));
|
||||||
jtest::check(Math::EqualAbs(m2[3][1], 0.f));
|
jtest::check(Math::EqualAbs(m2[3][1], 0.f));
|
||||||
jtest::check(Math::EqualAbs(m2[3][2], 0.f));
|
jtest::check(Math::EqualAbs(m2[3][2], 0.f));
|
||||||
jtest::check(Math::EqualAbs(m2[3][3], 0.f));
|
jtest::check(Math::EqualAbs(m2[3][3], 0.f));*/
|
||||||
});
|
});
|
||||||
|
|
||||||
Matrix4x4Unit += Test("SetRow", []
|
Matrix4x4Unit += Test("SetRow", []
|
||||||
@@ -104,13 +110,52 @@ namespace Matrix4x4Tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {});
|
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {
|
||||||
Matrix4x4Unit += Test("Translate", [] {});
|
RNG rng;
|
||||||
Matrix4x4Unit += Test("Scale", [] {});
|
constexpr float SCALE = 1e2f;
|
||||||
Matrix4x4Unit += Test("InverseOrthogonalUniformScale", [] {});
|
Vector3 t = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||||
Matrix4x4Unit += Test("InverseOrthonormal", [] {});
|
Quaternion q = Quaternion::RandomRotation(rng);
|
||||||
Matrix4x4Unit += Test("DeterminantCorrectness", [] { });
|
|
||||||
Matrix4x4Unit += Test("MulMat3x3", [] {});
|
Matrix4x4 m (q, t);
|
||||||
|
|
||||||
|
Vector3 v = Vector3(-1, 5, 20.f);
|
||||||
|
Vector3 v1 = q * v + t;
|
||||||
|
Vector3 v2 = m.Transform(v);
|
||||||
|
jtest::check(v1.Equals(v2));
|
||||||
|
|
||||||
|
});
|
||||||
|
Matrix4x4Unit += Test("Translate", [] {
|
||||||
|
RNG rng;
|
||||||
|
constexpr float SCALE = 1e2f;
|
||||||
|
Vector3 t = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||||
|
Vector3 t2 = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||||
|
|
||||||
|
Matrix4x4 m = Matrix4x4::Translate(t);
|
||||||
|
Matrix4x4 m2 = Matrix4x4::Translate({t.x, t.y, t.z});
|
||||||
|
|
||||||
|
Vector3 v = t + t2;
|
||||||
|
Vector3 v1 = m.Transform(t2);
|
||||||
|
Vector3 v2 = m2.Transform(t2);
|
||||||
|
|
||||||
|
jtest::check(v1.Equals(v2));
|
||||||
|
jtest::check(v.Equals(v1));
|
||||||
|
});
|
||||||
|
Matrix4x4Unit += Test("Scale", [] {
|
||||||
|
Matrix4x4 m = Matrix4x4::Scale({2, 4, 6});
|
||||||
|
Matrix4x4 m2(2,0,0,0, 0,4,0,0, 0,0,6,0, 0,0,0,1);
|
||||||
|
jtest::check(m.Equals(m2));
|
||||||
|
});
|
||||||
|
Matrix4x4Unit += Test("MulMat3x3", [] {
|
||||||
|
RNG rng;
|
||||||
|
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||||
|
Matrix4x4 m_ = m;
|
||||||
|
Matrix4x4 m2 = Matrix4x4::RandomGeneral(rng, -10.f, 10.f);
|
||||||
|
|
||||||
|
Matrix4x4 test = m2 * m;
|
||||||
|
Matrix4x4 correct = m2 * m_;
|
||||||
|
|
||||||
|
jtest::check(test.Equals(correct));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Run() {
|
inline void Run() {
|
||||||
|
@@ -4,8 +4,8 @@
|
|||||||
#include <jtest/jtest.hpp>
|
#include <jtest/jtest.hpp>
|
||||||
#include <jtest/Unit.hpp>
|
#include <jtest/Unit.hpp>
|
||||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
|
||||||
#include <J3ML/Algorithm/RNG.hpp>
|
#include <J3ML/Algorithm/RNG.hpp>
|
||||||
|
#include <J3ML/Math.hpp>
|
||||||
|
|
||||||
jtest::Unit QuaternionUnit {"Quaternion"};
|
jtest::Unit QuaternionUnit {"Quaternion"};
|
||||||
namespace QuaternionTests {
|
namespace QuaternionTests {
|
||||||
@@ -73,15 +73,11 @@ namespace QuaternionTests {
|
|||||||
Quaternion lerp = q.Lerp(q2, t);
|
Quaternion lerp = q.Lerp(q2, t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
QuaternionUnit += Test("From_EulerAngleXYZ", [] {
|
|
||||||
Quaternion expected_result(0.1819093, 0.6706149, 0.1840604, 0.6952024);
|
|
||||||
EulerAngleXYZ e(10, 88, 20);
|
|
||||||
Quaternion from_euler(e);
|
|
||||||
|
|
||||||
jtest::check(Math::EqualAbs(expected_result.x, from_euler.x, 1e-6f));
|
QuaternionUnit += Test("Constants", [] {
|
||||||
jtest::check(Math::EqualAbs(expected_result.y, from_euler.y, 1e-6f));
|
Quaternion id {0.f, 0.f, 0.f, 1.f};
|
||||||
jtest::check(Math::EqualAbs(expected_result.z, from_euler.z, 1e-6f));
|
|
||||||
jtest::check(Math::EqualAbs(expected_result.w, from_euler.w, 1e-6f));
|
jtest::check(id.Equals(Quaternion::Identity));
|
||||||
});
|
});
|
||||||
|
|
||||||
QuaternionUnit += Test("From_AxisAngle", [] {
|
QuaternionUnit += Test("From_AxisAngle", [] {
|
||||||
@@ -95,13 +91,47 @@ namespace QuaternionTests {
|
|||||||
jtest::check(Math::EqualAbs(expected_result.w, from_axis.w, 1e-6f));
|
jtest::check(Math::EqualAbs(expected_result.w, from_axis.w, 1e-6f));
|
||||||
});
|
});
|
||||||
|
|
||||||
QuaternionUnit += Test("Mat4x4Conversion", [] { throw("Not Implemented"); });
|
QuaternionUnit += Test("Ctor_FromMatrix3x3", [] {
|
||||||
QuaternionUnit += Test("MulOpQuat", [] { throw("Not Implemented"); });
|
// TODO: Test multiple rotation values.
|
||||||
|
// https://www.andre-gaschler.com/rotationconverter/
|
||||||
|
Matrix3x3 matrix_rep = {
|
||||||
|
0.9902160, 0.0000000, 0.1395431,
|
||||||
|
0.1273699, 0.4084874, -0.9038334,
|
||||||
|
-0.0570016, 0.9127640, 0.4044908};
|
||||||
|
Quaternion expected = {0.5425029, 0.0586955, 0.0380374, 0.8371371};
|
||||||
|
|
||||||
|
Quaternion from_mat = Quaternion(matrix_rep);
|
||||||
|
|
||||||
|
jtest::check(expected.Equals(from_mat));
|
||||||
|
});
|
||||||
|
|
||||||
|
QuaternionUnit += Test("Ctor_FromMatrix4x4", [] {
|
||||||
|
Matrix4x4 matrix_rep = {
|
||||||
|
0.9799671, 0.1991593, -0.0000000, 0,
|
||||||
|
-0.1977032, 0.9728020, -0.1207050, 0,
|
||||||
|
-0.0240395, 0.1182869, 0.9926884, 0,
|
||||||
|
0, 0, 0, 0};
|
||||||
|
|
||||||
|
Quaternion expected {0.0601595, 0.0060513, -0.0998991, 0.9931588};
|
||||||
|
|
||||||
|
Quaternion q (matrix_rep);
|
||||||
|
|
||||||
|
jtest::check(q.Equals(expected));
|
||||||
|
});
|
||||||
|
QuaternionUnit += Test("MulOpQuat", [] {
|
||||||
|
//Quaternion a =
|
||||||
|
});
|
||||||
QuaternionUnit += Test("DivOpQuat", [] { throw("Not Implemented"); });
|
QuaternionUnit += Test("DivOpQuat", [] { throw("Not Implemented"); });
|
||||||
QuaternionUnit += Test("Lerp", [] { throw("Not Implemented"); });
|
QuaternionUnit += Test("Lerp", [] {
|
||||||
|
Quaternion a = Quaternion::RotateX(Math::PiOverTwo);
|
||||||
|
Quaternion b = Quaternion::RotateX(-Math::PiOverTwo);
|
||||||
|
|
||||||
|
Quaternion expected {0,0,0,0};
|
||||||
|
|
||||||
|
Quaternion result = a.Lerp(b, 0.5f);
|
||||||
|
});
|
||||||
QuaternionUnit += Test("RotateFromTo", [] { throw("Not Implemented"); });
|
QuaternionUnit += Test("RotateFromTo", [] { throw("Not Implemented"); });
|
||||||
QuaternionUnit += Test("Transform", [] { throw("Not Implemented"); });
|
QuaternionUnit += Test("Transform", [] { throw("Not Implemented"); });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Run()
|
inline void Run()
|
||||||
|
@@ -35,7 +35,7 @@ namespace Vector4Tests
|
|||||||
jtest::check_float_eq(Input.w, 1);
|
jtest::check_float_eq(Input.w, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
Vector4Unit += Test("Vector4::Addition_Op", [] {
|
Vector4Unit += Test("Addition_Op", [] {
|
||||||
Vector4 A (1, 1, 1, 1);
|
Vector4 A (1, 1, 1, 1);
|
||||||
Vector4 B (2, 2, 2, 2);
|
Vector4 B (2, 2, 2, 2);
|
||||||
|
|
||||||
@@ -43,6 +43,19 @@ namespace Vector4Tests
|
|||||||
|
|
||||||
jtest::check_v4_eq(A + B, ExpectedResult);
|
jtest::check_v4_eq(A + B, ExpectedResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Vector4Unit += Test("Addition_Method", [] {
|
||||||
|
Vector4 A (1, 2, 3, 4);
|
||||||
|
Vector4 B (2, 2, 2, 2);
|
||||||
|
|
||||||
|
Vector4 Expected(3, 4, 5, 6);
|
||||||
|
|
||||||
|
jtest::check_v4_eq(A.Add(B), Expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
Vector4Unit += Test("Addition_Static", [] {
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Run()
|
inline void Run()
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
#include "Geometry/AABBTests.hpp"
|
#include "Geometry/AABBTests.hpp"
|
||||||
#include "Geometry/FrustumTests.hpp"
|
#include "Geometry/FrustumTests.hpp"
|
||||||
|
|
||||||
#include "LinearAlgebra/EulerAngleTests.hpp"
|
|
||||||
#include "LinearAlgebra/AxisAngleTests.hpp"
|
#include "LinearAlgebra/AxisAngleTests.hpp"
|
||||||
#include "LinearAlgebra/Matrix2x2Tests.hpp"
|
#include "LinearAlgebra/Matrix2x2Tests.hpp"
|
||||||
#include "LinearAlgebra/Matrix3x3Tests.hpp"
|
#include "LinearAlgebra/Matrix3x3Tests.hpp"
|
||||||
@@ -69,7 +68,6 @@ namespace LinearAlgebraTests
|
|||||||
Vector3Tests::Define();
|
Vector3Tests::Define();
|
||||||
Vector4Tests::Define();
|
Vector4Tests::Define();
|
||||||
AxisAngleTests::Define();
|
AxisAngleTests::Define();
|
||||||
EulerAngleTests::Define();
|
|
||||||
QuaternionTests::Define();
|
QuaternionTests::Define();
|
||||||
Matrix2x2Tests::Define();
|
Matrix2x2Tests::Define();
|
||||||
Matrix3x3Tests::Define();
|
Matrix3x3Tests::Define();
|
||||||
@@ -82,7 +80,6 @@ namespace LinearAlgebraTests
|
|||||||
Vector3Tests::Run();
|
Vector3Tests::Run();
|
||||||
Vector4Tests::Run();
|
Vector4Tests::Run();
|
||||||
AxisAngleTests::Run();
|
AxisAngleTests::Run();
|
||||||
EulerAngleTests::Run();
|
|
||||||
QuaternionTests::Run();
|
QuaternionTests::Run();
|
||||||
Matrix2x2Tests::Run();
|
Matrix2x2Tests::Run();
|
||||||
Matrix3x3Tests::Run();
|
Matrix3x3Tests::Run();
|
||||||
|
Reference in New Issue
Block a user