Compare commits
66 Commits
Release-3.
...
main
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 | |||
4de703209c | |||
6aa4a33121 | |||
b24328488b | |||
1e3e2f42f2 | |||
88dad23e50 | |||
f4d8523bdc | |||
df2c8b31bf | |||
d715391d2a | |||
13a68eea45 | |||
79e617b780 | |||
aaea5ff53e | |||
2caa4c8412 | |||
bb1b1b5a13 | |||
fa6d2fefcc | |||
80b752128c | |||
3fc9ca3954 | |||
af75700c46 | |||
bf794ce092 | |||
192b93ded4 | |||
85aac1c192 | |||
29db4f0792 | |||
143b7e7279 | |||
3861741ff2 | |||
262603a496 | |||
5e0e4b8349 | |||
|
756316169e | ||
237c318bf1 |
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.18...3.28)
|
||||
cmake_minimum_required(VERSION 3.18...3.27)
|
||||
PROJECT(J3ML
|
||||
VERSION 1.1
|
||||
LANGUAGES CXX
|
||||
@@ -34,12 +34,12 @@ set_target_properties(J3ML PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
CPMAddPackage(
|
||||
NAME jtest
|
||||
URL https://git.redacted.cc/josh/jtest/archive/Release-1.2.zip
|
||||
URL https://git.redacted.cc/josh/jtest/archive/Release-1.5.zip
|
||||
)
|
||||
|
||||
target_include_directories(J3ML PUBLIC ${jtest_SOURCE_DIR}/include)
|
||||
|
||||
target_link_libraries(J3ML PUBLIC jtest)
|
||||
target_link_libraries(J3ML PUBLIC jlog jtest)
|
||||
|
||||
if(WIN32)
|
||||
#target_compile_options(J3ML PRIVATE -Wno-multichar)
|
||||
@@ -58,4 +58,4 @@ target_link_libraries(MathDemo ${PROJECT_NAME})
|
||||
|
||||
if(WIN32)
|
||||
#target_compile_options(MathDemo PRIVATE -mwindows)
|
||||
endif()
|
||||
endif()
|
||||
|
4
Doxyfile
4
Doxyfile
@@ -48,13 +48,13 @@ PROJECT_NAME = J3ML
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
PROJECT_NUMBER = 3.1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
# quick idea about the purpose of the project. Keep the description short.
|
||||
|
||||
PROJECT_BRIEF = "Linear Algebra, Geometry, and Algorithms in C++"
|
||||
PROJECT_BRIEF = "Linear Algebra, Geometry, and Algorithms in C++ (v3.1)"
|
||||
|
||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||
# in the documentation. The maximum height of the logo should not exceed 55
|
||||
|
77
README.md
77
README.md
@@ -4,13 +4,13 @@
|
||||
|
||||
Yet Another C++ Math Standard
|
||||
|
||||
J3ML is a "Modern C++" C++ library designed to provide comprehensive support for 3D mathematical operations commonly used in computer graphics, game development, physics simulations, and related fields. It offers a wide range of functionalities to simplify the implementation of complex mathematical operations in your projects.
|
||||
J3ML is a "Modern C++" library designed to provide comprehensive support for 3D mathematical operations commonly used in computer graphics, game development, physics simulations, and related fields. It offers a wide range of functionalities to simplify the implementation of complex mathematical operations in your projects.
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
* **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.
|
||||
@@ -18,29 +18,68 @@ J3ML is a "Modern C++" C++ library designed to provide comprehensive support for
|
||||
* **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.
|
||||
|
||||
# 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
|
||||
#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>
|
||||
|
||||
int main() {
|
||||
// Create two 3D vectors
|
||||
Vector3 v1(1.0, 2.0, 3.0);
|
||||
Vector3 v2(4.0, 5.0, 6.0);
|
||||
|
||||
// Perform vector addition
|
||||
Vector3 result = v1 + v2;
|
||||
|
||||
// Output the result
|
||||
std::cout << "Result: " << result << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Matrix3x3 mRotation = Matrix3x3::RotateX(Math::PiOverTwo);
|
||||
Quaternion qRotation(mRotation); // Convert to Quaternion
|
||||
AxisAngle aRotation(qRotation); // Convert to AxisAngle
|
||||
EulerAngleXYZ eRotation(aRotation); // Convert to Euler Angle (XYZ)
|
||||
```
|
||||
|
||||
For more detailed usage instructions and examples, please refer to the documentation.
|
||||
@@ -50,7 +89,7 @@ Documentation is automatically generated from latest commit and is hosted at htt
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions to J3ML are welcome! If you find a bug, have a feature request, or would like to contribute code, please submit an issue or pull request to the GitHub repository.
|
||||
Contributions to J3ML are welcome! If you find a bug, have a feature request, or would like to contribute code, please submit an issue or pull request to the repository.
|
||||
|
||||
# License
|
||||
|
||||
|
@@ -17,7 +17,7 @@
|
||||
// Transcribed from here: explicit form and derivative
|
||||
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B%C3%A9zier_curves
|
||||
|
||||
#include "J3ML/LinearAlgebra/Vector2.hpp"
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
|
||||
namespace J3ML::Algorithm
|
||||
{
|
||||
@@ -29,17 +29,61 @@ namespace J3ML::Algorithm
|
||||
template <typename T>
|
||||
inline T Cube(T f) { return f * f * f; }
|
||||
|
||||
/// Four points P0, P1, P2, P3 in the plane space define a cubic Bezier curve.
|
||||
/// The curve can be modeled as a polynomial of third order.
|
||||
/// The curve starts at P0, going toward P1, and arrives at P3 coming from the direction of P2.
|
||||
/// Usually, it will not pass through P1, or P2, these points are only there to provide directional information.
|
||||
template <typename T>
|
||||
inline T Bezier(float t, const T& p0, const T& p1, const T& p2, const T& p3)
|
||||
{
|
||||
return Cube(1 - t) * p0 + 3 * Square(1 - t) * t * p1 + 3 * (1 - t) * Square(t) * p2 + Cube(t) * p3;
|
||||
}
|
||||
|
||||
/// Computes a point along a 2-dimensional Cubic Bezier curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1
|
||||
/// @param p2
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector2 Bezier(float t, const Vector2& p0, const Vector2& p1, const Vector2& p2, const Vector2& p3);
|
||||
|
||||
// Tangent
|
||||
/// Computes a point along the tangent of a 2-dimensional Cubic Bezier Curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1
|
||||
/// @param p2
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector2 BezierDerivative(float t, const Vector2& p0, const Vector2& p1, const Vector2& p2, const Vector2& p3);
|
||||
|
||||
// Normal
|
||||
/// Computes a point along the normal of a 2-dimensional Cubic Bezier Curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1 The first control point, which determines the direction at which the curve meets point 0.
|
||||
/// @param p2 The second control point, which determines the direction at which the curve meets point 3.
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector2 BezierNormal(float t, const Vector2& p0, const Vector2& p1, const Vector2& p2, const Vector2& p3);
|
||||
|
||||
/// Computes a point along a 3-dimensional Cubic Bezier curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1 The first control point, which determines the direction at which the curve meets point 0.
|
||||
/// @param p2 The second control point, which determines the direction at which the curve meets point 3.
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector3 Bezier(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3);
|
||||
|
||||
/// Computes a point along the tangent of a 3-dimensional Cubic Bezier Curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1 The first control point, which determines the direction at which the curve meets point 0.
|
||||
/// @param p2 The second control point, which determines the direction at which the curve meets point 3.
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector3 BezierDerivative(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3);
|
||||
|
||||
/// Computes a point along the normal of a 3-dimensional Cubic Bezier Curve.
|
||||
/// @param t The normalized distance along the curve to compute, with range of [0, 1].
|
||||
/// @param p0 The start-point of the curve.
|
||||
/// @param p1 The first control point, which determines the direction at which the curve meets point 0.
|
||||
/// @param p2 The second control point, which determines the direction at which the curve meets point 3.
|
||||
/// @param p3 The end-point of the curve.
|
||||
Vector3 BezierNormal(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3);
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
// @file GJK.hpp
|
||||
/// @file GJK.hpp
|
||||
/// Implementation of the Gilbert-Johnson-Keerthi (GJK) convex polyhedron intersection test
|
||||
|
||||
#pragma once
|
||||
|
17
include/J3ML/Algorithm/Parabola.hpp
Normal file
17
include/J3ML/Algorithm/Parabola.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/// 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 Parabola.hpp
|
||||
/// @desc Algorithm for calculating a parabolic curve to be used in instantaneous bullet raycasting.
|
||||
/// @edit 2024-10-22
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace J3ML
|
||||
{
|
||||
|
||||
}
|
18
include/J3ML/Algorithm/Triangulate.hpp
Normal file
18
include/J3ML/Algorithm/Triangulate.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
/// 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 Parabola.hpp
|
||||
/// @desc Algorithm for calculating a parabolic curve to be used in instantaneous bullet raycasting.
|
||||
/// @edit 2024-10-22
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace J3ML
|
||||
{
|
||||
/// @see class Polygon::Triangulate for current implementation.
|
||||
}
|
@@ -7,8 +7,7 @@
|
||||
|
||||
/// @file AABB2D.hpp
|
||||
/// @desc A 2D Axis-Aligned Bounding Box structure.
|
||||
/// @edit 2024-08-01
|
||||
/// @note On backlog, low-priority.
|
||||
/// @edit 2025-04-18
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -16,9 +15,19 @@
|
||||
#include <J3ML/Geometry/Shape.hpp>
|
||||
#include <J3ML/Geometry/Forward.hpp>
|
||||
|
||||
|
||||
/// See Christer Ericson's Real-time Collision Detection, p. 87, or
|
||||
/// James Arvo's "Transforming Axis-aligned Bounding Boxes" in Graphics Gems 1, pp. 548-550.
|
||||
/// http://www.graphicsgems.org/
|
||||
template <typename Matrix>
|
||||
void AABB2DTransformAsAABB2D(AABB2D& aabb, Matrix& m);
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
using LinearAlgebra::Vector2;
|
||||
|
||||
// TODO: Integer AABB2D for even leaner box computation.
|
||||
|
||||
// CaveGame AABB
|
||||
class AABB2D : public Shape2D
|
||||
{
|
||||
@@ -31,28 +40,30 @@ namespace J3ML::Geometry
|
||||
minPoint(min), maxPoint(max)
|
||||
{}
|
||||
|
||||
float Width() const;
|
||||
float Height() const;
|
||||
[[nodiscard]] float Width() const;
|
||||
[[nodiscard]] float Height() const;
|
||||
|
||||
float DistanceSq(const Vector2& pt) const;
|
||||
Vector2 Centroid() const;
|
||||
|
||||
[[nodiscard]] float DistanceSq(const Vector2& pt) const;
|
||||
|
||||
void SetNegativeInfinity();
|
||||
|
||||
void Enclose(const Vector2& point);
|
||||
|
||||
bool Intersects(const AABB2D& rhs) const;
|
||||
[[nodiscard]] bool Intersects(const AABB2D& rhs) const;
|
||||
|
||||
bool Contains(const AABB2D& rhs) const;
|
||||
[[nodiscard]] bool Contains(const AABB2D& rhs) const;
|
||||
|
||||
bool Contains(const Vector2& pt) const;
|
||||
[[nodiscard]] bool Contains(const Vector2& pt) const;
|
||||
|
||||
bool Contains(int x, int y) const;
|
||||
[[nodiscard]] bool Contains(int x, int y) const;
|
||||
|
||||
bool IsDegenerate() const;
|
||||
[[nodiscard]] bool IsDegenerate() const;
|
||||
|
||||
bool HasNegativeVolume() const;
|
||||
[[nodiscard]] bool HasNegativeVolume() const;
|
||||
|
||||
bool IsFinite() const;
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
|
||||
Vector2 PosInside(const Vector2 &normalizedPos) const;
|
||||
|
||||
@@ -62,5 +73,30 @@ namespace J3ML::Geometry
|
||||
|
||||
AABB2D operator-(const Vector2& pt) const;
|
||||
|
||||
Vector2 CornerPoint(int cornerIndex);
|
||||
|
||||
void TransformAsAABB(const Matrix3x3& transform);
|
||||
void TransformAsAABB(const Matrix4x4& transform);
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<typename Matrix>
|
||||
void AABB2DTransformAsAABB2D(AABB2D &aabb, Matrix &m) {
|
||||
float ax = m[0][0] * aabb.minPoint.x;
|
||||
float bx = m[0][0] * aabb.maxPoint.x;
|
||||
float ay = m[0][1] * aabb.minPoint.y;
|
||||
float by = m[0][1] * aabb.maxPoint.y;
|
||||
|
||||
float ax2 = m[1][0] * aabb.minPoint.x;
|
||||
float bx2 = m[1][0] * aabb.maxPoint.x;
|
||||
float ay2 = m[1][1] * aabb.minPoint.y;
|
||||
float by2 = m[1][1] * aabb.maxPoint.y;
|
||||
|
||||
aabb.minPoint.x = J3ML::Math::Min(ax, bx) + J3ML::Math::Min(ay, by) + m[0][3];
|
||||
aabb.maxPoint.x = J3ML::Math::Max(ax, bx) + J3ML::Math::Max(ay, by) + m[0][3];
|
||||
|
||||
aabb.minPoint.y = J3ML::Math::Min(ax2, bx2) + J3ML::Math::Min(ay2, by2) + m[1][3];
|
||||
aabb.maxPoint.y = J3ML::Math::Max(ax2, bx2) + J3ML::Math::Max(ay2, by2) + m[1][3];
|
||||
}
|
||||
}
|
@@ -54,7 +54,7 @@ namespace J3ML::Geometry
|
||||
|
||||
|
||||
/// Quickly returns an arbitrary point inside this Capsule. Used in GJK intersection test.
|
||||
[[nodiscard]] inline Vector3 AnyPointFast() const;
|
||||
[[nodiscard]] Vector3 AnyPointFast() const;
|
||||
|
||||
/// Generates a point that perhaps lies inside this capsule.
|
||||
/** @param height A normalized value between [0,1]. This specifies the point position along the height line of this capsule.
|
||||
|
@@ -83,7 +83,7 @@ namespace J3ML::Geometry
|
||||
/// Specifies whether this frustum is a perspective or an orthographic frustum.
|
||||
FrustumType type;
|
||||
/// Specifies whether the [-1, 1] or [0, 1] range is used for the post-projective depth range.
|
||||
FrustumProjectiveSpace projectiveSpace;
|
||||
FrustumProjectiveSpace projectiveSpace ;
|
||||
/// Specifies the chirality of world and view spaces
|
||||
FrustumHandedness handedness;
|
||||
/// The eye point of this frustum
|
||||
@@ -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
|
||||
if the defaults were uninitialized. */
|
||||
Frustum();
|
||||
|
||||
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
|
||||
public:
|
||||
|
||||
|
||||
/// Quickly returns an arbitrary point inside this Frustum. Used in GJK intersection test.
|
||||
[[nodiscard]] Vector3 AnyPointFast() const { return CornerPoint(0); }
|
||||
|
||||
|
109
include/J3ML/Geometry/Icosahedron.hpp
Normal file
109
include/J3ML/Geometry/Icosahedron.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/// 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 Icosahedron.hpp
|
||||
/// @desc Icosahedron class implementation, borrowed from http://www.songho.ca/opengl/gl_sphere.html#icosphere
|
||||
/// @edit 2024-10-22
|
||||
|
||||
/** Polyhedron with 12 vertices, 30 edges, and 20 faces (triangles) for OpenGL
|
||||
If the radius is r, then the length of the edge is (r / sin(2pi/5))
|
||||
|
||||
Vertices of icosahedron are constructed with spherical coords by aligning
|
||||
the north pole to (0,0,r) and the south pole to (0,0,-r). Other 10 vertices
|
||||
are computed by rotating 72 degrees along y-axis at the elevation angle
|
||||
+/- 26.565 (=arctan(1/2)).
|
||||
|
||||
The unwrapped (paper model) of icosahedron and texture map look like this:
|
||||
// (S,0) 3S 5S 7S 9S
|
||||
// /\ /\ /\ /\ /\ : 1st row (5 triangles) //
|
||||
// /__\/__\/__\/__\/__\ //
|
||||
// T \ /\ /\ /\ /\ /\ : 2nd row (10 triangles) //
|
||||
// \/__\/__\/__\/__\/__\ //
|
||||
// 2T \ /\ /\ /\ /\ / : 3rd row (5 triangles) //
|
||||
// \/ \/ \/ \/ \/ //
|
||||
// 2S 4S 6S 8S (10S,3T)
|
||||
// where S = 186/2048 = 0.0908203
|
||||
// T = 322/1024 = 0.3144531
|
||||
// If a texture size is 2048x1024, S=186, T=322
|
||||
|
||||
AUTHOR: Song Ho Ahn (song.ahn@gmail.com)
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include "Color4.hpp"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace J3ML
|
||||
{
|
||||
|
||||
class Icosahedron
|
||||
{
|
||||
public:
|
||||
float radius;
|
||||
float edgeLength;
|
||||
Icosahedron(float radius = 1.0f);
|
||||
float Radius() const { return radius; }
|
||||
void Radius(float new_radius) {radius = new_radius;}
|
||||
float EdgeLength() const { return edgeLength;}
|
||||
void EdgeLength(float new_edge_length) { edgeLength = new_edge_length;}
|
||||
// for vertex data
|
||||
unsigned int VertexCount() const;
|
||||
unsigned int NormalCount() const;
|
||||
unsigned int TexCoordCount() const;
|
||||
unsigned int IndexCount() const;
|
||||
unsigned int LineIndexCount() const;
|
||||
unsigned int TriangleCount() const;
|
||||
unsigned int VertexSize() const;
|
||||
unsigned int NormalSize() const;
|
||||
unsigned int TexCoordSize() const;
|
||||
unsigned int IndexSize() const;
|
||||
unsigned int LineIndexSize() const;
|
||||
const float* Vertices() const;
|
||||
const float* Normals() const;
|
||||
const float* TexCoords() const;
|
||||
const unsigned int* Indices() const;
|
||||
const unsigned int* LineIndices() const;
|
||||
// for interleaved vertices: V/N/T
|
||||
unsigned int InterleavedVertexCount() const;
|
||||
unsigned int InterleavedVertexSize() const;
|
||||
int InterleavedStride() const;
|
||||
const float* InterleavedVertices() const;
|
||||
|
||||
// draw in VertexArray mode
|
||||
void draw() const;
|
||||
void drawLines(const Color4& lineColor) const;
|
||||
void drawWithLines(const Color4& lineColor) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
// static functions
|
||||
static void computeFaceNormal(float v1[3], float v2[3], float v3[3], float n[3]);
|
||||
|
||||
// member functions
|
||||
void updateRadius();
|
||||
std::vector<float> computeVertices();
|
||||
void buildVertices();
|
||||
void buildInterleavedVertices();
|
||||
void addVertices(float v1[3], float v2[3], float v3[3]);
|
||||
void addNormals(float n1[3], float n2[3], float n3[3]);
|
||||
void addTexCoords(float t1[2], float t2[2], float t3[2]);
|
||||
void addIndices(unsigned int i1, unsigned int i2, unsigned int i3);
|
||||
void addLineIndices(unsigned int indexFrom);
|
||||
|
||||
// member vars
|
||||
//float radius;
|
||||
//float edgeLength;
|
||||
std::vector<float> vertices;
|
||||
std::vector<float> normals;
|
||||
std::vector<float> texCoords;
|
||||
std::vector<unsigned int> indices;
|
||||
std::vector<unsigned int> lineIndices;
|
||||
|
||||
|
||||
};
|
||||
}
|
185
include/J3ML/Geometry/LineSegment2D.hpp
Normal file
185
include/J3ML/Geometry/LineSegment2D.hpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/// 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 LineSegment2D.hpp
|
||||
/// @desc A 2D representation of a finite line between two points.
|
||||
/// @edit 2024-10-22
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
/// A line segment in 2D space is a finite line with a start and end point.
|
||||
class LineSegment2D {
|
||||
public:
|
||||
/// The starting point of this line segment.
|
||||
Vector2 A;
|
||||
/// The end point of this line segment.
|
||||
Vector2 B;
|
||||
|
||||
/// The default constructor does not initialize any members of this class.
|
||||
/** This means that the values of the members a and b are undefined after creating a new LineSegment2D using this
|
||||
default constructor. Remember to assign to them before use.
|
||||
@see A, B. */
|
||||
LineSegment2D() {}
|
||||
|
||||
/// Constructs a line segment through the given end points.
|
||||
LineSegment2D(const Vector2 &a, const Vector2 &b);
|
||||
|
||||
/// Returns a point on the line.
|
||||
/** @param d The normalized distance along the line segment to compute. If a value in the range [0, 1] is passed, then the
|
||||
returned point lies along this line segment. If some other value is specified, the returned point lies on the line
|
||||
defined by this line segment, but *not* inside the interval from a to b.
|
||||
@note The meaning of d here differs from Line2D::GetPoint and Ray2D::GetPoint. For the class LineSegment2D,
|
||||
GetPoint(0) returns a, and getPoint(1) returns b. This means that GetPoint(1) will not generally be exactly one unit
|
||||
away from the starting point of this line segment, as is the case with Line2D and Ray2D.
|
||||
@return (1-d)*a + d*b;
|
||||
@see a, b, Line2D::GetPoint(), Ray2D::GetPoint() */
|
||||
Vector2 GetPoint(float d) const;
|
||||
|
||||
/// Returns the center point of this line segment.
|
||||
/** This function is the same as calling GetPoint(0.5f), but provided here as convenience.
|
||||
@see GetPoint(). */
|
||||
Vector2 CenterPoint() const;
|
||||
|
||||
Vector2 Centroid() const;
|
||||
|
||||
/// Reverses the direction of this line segment.
|
||||
/** This function swaps the start and end points of this line segment so that it runs from b to a.
|
||||
This does not have an effect on the set of points represented by this line segment, but it reverses
|
||||
the direction of the vector returned by Dir().
|
||||
@note This function operates in-place.
|
||||
@see a, b, Dir(). */
|
||||
void Reverse();
|
||||
|
||||
/// Returns the normalized direction vector that points in the direction a->b.
|
||||
/** @note The returned vector is normalized, meaning that its length is 1, not |b-a|.
|
||||
@see a, b. */
|
||||
Vector2 Dir() const;
|
||||
|
||||
/// Quickly returns an arbitrary point inside this LineSegment2D. Used in GJK intersection test.
|
||||
Vector2 AnyPointFast() const;
|
||||
|
||||
/// Computes an extreme point of this LineSegment2D in the given direction.
|
||||
/** An extreme point is a farthest point along this LineSegment2D in the given direction. Given a direction,
|
||||
this point is not necessarily unique.
|
||||
@param direction The direction vector of the direction to find the extreme point. This vector may
|
||||
be un-normalized, but may not be null.
|
||||
@return An extreme point of this LineSegment2D in the given direction. The returned point is always
|
||||
either a or b.
|
||||
@see a, b. **/
|
||||
Vector2 ExtremePoint(const Vector2 &direction) const;
|
||||
|
||||
Vector2 ExtremePoint(const Vector2 &direction, float &projectionDistance) const;
|
||||
|
||||
/// Translates this LineSegment2D in world space.
|
||||
/** @param offset The amount of displacement to apply to this LineSegment2D, in world space coordinates.
|
||||
@see Transform(). */
|
||||
void Translate(const Vector2& offset);
|
||||
|
||||
/// Applies a transformation to this line.
|
||||
/** This function operates in-place.
|
||||
@see Translate(), Transform(), classes Matrix3x3, Matrix4x4, Quaternion*/
|
||||
void Transform(const Matrix3x3& transform);
|
||||
void Transform(const Matrix4x4& transform);
|
||||
void Transform(const Quaternion& transform);
|
||||
|
||||
/// Computes the length of this line segment.
|
||||
/** @return |b - a|
|
||||
@see a, b. */
|
||||
float Length() const;
|
||||
/// Computes the squared length of this line segment.
|
||||
/** Calling this function is faster than calling Length(), since this function avoids computing a square root.
|
||||
If you only need to compare lengths to each other and are not interested in the actual length values,
|
||||
you can compare using LengthSq(), instead of Length(), since Sqrt() is an order-preserving,
|
||||
(monotonous and non-decreasing) function. */
|
||||
float LengthSq() const;
|
||||
float LengthSquared() const;
|
||||
|
||||
/// Tests if this line segment is finite
|
||||
/** A line segment is finite if its endpoints a and b do not contain floating-point NaNs for +/- infs
|
||||
in them.
|
||||
@return True if both a and b have finite floating-point values. */
|
||||
bool IsFinite() const;
|
||||
|
||||
/// Tests if this line segment represents the same set of points than the the given line segment.
|
||||
/** @param epsilon Specifies how much distance threshold to allow in the comparison.
|
||||
@return True if a == rhs.a && b == rhs.b, or, a == rhs.b && b == rhs.a, within the given epsilon. */
|
||||
bool Equals(const LineSegment2D& rhs, float epsilon = 1e-3f) const;
|
||||
|
||||
/// Tests if the given point or line segment is contained on this line segment.
|
||||
/** @param epsilon Because a line segment is a one-dimensional object in 3D space, an epsilon value
|
||||
is used as a threshold for this test. This effectively transforms this line segment to a capsule with
|
||||
the radius indicated by this value.
|
||||
@return True if this line segment contains the given point or line segment.
|
||||
@see Intersects, ClosestPoint(), Distance(). */
|
||||
bool Contains(const Vector2& point, float epsilon = 1e-3f) const;
|
||||
bool Contains(const LineSegment2D& rhs, float epsilon = 1e-3f) const;
|
||||
|
||||
/// Computes the closest point on this line segment to the given object.
|
||||
/** @param d If specified, this parameter receives the normalized distance along
|
||||
this line segment which specifies the closest point on this line segment to
|
||||
the specified point.
|
||||
@return The closest point on this line segment to the given object.
|
||||
@see Contains(), Distance(), Intersects(). */
|
||||
Vector2 ClosestPoint(const Vector2& point) const;
|
||||
Vector2 ClosestPoint(const Vector2& point, float& d) const;
|
||||
|
||||
|
||||
|
||||
/** @param d2 [out] If specified, this parameter receives the (normalized, in case of line segment)
|
||||
distance along the other line object which specifies the closest point on that line to
|
||||
this line segment. */
|
||||
Vector2 ClosestPoint(const LineSegment2D& other) const;
|
||||
Vector2 ClosestPoint(const LineSegment2D& other, float& d) const;
|
||||
Vector2 ClosestPoint(const LineSegment2D& other, float& d, float& d2) const;
|
||||
|
||||
/// Computes the distance between this line segment and the given object.
|
||||
/** @param d [out] If specified, this parameter receives the normalized distance along
|
||||
this line segment which specifies the closest point on this line segment to
|
||||
the specified point.
|
||||
@return The distance between this line segment and the given object.
|
||||
@see */
|
||||
float Distance(const Vector2& point) const;
|
||||
float Distance(const Vector2& point, float& d) const;
|
||||
|
||||
/** @param d2 [out] If specified, this parameter receives the (normalized, in case of line segment)
|
||||
distance along the other line object which specifies the closest point on that line to
|
||||
this line segment. */
|
||||
float Distance(const LineSegment2D& other) const;
|
||||
float Distance(const LineSegment2D& other, float& d) const;
|
||||
float Distance(const LineSegment2D& other, float& d, float& d2) const;
|
||||
|
||||
float DistanceSq(const Vector2& point) const;
|
||||
float DistanceSq(const LineSegment2D& other) const;
|
||||
|
||||
/** @param epsilon If testing intersection between two line segments, a distance threshold value is used to account
|
||||
for floating point inaccuracies. */
|
||||
bool Intersects(const LineSegment2D& lineSegment, float epsilon = 1e-3f) const;
|
||||
|
||||
|
||||
/// Projects this LineSegment2D onto the given 1D axis direction vector.
|
||||
/** This function collapses this LineSegment2D onto a 1D axis for the purposes of e.g. separate axis test computations.
|
||||
This function returns a 1D range [outMin, outNax] denoting the interval of the projection.
|
||||
@param direction The 1D axis to project to. This vector may be unnormalized, in which case the output
|
||||
of this function gets scaled by the length of this vector.
|
||||
@param outMin [out] Returns the minimum extent of this vector along the projection axis.
|
||||
@param outMax [out] Returns the maximum extent of this vector along the projection axis. */
|
||||
void ProjectToAxis(const Vector2& direction, float& outMin, float& outMax) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
};
|
||||
|
||||
LineSegment2D operator * (const Matrix3x3& transform, const LineSegment2D& line);
|
||||
LineSegment2D operator * (const Matrix4x4& transform, const LineSegment2D& line);
|
||||
LineSegment2D operator * (const Quaternion& transform, const LineSegment2D& line);
|
||||
}
|
@@ -52,7 +52,7 @@ namespace J3ML::Geometry {
|
||||
}
|
||||
}
|
||||
|
||||
AABB2D ComputeAABB() {}
|
||||
AABB2D ComputeAABB() { return AABB2D(); }
|
||||
|
||||
float DistanceSq(const Vector2 &point) const {
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
@@ -114,8 +114,10 @@ namespace J3ML::Geometry
|
||||
[[nodiscard]] bool Contains(const Vector3& point, float epsilon) const;
|
||||
|
||||
[[nodiscard]] bool Contains(const LineSegment& lineseg) const;
|
||||
TriangleMesh GenerateUVSphere() const;
|
||||
TriangleMesh GenerateUVSphere(int subdivisions = 10.f) const;
|
||||
TriangleMesh GenerateIcososphere() const;
|
||||
TriangleMesh GenerateCubesphere() const;
|
||||
|
||||
|
||||
void ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const;
|
||||
};
|
||||
|
@@ -15,15 +15,17 @@ namespace J3ML::Geometry
|
||||
TriangleMesh(int expectedPolygonCount = 1000);
|
||||
|
||||
public:
|
||||
//std::vector<Vector3> Vertices;
|
||||
//std::vector<Vector3> Normals;
|
||||
//std::vector<Vector3> UVs;
|
||||
//std::vector<u64> Indices;
|
||||
std::vector<Vector3> Vertices;
|
||||
std::vector<Vector3> Normals;
|
||||
std::vector<Vector3> UVs;
|
||||
std::vector<u64> Indices;
|
||||
|
||||
std::vector<float> GenerateVertexList();
|
||||
//std::vector<Triangle> GenerateTriangleList();
|
||||
public:
|
||||
|
||||
private:
|
||||
std::vector<float> cachedVertexList;
|
||||
|
||||
//std::vector<Triangle> cachedTriangleList;
|
||||
};
|
||||
|
||||
|
@@ -17,18 +17,114 @@
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
/// 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.
|
||||
#undef USE_LOOKUP_TABLES /// Pre-computed lookup tables.
|
||||
#undef USE_SSE /// Streaming SIMD Extensions (x86)
|
||||
#undef USE_NEON /// ARM Vector Processing
|
||||
#undef USE_AVX /// Advanced Vector Extensions (x86)
|
||||
|
||||
/// TODO: Implement lookup tables.
|
||||
/// TODO: Implement constexpr Trigonometric LUT generators that are parameterized (samples, samples-per-period, etc.)
|
||||
|
||||
#ifdef USE_LOOKUP_TABLES
|
||||
|
||||
static float fast_cossin_table[MAX_CIRCLE_ANGLE];
|
||||
#define LUT_SAMPLES 1024
|
||||
|
||||
#pragma region Trigonometric Lookup Tables
|
||||
|
||||
// Formula: sin(2*pi*t/T)
|
||||
/** Generated using Dr LUT - Free Lookup Table Generator
|
||||
* https://github.com/ppelikan/drlut
|
||||
**/
|
||||
// Formula: sin(2*pi*t/T)
|
||||
const uint8_t u8_sin_lut[1024] = {
|
||||
127,128,129,129,130,131,132,132,133,134,135,136,136,
|
||||
137,138,139,139,140,141,142,143,143,144,145,146,146,
|
||||
147,148,149,149,150,151,152,153,153,154,155,156,156,
|
||||
157,158,159,159,160,161,162,162,163,164,165,165,166,
|
||||
167,168,168,169,170,171,171,172,173,173,174,175,176,
|
||||
176,177,178,178,179,180,181,181,182,183,183,184,185,
|
||||
185,186,187,188,188,189,190,190,191,192,192,193,194,
|
||||
194,195,196,196,197,198,198,199,199,200,201,201,202,
|
||||
203,203,204,205,205,206,206,207,208,208,209,209,210,
|
||||
211,211,212,212,213,213,214,215,215,216,216,217,217,
|
||||
218,218,219,220,220,221,221,222,222,223,223,224,224,
|
||||
225,225,226,226,227,227,228,228,229,229,229,230,230,
|
||||
231,231,232,232,233,233,233,234,234,235,235,236,236,
|
||||
236,237,237,238,238,238,239,239,239,240,240,240,241,
|
||||
241,241,242,242,242,243,243,243,244,244,244,245,245,
|
||||
245,245,246,246,246,247,247,247,247,248,248,248,248,
|
||||
249,249,249,249,249,250,250,250,250,250,251,251,251,
|
||||
251,251,251,252,252,252,252,252,252,252,253,253,253,
|
||||
253,253,253,253,253,253,253,253,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,254,254,
|
||||
254,254,254,254,254,254,254,254,254,254,254,253,253,
|
||||
253,253,253,253,253,253,253,253,253,252,252,252,252,
|
||||
252,252,252,251,251,251,251,251,251,250,250,250,250,
|
||||
250,249,249,249,249,249,248,248,248,248,247,247,247,
|
||||
247,246,246,246,245,245,245,245,244,244,244,243,243,
|
||||
243,242,242,242,241,241,241,240,240,240,239,239,239,
|
||||
238,238,238,237,237,236,236,236,235,235,234,234,233,
|
||||
233,233,232,232,231,231,230,230,229,229,229,228,228,
|
||||
227,227,226,226,225,225,224,224,223,223,222,222,221,
|
||||
221,220,220,219,218,218,217,217,216,216,215,215,214,
|
||||
213,213,212,212,211,211,210,209,209,208,208,207,206,
|
||||
206,205,205,204,203,203,202,201,201,200,199,199,198,
|
||||
198,197,196,196,195,194,194,193,192,192,191,190,190,
|
||||
189,188,188,187,186,185,185,184,183,183,182,181,181,
|
||||
180,179,178,178,177,176,176,175,174,173,173,172,171,
|
||||
171,170,169,168,168,167,166,165,165,164,163,162,162,
|
||||
161,160,159,159,158,157,156,156,155,154,153,153,152,
|
||||
151,150,149,149,148,147,146,146,145,144,143,143,142,
|
||||
141,140,139,139,138,137,136,136,135,134,133,132,132,
|
||||
131,130,129,129,128,127,126,125,125,124,123,122,122,
|
||||
121,120,119,118,118,117,116,115,115,114,113,112,111,
|
||||
111,110,109,108,108,107,106,105,105,104,103,102,101,
|
||||
101,100, 99, 98, 98, 97, 96, 95, 95, 94, 93, 92, 92,
|
||||
91, 90, 89, 89, 88, 87, 86, 86, 85, 84, 83, 83, 82,
|
||||
81, 81, 80, 79, 78, 78, 77, 76, 76, 75, 74, 73, 73,
|
||||
72, 71, 71, 70, 69, 69, 68, 67, 66, 66, 65, 64, 64,
|
||||
63, 62, 62, 61, 60, 60, 59, 58, 58, 57, 56, 56, 55,
|
||||
55, 54, 53, 53, 52, 51, 51, 50, 49, 49, 48, 48, 47,
|
||||
46, 46, 45, 45, 44, 43, 43, 42, 42, 41, 41, 40, 39,
|
||||
39, 38, 38, 37, 37, 36, 36, 35, 34, 34, 33, 33, 32,
|
||||
32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26,
|
||||
25, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20,
|
||||
20, 19, 19, 18, 18, 18, 17, 17, 16, 16, 16, 15, 15,
|
||||
15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11,
|
||||
10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7,
|
||||
7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 4, 4, 4,
|
||||
4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
|
||||
2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
|
||||
3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6,
|
||||
6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9,
|
||||
10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14,
|
||||
14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18, 18,
|
||||
19, 19, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30,
|
||||
31, 31, 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, 37,
|
||||
38, 38, 39, 39, 40, 41, 41, 42, 42, 43, 43, 44, 45,
|
||||
45, 46, 46, 47, 48, 48, 49, 49, 50, 51, 51, 52, 53,
|
||||
53, 54, 55, 55, 56, 56, 57, 58, 58, 59, 60, 60, 61,
|
||||
62, 62, 63, 64, 64, 65, 66, 66, 67, 68, 69, 69, 70,
|
||||
71, 71, 72, 73, 73, 74, 75, 76, 76, 77, 78, 78, 79,
|
||||
80, 81, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89,
|
||||
89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 98, 98,
|
||||
99,100,101,101,102,103,104,105,105,106,107,108,108,
|
||||
109,110,111,111,112,113,114,115,115,116,117,118,118,
|
||||
119,120,121,122,122,123,124,125,125,126 };
|
||||
|
||||
|
||||
#pragma endregion
|
||||
#endif
|
||||
|
||||
|
||||
#include <J3ML/Algorithm/Reinterpret.hpp>
|
||||
|
||||
|
||||
/// Swaps two elements in-place without copying their data.
|
||||
template <typename T>
|
||||
void Swap(T &a, T &b)
|
||||
@@ -38,79 +134,82 @@ void Swap(T &a, T &b)
|
||||
b = std::move(temp);
|
||||
}
|
||||
|
||||
/// Clean symbolic names for integers of specific size.
|
||||
namespace J3ML::SizedIntegralTypes
|
||||
{
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
using s8 = int8_t;
|
||||
using s16 = int16_t;
|
||||
using s32 = int32_t;
|
||||
using s64 = int64_t;
|
||||
}
|
||||
|
||||
namespace J3ML::SizedFloatTypes
|
||||
{
|
||||
// TODO: Use C++23 <stdfloat>
|
||||
using f16 = float;
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
using f128 = long double;
|
||||
namespace J3ML {
|
||||
/// Clean symbolic names for integers of specific size.
|
||||
namespace SizedIntegralTypes {
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
using s8 = int8_t;
|
||||
using s16 = int16_t;
|
||||
using s32 = int32_t;
|
||||
using s64 = int64_t;
|
||||
}
|
||||
//using namespace SizedIntegralTypes; // Bring into J3ML namespace.
|
||||
|
||||
namespace SizedFloatTypes { // TODO: Use C++23 <stdfloat>
|
||||
using f16 = float;
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
using f128 = long double;
|
||||
}
|
||||
//using namespace SizedFloatTypes; // Bring into J3ML namespace.
|
||||
}
|
||||
|
||||
using namespace J3ML::SizedIntegralTypes;
|
||||
using namespace J3ML::SizedFloatTypes;
|
||||
|
||||
namespace J3ML::Math::BitTwiddling
|
||||
{
|
||||
namespace J3ML::BitTwiddling {
|
||||
/// Parses a string of form "011101010" to a u32
|
||||
u32 BinaryStringToValue(const char* s);
|
||||
|
||||
/// Returns the number of 1's set in the given value.
|
||||
inline int CountBitsSet(u32 value);
|
||||
//inline int CountBitsSet(u32 value);
|
||||
}
|
||||
|
||||
namespace J3ML::Math {
|
||||
enum class Quadrant { I, II, III, IV };
|
||||
|
||||
// Zero technically isn't a sign, but zero also isn't positive, or negative, so bite me.
|
||||
enum class Sign { ZERO, POSITIVE, NEGATIVE};
|
||||
|
||||
// TODO: Implement "Wrappers" for most standard math functions.
|
||||
// We want to later-on implement lookup tables and SSE as conditional macros.
|
||||
|
||||
namespace J3ML::Math::Constants {
|
||||
/// sqrt(2pi) ^ -1
|
||||
constexpr float RecipSqrt2Pi = 0.3989422804014326779399460599343818684758586311649346576659258296706579258993018385012523339073069364;
|
||||
/// pi - https://www.mathsisfun.com/numbers/pi.html
|
||||
constexpr float Pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
|
||||
/// e - https://www.mathsisfun.com/numbers/e-eulers-number.html
|
||||
constexpr float EulersNumber = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274;
|
||||
/// 2pi - The ratio of a circle's circumferecne to its radius, and the number of radians in one turn.
|
||||
constexpr float Tau = 6.28318530717958647692;
|
||||
/// sqrt(2)
|
||||
constexpr float PythagorasConstant = 1.41421356237309504880;
|
||||
/// sqrt(3)
|
||||
constexpr float TheodorusConstant = 1.73205080756887729352;
|
||||
/// Golden Ratio
|
||||
constexpr float Phi = 1.61803398874989484820;
|
||||
/// ln 2
|
||||
constexpr float NaturalLog2 = 0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875;
|
||||
/// ln 10
|
||||
constexpr float NaturalLog10 = 2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983;
|
||||
constexpr float Infinity = INFINITY;
|
||||
constexpr float NegativeInfinity = -INFINITY;
|
||||
constexpr float NotANumber = NAN;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#undef USE_LOOKUP_TABLES /// Pre-computed lookup tables.
|
||||
#undef USE_SSE /// Streaming SIMD Extensions (x86)
|
||||
#undef USE_NEON /// ARM Vector Processing
|
||||
#undef USE_AVX /// Advanced Vector Extensions (x86)
|
||||
namespace J3ML::Math::Constants { // TODO: Consider double precision for these.
|
||||
/// sqrt(2pi) ^ -1
|
||||
constexpr float RecipSqrt2Pi = 0.3989422804014326779399460599343818684758586311649346576659258296706579258993018385012523339073069364;
|
||||
/// pi - https://www.mathsisfun.com/numbers/pi.html
|
||||
constexpr float Pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679;
|
||||
constexpr float TwoPi = Pi*2.0;
|
||||
constexpr float PiOverTwo = Pi/2.0;
|
||||
constexpr float ThreePiOverTwo = 3.0*Pi/2.0;
|
||||
/// e - https://www.mathsisfun.com/numbers/e-eulers-number.html
|
||||
constexpr float EulersNumber = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274;
|
||||
/// 2pi - The ratio of a circle's circumferecne to its radius, and the number of radians in one turn.
|
||||
constexpr float Tau = 6.28318530717958647692;
|
||||
/// sqrt(2)
|
||||
constexpr float PythagorasConstant = 1.41421356237309504880;
|
||||
/// sqrt(3)
|
||||
constexpr float TheodorusConstant = 1.73205080756887729352;
|
||||
/// Golden Ratio
|
||||
constexpr float Phi = 1.61803398874989484820;
|
||||
/// ln 2
|
||||
constexpr float NaturalLog2 = 0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875;
|
||||
/// ln 10
|
||||
constexpr float NaturalLog10 = 2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983;
|
||||
constexpr float Infinity = INFINITY;
|
||||
constexpr float NegativeInfinity = -INFINITY;
|
||||
constexpr float NotANumber = NAN;
|
||||
}
|
||||
|
||||
namespace J3ML::Math {
|
||||
using namespace Constants; // Bring into J3ML::Math namespace.
|
||||
}
|
||||
|
||||
namespace J3ML::Math::Functions {
|
||||
// TODO: Implement "Wrappers" for most standard math functions.
|
||||
// We want to later-on implement lookup tables and SSE as conditional macros.
|
||||
|
||||
/// Clamps the given input value to the range [min, max].
|
||||
/** @see Clamp01(), Min(), Max(). */
|
||||
@@ -221,26 +320,37 @@ namespace J3ML::Math::Functions {
|
||||
inline bool IsInfinite(double d) { return (ReinterpretAs<u64>(d) << 1) == 0xFFE0000000000000ULL; }
|
||||
|
||||
|
||||
namespace Trigonometric {
|
||||
Sign SignOfSin(float radians);
|
||||
Sign SignOfCos(float radians);
|
||||
Sign SignOfTan(float radians);
|
||||
|
||||
float Radians(float deg); /// Converts the given amount of degrees into radians.
|
||||
float Degrees(float rad); /// Converts the given amount of radians into degrees.
|
||||
Quadrant QuadrantOf(float radians);
|
||||
|
||||
float Sin(float x); /// Computes the sine of x, in radians.
|
||||
float Cos(float x); /// Computes the cosine of x, in radians.
|
||||
float Tan(float x); /// Computes the tangent of x, in radians.
|
||||
|
||||
/// Simultaneously computes both sine and cosine of x, in radians.
|
||||
/// This yields a small performance increase over computing them separately.
|
||||
/// @see Sin(), Cos().
|
||||
void SinCos(float x, float& outSin, float& outCos);
|
||||
float Radians(float deg); /// Converts the given amount of degrees into radians.
|
||||
float Degrees(float rad); /// Converts the given amount of radians into degrees.
|
||||
|
||||
float Asin(float x); /// Computes the inverse sine of x, in radians.
|
||||
float Acos(float x); /// Computes the inverse cosine of x, in radians.
|
||||
float Atan(float x); /// Computes the inverse tangent of x, in radians.
|
||||
float Atan2(float y, float x); /// Computes the signed (principal value) inverse tangent of y/x, in radians.
|
||||
float Sinh(float x); /// Computes the hyperbolic sine of x, in radians.
|
||||
float Cosh(float x); /// Computes the hyperbolic cosine of x, in radians.
|
||||
float Tanh(float x); /// Computes the hyperbolic tangent of x, in radians.
|
||||
float Sin(float x); /// Computes the sine of x, in radians.
|
||||
float Cos(float x); /// Computes the cosine of x, in radians.
|
||||
float Tan(float x); /// Computes the tangent of x, in radians.
|
||||
|
||||
/// Simultaneously computes both sine and cosine of x, in radians.
|
||||
/// This yields a small performance increase over computing them separately.
|
||||
/// @see Sin(), Cos().
|
||||
void SinCos(float x, float& outSin, float& outCos);
|
||||
|
||||
float Asin(float x); /// Computes the inverse sine of x, in radians.
|
||||
float Acos(float x); /// Computes the inverse cosine of x, in radians.
|
||||
float Atan(float x); /// Computes the inverse tangent of x, in radians.
|
||||
float Atan2(float y, float x); /// Computes the signed (principal value) inverse tangent of y/x, in radians.
|
||||
float Sinh(float x); /// Computes the hyperbolic sine of x, in radians.
|
||||
float Cosh(float x); /// Computes the hyperbolic cosine of x, in radians.
|
||||
float Tanh(float x); /// Computes the hyperbolic tangent of x, in radians.
|
||||
}
|
||||
|
||||
|
||||
using namespace Trigonometric;
|
||||
|
||||
bool IsPow2(u32 number); /// Returns true if the given number is a power of 2.
|
||||
bool IsPow2(u64 number); /// Returns true if the given number is a power of 2.
|
||||
@@ -272,10 +382,6 @@ namespace J3ML::Math::Functions {
|
||||
/// 2241 -> 2.2k, 55421 -> 55.4k, 1000000 -> 1.0M
|
||||
std::string Truncate(float input);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float RecipFast(float x);
|
||||
|
||||
|
||||
@@ -331,47 +437,50 @@ namespace J3ML::Math::Functions {
|
||||
/// Returns the fractional part of x.
|
||||
/** @see Lerp(), LerpMod(), InvLerp(), Step(), SmoothStep(), PingPongMod(), Mod(), ModPos(). */
|
||||
float Frac(float x);
|
||||
float Sqrt(float x); /// Returns the square root of x.
|
||||
float FastSqrt(float x); /// Computes a fast approximation of the square root of x.
|
||||
float RSqrt(float x); /// Returns 1/Sqrt(x). (The reciprocal of the square root of x)
|
||||
float FastRSqrt(float x); /// SSE implementation of reciprocal square root.
|
||||
float Recip(float x); /// Returns 1/x, the reciprocal of x.
|
||||
float RecipFast(float x); /// Returns 1/x, the reciprocal of x, using a fast approximation (SSE rcp instruction).
|
||||
|
||||
|
||||
namespace Interp
|
||||
{
|
||||
inline float SmoothStart(float t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Returns the square root of x.
|
||||
float Sqrt(float x);
|
||||
/// Computes a fast approximation of the square root of x.
|
||||
float FastSqrt(float x);
|
||||
/// Returns 1/Sqrt(x). (The reciprocal of the square root of x)
|
||||
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
|
||||
{
|
||||
inline float SmoothStart(float t);
|
||||
}
|
||||
|
||||
|
||||
namespace J3ML::Math {
|
||||
using namespace Math::Constants;
|
||||
using namespace Math::Functions;
|
||||
using namespace Functions;
|
||||
}
|
||||
|
||||
namespace J3ML::Math::Types {
|
||||
|
||||
|
||||
struct Rotation
|
||||
{
|
||||
public:
|
||||
Rotation();
|
||||
Rotation(float value);
|
||||
float valueInRadians;
|
||||
float ValueInRadians() const;
|
||||
float ValueInDegrees() const;
|
||||
Rotation operator+(const Rotation& rhs);
|
||||
struct Radians { // TODO: Fill in with relevant members.
|
||||
float value;
|
||||
float operator()() const { return value; }
|
||||
};
|
||||
|
||||
struct Degrees { // TODO: Fill in with relevant members.
|
||||
float value;
|
||||
float operator()() const { return value; }
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
/// @file LinearAlgebra.h
|
||||
/// @file LinearAlgebra.hpp
|
||||
/// @description Includes all LinearAlgebra classes and functions
|
||||
/// @author Josh O'Leary, William Tomasine II
|
||||
/// @copyright 2024 Redacted Software
|
||||
@@ -9,22 +9,15 @@
|
||||
|
||||
#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/Vector3.hpp"
|
||||
#include "J3ML/LinearAlgebra/Vector4.hpp"
|
||||
#include "J3ML/LinearAlgebra/Quaternion.hpp"
|
||||
#include "J3ML/LinearAlgebra/AxisAngle.hpp"
|
||||
#include "J3ML/LinearAlgebra/EulerAngle.hpp"
|
||||
#include "J3ML/LinearAlgebra/Matrix2x2.hpp"
|
||||
#include "J3ML/LinearAlgebra/Matrix3x3.hpp"
|
||||
#include "J3ML/LinearAlgebra/Matrix4x4.hpp"
|
||||
#include "J3ML/LinearAlgebra/Transform2D.hpp"
|
||||
#include "J3ML/LinearAlgebra/CoordinateFrame.hpp"
|
||||
#include "J3ML/LinearAlgebra/Vector2i.hpp"
|
||||
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
@@ -1,29 +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
|
||||
|
||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Forward.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
namespace J3ML::LinearAlgebra {
|
||||
class AxisAngle;
|
||||
}
|
||||
|
||||
/// Transitional datatype, not useful for internal representation of rotation
|
||||
/// But has uses for conversion and manipulation.
|
||||
class AxisAngle {
|
||||
public:
|
||||
Vector3 axis;
|
||||
float angle;
|
||||
public:
|
||||
AxisAngle();
|
||||
explicit AxisAngle(const Quaternion& q);
|
||||
explicit AxisAngle(const EulerAngle& e);
|
||||
/// @class AxisAngle
|
||||
/// @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 {
|
||||
public:
|
||||
/// The
|
||||
Vector3 axis;
|
||||
/// Radians.
|
||||
float angle;
|
||||
public:
|
||||
/// 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);
|
||||
/// 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;
|
||||
|
||||
EulerAngle ToEulerAngleXYZ() const;
|
||||
/// Returns the axis component of this AxisAngle rotation.
|
||||
Vector3 Axis() const;
|
||||
float Angle() const;
|
||||
|
||||
Quaternion ToQuaternion() const;
|
||||
static AxisAngle FromEulerAngleXYZ(const EulerAngle&);
|
||||
};
|
||||
}
|
||||
/// 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,52 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
class AxisAngle;
|
||||
|
||||
// Essential Reading:
|
||||
// http://www.essentialmath.com/GDC2012/GDC2012_JMV_Rotations.pdf
|
||||
class EulerAngle {
|
||||
public:
|
||||
EulerAngle();
|
||||
EulerAngle(float pitch, float yaw, float roll);
|
||||
EulerAngle(const Vector3& vec) : pitch(vec.x), yaw(vec.y), roll(vec.z) {}
|
||||
|
||||
AxisAngle ToAxisAngle() const;
|
||||
|
||||
[[nodiscard]] Quaternion ToQuaternion() const;
|
||||
|
||||
|
||||
explicit EulerAngle(const Quaternion& rhs);
|
||||
explicit EulerAngle(const AxisAngle& rhs);
|
||||
|
||||
/// TODO: Implement separate upper and lower bounds
|
||||
/// Preserves internal value of euler angles, normalizes and clamps the output.
|
||||
/// This does not solve gimbal lock!!!
|
||||
float GetPitch(float pitch_limit) const;
|
||||
float GetYaw(float yaw_limit) const;
|
||||
float GetRoll(float roll_limit) const;
|
||||
|
||||
bool operator==(const EulerAngle& a) const;
|
||||
void clamp();
|
||||
|
||||
// TODO: Euler Angles do not represent a vector, length doesn't apply, nor is this information meaningful for this data type.
|
||||
// If you need a meaningful representation of length in 3d space, use a vector!!
|
||||
[[nodiscard]] float length() const {
|
||||
return 0;
|
||||
}
|
||||
// TODO: Implement
|
||||
Vector3 unitVector() const;
|
||||
|
||||
EulerAngle movementAngle() const;
|
||||
public:
|
||||
float pitch;
|
||||
float yaw;
|
||||
float roll;
|
||||
};
|
||||
|
||||
}
|
@@ -4,10 +4,10 @@
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
class Vector2; // A type representing a position in a 2-dimensional coordinate space.
|
||||
class Vector2i;
|
||||
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 Angle2D; // Uses x,y components to represent a 2D rotation.
|
||||
class EulerAngle; // Uses pitch,yaw,roll components to represent a 3D orientation.
|
||||
class AxisAngle; //
|
||||
class CoordinateFrame; //
|
||||
class Matrix2x2;
|
||||
@@ -15,6 +15,7 @@ namespace J3ML::LinearAlgebra
|
||||
class Matrix4x4;
|
||||
class Transform2D;
|
||||
class Transform3D;
|
||||
class DirectionVectorRH; // A type representing a direction in 3D space.
|
||||
class Quaternion;
|
||||
|
||||
|
||||
|
@@ -15,6 +15,9 @@
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "Vector.hpp"
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
@@ -22,8 +25,8 @@ namespace J3ML::LinearAlgebra
|
||||
|
||||
|
||||
template <uint ROWS, uint COLS, typename T>
|
||||
class Matrix
|
||||
{
|
||||
class Matrix {
|
||||
public:
|
||||
static constexpr uint Diag = std::min(ROWS, COLS);
|
||||
|
||||
using RowVector = Vector<ROWS, T>;
|
||||
@@ -33,6 +36,22 @@ namespace J3ML::LinearAlgebra
|
||||
enum { Rows = ROWS };
|
||||
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)
|
||||
{
|
||||
assert(rows < Rows && "");
|
||||
|
@@ -5,7 +5,6 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
|
||||
using namespace J3ML::Algorithm;
|
||||
@@ -62,8 +61,9 @@ namespace J3ML::LinearAlgebra {
|
||||
Matrix3x3(const Vector3& col0, const Vector3& col1, const Vector3& col2);
|
||||
/// Constructs this matrix3x3 from the given quaternion.
|
||||
explicit Matrix3x3(const Quaternion& orientation);
|
||||
/// Constructs this matrix3x3 from the given euler angle.
|
||||
explicit Matrix3x3(const EulerAngle& 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.
|
||||
explicit Matrix3x3(const float *data);
|
||||
@@ -153,10 +153,19 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// Sets this matrix to perform a rotation about the given axis and angle.
|
||||
void SetRotatePart(const Vector3& a, float angle);
|
||||
|
||||
void SetRotatePart(const AxisAngle& axisAngle);
|
||||
/// Sets this matrix to perform the rotation expressed by the given quaternion.
|
||||
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.
|
||||
/** @param row The zero-based index [0, 2] of the row to get. */
|
||||
Vector3 GetRow(int index) const;
|
||||
@@ -239,17 +248,10 @@ namespace J3ML::LinearAlgebra {
|
||||
inline float* ptr() { return &elems[0][0];}
|
||||
[[nodiscard]] inline const float* ptr() const {return &elems[0][0];}
|
||||
|
||||
|
||||
/// Convers this rotation matrix to a quaternion.
|
||||
/// This function assumes that the matrix is orthonormal (no shear or scaling) and does not perform any mirroring (determinant > 0)
|
||||
[[nodiscard]] Quaternion ToQuat() const;
|
||||
/// Attempts to convert this matrix to a quaternion. Returns false if the conversion cannot succeed (this matrix was not a rotation
|
||||
/// matrix, and there is scaling ,shearing, or mirroring in this matrix)
|
||||
bool TryConvertToQuat(Quaternion& q) const;
|
||||
|
||||
/// Converts this rotation matrix to an Euler Angle.
|
||||
[[nodiscard]] EulerAngle ToEulerAngle() const;
|
||||
|
||||
/// Returns the main diagonal.
|
||||
/// The main diagonal consists of the elements at m[0][0], m[1][1], m[2][2]
|
||||
[[nodiscard]] Vector3 Diagonal() const;
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <bits/ostream.tcc>
|
||||
|
||||
using namespace J3ML::Algorithm;
|
||||
|
||||
@@ -71,8 +73,7 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// Constructs this Matrix4x4 from the given quaternion.
|
||||
explicit Matrix4x4(const Quaternion& orientation);
|
||||
/// Constructs this Matrix4x4 from the given Euler Angle.
|
||||
explicit Matrix4x4(const EulerAngle& orientation);
|
||||
|
||||
|
||||
/// Constructs this float4x4 from the given quaternion and translation.
|
||||
/// Logically, the translation occurs after the rotation has been performed.
|
||||
@@ -567,15 +568,18 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
[[nodiscard]] Quaternion ToQuat() const;
|
||||
|
||||
[[nodiscard]] EulerAngle ToEulerAngle() const;
|
||||
|
||||
/// 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;
|
||||
|
||||
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
|
||||
protected:
|
||||
float elems[4][4];
|
||||
|
||||
|
||||
Vector3 TransformDir(float tx, float ty, float tz) const;
|
||||
};
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& out, const Matrix4x4& rhs);
|
||||
}
|
||||
|
@@ -4,258 +4,262 @@
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
class Quaternion {
|
||||
public:
|
||||
/// The identity quaternion performs no rotation when applied to a vector.
|
||||
static const Quaternion Identity;
|
||||
/// A compile-time constant Quaternion with the value (NAN, NAN, NAN, NAN).
|
||||
/// For this constant, each element has the value of quiet NAN, or Not-A-Number.
|
||||
/// @note Never compare a Quaternion to this value! Due to how IEEE floats work, "nan == nan" returns false!
|
||||
/// That is, nothing is equal to NaN, not even NaN itself!
|
||||
static const Quaternion NaN;
|
||||
public:
|
||||
/// The default constructor does not initialize any member values.
|
||||
Quaternion();
|
||||
/// Copy constructor
|
||||
Quaternion(const Quaternion &rhs) = default;
|
||||
/// Constructs a quaternion from the given data buffer.
|
||||
/// @param data An array of four floats to use for the quaternion, in the order 'x,y,z,w.' (== 'i,j,k,w')
|
||||
explicit Quaternion(const float *data);
|
||||
namespace J3ML::LinearAlgebra {
|
||||
class Quaternion;
|
||||
}
|
||||
|
||||
explicit Quaternion(const Matrix3x3 &rotationMtrx);
|
||||
explicit Quaternion(const Matrix4x4 &rotationMtrx);
|
||||
class J3ML::LinearAlgebra::Quaternion {
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
public:
|
||||
/// The identity quaternion performs no rotation when applied to a vector.
|
||||
static const Quaternion Identity;
|
||||
/// A compile-time constant Quaternion with the value (NAN, NAN, NAN, NAN).
|
||||
/// For this constant, each element has the value of quiet NAN, or Not-A-Number.
|
||||
/// @note Never compare a Quaternion to this value! Due to how IEEE floats work, "nan == nan" returns false!
|
||||
/// That is, nothing is equal to NaN, not even NaN itself!
|
||||
static const Quaternion NaN;
|
||||
public:
|
||||
/// The default constructor does not initialize any member values.
|
||||
Quaternion() = default;
|
||||
|
||||
/// @param x The factor of i.
|
||||
/// @param y The factor of j.
|
||||
/// @param z The factor of k.
|
||||
/// @param w The scalar factor (or 'w').
|
||||
/// @note The input data is not normalized after construction, this has to be done manually.
|
||||
Quaternion(float X, float Y, float Z, float W);
|
||||
/// Copy constructor
|
||||
Quaternion(const Quaternion &rhs);
|
||||
|
||||
/// Constructs this quaternion by specifying a rotation axis and the amount of rotation to be performed about that axis
|
||||
/// @param rotationAxis The normalized rotation axis to rotate about. If using Vector4 version of the constructor, the w component of this vector must be 0.
|
||||
/// @param rotationAngleRadians The angle to rotate by, in radians. For example, Pi/4.f equals to 45 degrees, Pi/2.f is 90 degrees, etc.
|
||||
/// @see DegToRad()
|
||||
Quaternion(const Vector3 &rotationAxis, float rotationAngleRadians);
|
||||
Quaternion(const Vector4 &rotationAxis, float rotationAngleRadians);
|
||||
/// Quaternion from Matrix3x3
|
||||
explicit Quaternion(const Matrix3x3 &ro_mat);
|
||||
|
||||
explicit Quaternion(const Vector4& vector4);
|
||||
explicit Quaternion(const EulerAngle& angle);
|
||||
explicit Quaternion(const AxisAngle& angle);
|
||||
|
||||
/// Creates a LookAt quaternion.
|
||||
/** A LookAt quaternion is a quaternion that orients an object to face towards a specified target direction.
|
||||
@param localForward Specifies the forward direction in the local space of the object. This is the direction
|
||||
the model is facing at in its own local/object space, often +X(1,0,0), +Y(0,1,0), or +Z(0,0,1).
|
||||
The vector to pass in here depends on the conventions you or your modeling software is using, and it is best
|
||||
to pick one convention for all your objects, and be consistent.
|
||||
This input parameter must be a normalized vector.
|
||||
@param targetDirection Specifies the desired world space direction the object should look at. This function
|
||||
will compute a quaternion which will rotate the localForward vector to orient towards this targetDirection
|
||||
vector. This input parameter must be a normalized vector.
|
||||
@param localUp Specifies the up direction in the local space of the object. This is the up direction the model
|
||||
was authored in, often +Y (0,1,0) or +Z (0,0,1). The vector to pass in here depends on the conventions you
|
||||
or your modeling software is using, and it is best to pick one convention for all your objects, and be
|
||||
consistent. This input parameter must be a normalized vector. This vector must be perpendicular to the
|
||||
vector localForward, i.e. localForward.Dot(localUp) == 0.
|
||||
@param worldUp Specifies the global up direction of the scene in world space. Simply rotating one vector to
|
||||
coincide with another (localForward->targetDirection) would cause the up direction of the resulting
|
||||
orientation to drift (e.g. the model could be looking at its target its head slanted sideways). To keep
|
||||
the up direction straight, this function orients the localUp direction of the model to point towards
|
||||
the specified worldUp direction (as closely as possible). The worldUp and targetDirection vectors cannot be
|
||||
collinear, but they do not need to be perpendicular either.
|
||||
@return A quaternion that maps the given local space forward direction vector to point towards the given target
|
||||
direction, and the given local up direction towards the given target world up direction. For the returned
|
||||
quaternion Q it holds that M * localForward = targetDirection, and M * localUp lies in the plane spanned
|
||||
by the vectors targetDirection and worldUp.
|
||||
@see RotateFromTo() */
|
||||
static Quaternion LookAt(const Vector3& localForward, const Vector3& targetDirection, const Vector3& localUp, const Vector3& worldUp);
|
||||
|
||||
/// Creates a new Quaternion that rotates about the given axis by the given angle.
|
||||
static Quaternion RotateAxisAngle(const AxisAngle& axisAngle);
|
||||
|
||||
/// Creates a new quaternion that rotates about the positive X axis by the given rotation.
|
||||
static Quaternion RotateX(float angleRadians);
|
||||
/// Creates a new quaternion that rotates about the positive Y axis by the given rotation.
|
||||
static Quaternion RotateY(float angleRadians);
|
||||
/// Creates a new quaternion that rotates about the positive Z axis by the given rotation.
|
||||
static Quaternion RotateZ(float angleRadians);
|
||||
|
||||
/// Creates a new quaternion that rotates sourceDirection vector (in world space) to coincide with the
|
||||
/// 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);
|
||||
/// Quaternion from Matrix4x4 RotatePart.
|
||||
explicit Quaternion(const Matrix4x4 &ro_mat);
|
||||
|
||||
|
||||
/// Returns a uniformly random unitary quaternion.
|
||||
static Quaternion RandomRotation(RNG &rng);
|
||||
public:
|
||||
void SetFromAxisAngle(const Vector3 &vector3, float between);
|
||||
/// Quaternion from AxisAngle.
|
||||
explicit Quaternion(const AxisAngle &angle);
|
||||
|
||||
void SetFromAxisAngle(const Vector4 &vector4, float between);
|
||||
void SetFrom(const AxisAngle& angle);
|
||||
/// Quaternion from Vector4 (no conversion).
|
||||
explicit Quaternion(const Vector4 &vector4);
|
||||
|
||||
/// Inverses this quaternion in-place.
|
||||
/// @note For optimization purposes, this function assumes that the quaternion is unitary, in which
|
||||
/// case the inverse of the quaternion is simply just the same as its conjugate.
|
||||
/// This function does not detect whether the operation succeeded or failed.
|
||||
void Inverse();
|
||||
/// @param x The factor of i.
|
||||
/// @param y The factor of j.
|
||||
/// @param z The factor of k.
|
||||
/// @param w The scalar factor (or 'w').
|
||||
/// @note The input data is not normalized after construction, this has to be done manually.
|
||||
Quaternion(float X, float Y, float Z, float W);
|
||||
|
||||
/// Returns an inverted copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Inverted() const;
|
||||
/// Computes the conjugate of this quaternion in-place.
|
||||
void Conjugate();
|
||||
/// Returns a conjugated copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Conjugated() const;
|
||||
/// Creates a LookAt quaternion.
|
||||
/** A LookAt quaternion is a quaternion that orients an object to face towards a specified target direction.
|
||||
@param localForward Specifies the forward direction in the local space of the object. This is the direction
|
||||
the model is facing at in its own local/object space, often +X(1,0,0), +Y(0,1,0), or +Z(0,0,1).
|
||||
The vector to pass in here depends on the conventions you or your modeling software is using, and it is best
|
||||
to pick one convention for all your objects, and be consistent.
|
||||
This input parameter must be a normalized vector.
|
||||
@param targetDirection Specifies the desired world space direction the object should look at. This function
|
||||
will compute a quaternion which will rotate the localForward vector to orient towards this targetDirection
|
||||
vector. This input parameter must be a normalized vector.
|
||||
@param localUp Specifies the up direction in the local space of the object. This is the up direction the model
|
||||
was authored in, often +Y (0,1,0) or +Z (0,0,1). The vector to pass in here depends on the conventions you
|
||||
or your modeling software is using, and it is best to pick one convention for all your objects, and be
|
||||
consistent. This input parameter must be a normalized vector. This vector must be perpendicular to the
|
||||
vector localForward, i.e. localForward.Dot(localUp) == 0.
|
||||
@param worldUp Specifies the global up direction of the scene in world space. Simply rotating one vector to
|
||||
coincide with another (localForward->targetDirection) would cause the up direction of the resulting
|
||||
orientation to drift (e.g. the model could be looking at its target its head slanted sideways). To keep
|
||||
the up direction straight, this function orients the localUp direction of the model to point towards
|
||||
the specified worldUp direction (as closely as possible). The worldUp and targetDirection vectors cannot be
|
||||
collinear, but they do not need to be perpendicular either.
|
||||
@return A quaternion that maps the given local space forward direction vector to point towards the given target
|
||||
direction, and the given local up direction towards the given target world up direction. For the returned
|
||||
quaternion Q it holds that M * localForward = targetDirection, and M * localUp lies in the plane spanned
|
||||
by the vectors targetDirection and worldUp.
|
||||
@see RotateFromTo() */
|
||||
static Quaternion LookAt(const Vector3 &localForward, const Vector3 &targetDirection, const Vector3 &localUp, const Vector3 &worldUp);
|
||||
|
||||
/// Inverses this quaternion in-place.
|
||||
/// Call this function when the quaternion is not known beforehand to be normalized.
|
||||
/// This function computes the inverse proper, and normalizes the result.
|
||||
/// @note Because of the normalization, it does not necessarily hold that q * q.InverseAndNormalize() == id.
|
||||
/// @return Returns the old length of this quaternion (not the old length of the inverse quaternion).
|
||||
float InverseAndNormalize();
|
||||
/// Creates a new quaternion that rotates about the positive X axis by the given rotation.
|
||||
static Quaternion RotateX(float rad);
|
||||
|
||||
/// 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;
|
||||
/// 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;
|
||||
/// 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;
|
||||
/// Creates a new quaternion that rotates about the positive Y axis by the given rotation.
|
||||
static Quaternion RotateY(float rad);
|
||||
|
||||
/// Returns the axis of rotation for this quaternion.
|
||||
[[nodiscard]] Vector3 Axis() const;
|
||||
/// Creates a new quaternion that rotates about the positive Z axis by the given rotation.
|
||||
static Quaternion RotateZ(float rad);
|
||||
|
||||
/// Returns the angle of rotation for this quaternion, in radians.
|
||||
[[nodiscard]] float Angle() const;
|
||||
/// Creates a new quaternion that rotates sourceDirection vector (in world space) to coincide with the
|
||||
/// 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);
|
||||
|
||||
[[nodiscard]] float LengthSquared() const;
|
||||
[[nodiscard]] float Length() const;
|
||||
static Quaternion RotateFromTo(const Vector4 &sourceDirection, const Vector4 &targetDirection);
|
||||
|
||||
[[nodiscard]] EulerAngle ToEulerAngle() const;
|
||||
/// 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);
|
||||
|
||||
|
||||
[[nodiscard]] Matrix3x3 ToMatrix3x3() const;
|
||||
[[nodiscard]] Matrix4x4 ToMatrix4x4() const;
|
||||
/// Returns a uniformly random unitary quaternion.
|
||||
static Quaternion RandomRotation(RNG &rng);
|
||||
|
||||
[[nodiscard]] Matrix4x4 ToMatrix4x4(const Vector3 &translation) const;
|
||||
public:
|
||||
/// Inverses this quaternion in-place.
|
||||
/// @note For optimization purposes, this function assumes that the quaternion is unitary, in which
|
||||
/// case the inverse of the quaternion is simply just the same as its conjugate.
|
||||
/// This function does not detect whether the operation succeeded or failed.
|
||||
void Inverse();
|
||||
|
||||
[[nodiscard]] Vector3 Transform(const Vector3& vec) 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
|
||||
[[nodiscard]] Vector4 Transform(const Vector4& vec) const;
|
||||
[[nodiscard]] Vector4 Transform(float X, float Y, float Z, float W) const;
|
||||
/// Returns an inverted copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Inverted() 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 Slerp(const Quaternion &source, const Quaternion& target, float t);
|
||||
/// Computes the conjugate of this quaternion in-place.
|
||||
void Conjugate();
|
||||
|
||||
/// 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.
|
||||
@param from A normalized direction vector specifying the direction of rotation at t=0
|
||||
@param to A normalized direction vector specifying the direction of rotation at t=1
|
||||
@param t The interpolation time parameter, in the range [0, 1]. Input values outside this range are
|
||||
silently clamped to the [0, 1] interval.
|
||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||
static Vector3 SlerpVector(const Vector3& from, const Vector3& to, float t);
|
||||
/// Returns a conjugated copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Conjugated() const;
|
||||
|
||||
/// 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.
|
||||
@param from A normalized direction vector specifying the direction of rotation at angleRadians=0.
|
||||
@param to A normalized direction vector specifying the target direction to rotate towards.
|
||||
@param angleRadians The maximum angle to rotate the 'from' vector by, in the range [0, pi]. If the
|
||||
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.
|
||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||
static Vector3 SlerpVectorAbs(const Vector3 &from, const Vector3& to, float angleRadians);
|
||||
/// Inverses this quaternion in-place.
|
||||
/// Call this function when the quaternion is not known beforehand to be normalized.
|
||||
/// This function computes the inverse proper, and normalizes the result.
|
||||
/// @note Because of the normalization, it does not necessarily hold that q * q.InverseAndNormalize() == id.
|
||||
/// @return Returns the old length of this quaternion (not the old length of the inverse quaternion).
|
||||
float InverseAndNormalize();
|
||||
|
||||
/// Normalizes this quaternion in-place.
|
||||
/// Returns the old length of this quaternion, or 0 if normalization failed.
|
||||
float Normalize();
|
||||
/// Returns a normalized copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Normalized() const;
|
||||
/// 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;
|
||||
|
||||
/// Returns true if the length of this quaternion is one.
|
||||
[[nodiscard]] bool IsNormalized(float epsilon = 1e-5f) const;
|
||||
[[nodiscard]] bool IsInvertible(float epsilon = 1e-3f) 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.
|
||||
[[nodiscard]] Vector3 WorldY() const;
|
||||
|
||||
/// Returns true if the entries of this quaternion are all finite.
|
||||
[[nodiscard]] bool IsFinite() 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.
|
||||
[[nodiscard]] Vector3 WorldZ() const;
|
||||
|
||||
/// Returns true if this quaternion equals rhs, up to the given epsilon.
|
||||
[[nodiscard]] bool Equals(const Quaternion& rhs, float epsilon = 1e-3f) const;
|
||||
/// Returns the axis of rotation for this quaternion.
|
||||
[[nodiscard]] Vector3 Axis() const;
|
||||
|
||||
/// 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.
|
||||
bool BitEquals(const Quaternion& rhs) const;
|
||||
/// Returns the angle of rotation for this quaternion, in radians.
|
||||
[[nodiscard]] float Angle() const;
|
||||
|
||||
/// @return A pointer to the first element (x). The data is contiguous in memory.
|
||||
/// ptr[0] gives x, ptr[1] gives y, ptr[2] gives z, ptr[3] gives w.
|
||||
inline float *ptr() { return &x; }
|
||||
[[nodiscard]] inline const float *ptr() const { return &x; }
|
||||
[[nodiscard]] float LengthSquared() const;
|
||||
|
||||
[[nodiscard]] float Length() const;
|
||||
|
||||
[[nodiscard]] Matrix3x3 ToMatrix3x3() const;
|
||||
|
||||
[[nodiscard]] Matrix4x4 ToMatrix4x4() const;
|
||||
|
||||
[[nodiscard]] Matrix4x4 ToMatrix4x4(const Vector3 &translation) const;
|
||||
|
||||
[[nodiscard]] Vector3 Transform(const Vector3 &vec) 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
|
||||
[[nodiscard]] Vector4 Transform(const Vector4 &vec) const;
|
||||
|
||||
[[nodiscard]] Vector4 Transform(float X, float Y, float Z, float W) 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 Slerp(const Quaternion &source, const Quaternion &target, float t);
|
||||
|
||||
/// 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.
|
||||
@param from A normalized direction vector specifying the direction of rotation at t=0
|
||||
@param to A normalized direction vector specifying the direction of rotation at t=1
|
||||
@param t The interpolation time parameter, in the range [0, 1]. Input values outside this range are
|
||||
silently clamped to the [0, 1] interval.
|
||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||
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.
|
||||
/** This function slerps the given 'from' vector towards the 'to' vector.
|
||||
@param from A normalized direction vector specifying the direction of rotation at angleRadians=0.
|
||||
@param to A normalized direction vector specifying the target direction to rotate towards.
|
||||
@param angleRadians The maximum angle to rotate the 'from' vector by, in the range [0, pi]. If the
|
||||
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.
|
||||
@return A spherical linear interpolation of the vector 'from' towards the vector 'to'. */
|
||||
static Vector3 SlerpVectorAbs(const Vector3 &from, const Vector3 &to, float angleRadians);
|
||||
|
||||
/// Normalizes this quaternion in-place.
|
||||
/// @returns false if failure, true if success.
|
||||
[[nodiscard]] bool Normalize();
|
||||
|
||||
/// Returns a normalized copy of this quaternion.
|
||||
[[nodiscard]] Quaternion Normalized() const;
|
||||
|
||||
/// Returns true if the length of this quaternion is one.
|
||||
[[nodiscard]] bool IsNormalized(float epsilon = 1e-5f) const;
|
||||
|
||||
[[nodiscard]] bool IsInvertible(float epsilon = 1e-3f) const;
|
||||
|
||||
/// Returns true if the entries of this quaternion are all finite.
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
|
||||
/// Returns true if this quaternion equals rhs, up to the given epsilon.
|
||||
[[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.
|
||||
/// @note Prefer using this over e.g. memcmp, since there can be SSE-related padding in the structures.
|
||||
bool BitEquals(const Quaternion& rhs) const;
|
||||
|
||||
/// @return A pointer to the first element (x). The data is contiguous in memory.
|
||||
/// ptr[0] gives x, ptr[1] gives y, ptr[2] gives z, ptr[3] gives w.
|
||||
inline float *ptr() { return &x; }
|
||||
[[nodiscard]] inline const float *ptr() const { return &x; }
|
||||
|
||||
|
||||
// Multiplies two quaternions together.
|
||||
// The product q1 * q2 returns a quaternion that concatenates the two orientation rotations.
|
||||
// The rotation q2 is applied first before q1.
|
||||
Quaternion operator * (const Quaternion& rhs) const;
|
||||
// Multiplies two quaternions together.
|
||||
// The product q1 * q2 returns a quaternion that concatenates the two orientation rotations.
|
||||
// The rotation q2 is applied first before q1.
|
||||
Quaternion operator * (const Quaternion& rhs) const;
|
||||
|
||||
// Unsafe
|
||||
Quaternion operator * (float scalar) const;
|
||||
// Unsafe
|
||||
Quaternion operator * (float scalar) const;
|
||||
|
||||
// Unsafe
|
||||
Quaternion operator / (float scalar) const;
|
||||
// Unsafe
|
||||
Quaternion operator / (float scalar) const;
|
||||
|
||||
// Transforms the given vector by this Quaternion.
|
||||
Vector3 operator * (const Vector3& rhs) const;
|
||||
// Transforms the given vector by this Quaternion.
|
||||
Vector3 operator * (const Vector3& rhs) const;
|
||||
|
||||
Vector4 operator * (const Vector4& rhs) const;
|
||||
Vector4 operator * (const Vector4& rhs) const;
|
||||
|
||||
// Divides a quaternion by another. Divison "a / b" results in a quaternion that rotates the orientation b to coincide with orientation of
|
||||
Quaternion operator / (const Quaternion& rhs) const;
|
||||
Quaternion operator + (const Quaternion& rhs) const;
|
||||
// Divides a quaternion by another. Divison "a / b" results in a quaternion that rotates the orientation b to coincide with orientation of
|
||||
Quaternion operator / (const Quaternion& rhs) const;
|
||||
Quaternion operator + (const Quaternion& rhs) const;
|
||||
|
||||
|
||||
|
||||
Quaternion operator + () const;
|
||||
Quaternion operator - () const;
|
||||
Quaternion operator + () const;
|
||||
Quaternion operator - () const;
|
||||
|
||||
/// Computes the dot product of this and the given quaternion.
|
||||
/// Dot product is commutative.
|
||||
[[nodiscard]] float Dot(const Quaternion &quaternion) const;
|
||||
/// Computes the dot product of this and the given quaternion.
|
||||
/// Dot product is commutative.
|
||||
[[nodiscard]] float Dot(const Quaternion &quaternion) const;
|
||||
|
||||
/// Returns the angle between this and the target orientation (the shortest route) in radians.
|
||||
[[nodiscard]] float AngleBetween(const Quaternion& target) const;
|
||||
/// Returns the axis of rotation to get from this orientation to target orientation (the shortest route).
|
||||
[[nodiscard]] Vector3 AxisFromTo(const Quaternion& target) const;
|
||||
/// Returns the angle between this and the target orientation (the shortest route) in radians.
|
||||
[[nodiscard]] float AngleBetween(const Quaternion& target) const;
|
||||
/// Returns the axis of rotation to get from this orientation to target orientation (the shortest route).
|
||||
[[nodiscard]] Vector3 AxisFromTo(const Quaternion& target) const;
|
||||
|
||||
|
||||
[[nodiscard]] AxisAngle ToAxisAngle() const;
|
||||
void SetFromAxisAngle(const AxisAngle& axisAngle);
|
||||
/// Sets this quaternion to represent the same rotation as the given matrix.
|
||||
void Set(const Matrix3x3& matrix);
|
||||
void Set(const Matrix4x4& matrix);
|
||||
void Set(float x, float y, float z, float w);
|
||||
void Set(const Quaternion& q);
|
||||
void Set(const Vector4& v);
|
||||
|
||||
/// Sets this quaternion to represent the same rotation as the given matrix.
|
||||
void Set(const Matrix3x3& matrix);
|
||||
void Set(const Matrix4x4& matrix);
|
||||
void Set(float x, float y, float z, float w);
|
||||
void Set(const Quaternion& q);
|
||||
void Set(const Vector4& v);
|
||||
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
}
|
||||
};
|
@@ -4,36 +4,52 @@
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// A class that performs and represents translations, rotations, and scaling operations in two dimensions.
|
||||
class Transform2D {
|
||||
protected:
|
||||
// TODO: Verify column-major order (or transpose it) for compatibility with OpenGL.
|
||||
Matrix3x3 transformation;
|
||||
public:
|
||||
|
||||
const static Transform2D Identity;
|
||||
const static Transform2D FlipX;
|
||||
const static Transform2D FlipY;
|
||||
|
||||
Transform2D(float rotation, const Vector2& pos);
|
||||
Transform2D(float px, float py, float sx, float sy, float ox, float oy, float kx, float ky, float rotation)
|
||||
{
|
||||
transformation = Matrix3x3(px, py, rotation, sx, sy, ox, oy, kx, ky);
|
||||
}
|
||||
/// Default constructor initializes to an Identity transformation.
|
||||
Transform2D();
|
||||
|
||||
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(float x, float y) const;
|
||||
Transform2D Scale(float scale); // Perform Uniform Scale
|
||||
Transform2D Scale(float x, float y); // Perform Nonunform Scale
|
||||
Transform2D Scale(const Vector2& scales); // Perform Nonuniform Scale
|
||||
Transform2D Rotate();
|
||||
Vector2 Transform(const Vector2& input) const;
|
||||
Transform2D Scale(float scale);
|
||||
Transform2D Scale(float x, float y);
|
||||
Transform2D Scale(const Vector2& scales);
|
||||
Transform2D Rotate(float radians);
|
||||
|
||||
/// Transforms a given 2D point by this transformation.
|
||||
Vector2 Transform(const Vector2& point) const;
|
||||
Transform2D Inverse() const;
|
||||
Transform2D AffineInverse() const;
|
||||
|
||||
Vector2 ForwardVector() const;
|
||||
Vector2 UpVector() 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;
|
||||
Vector2 GetScale() const;
|
||||
float GetSkew() const;
|
||||
Transform2D OrthoNormalize();
|
||||
};
|
||||
}
|
||||
|
@@ -1,15 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
template <uint DIMS, typename T>
|
||||
|
||||
template <size_t D, typename T>
|
||||
class Vector {
|
||||
static_assert(D > 1, "A vector cannot be of 1-dimension, it would be just a scalar!");
|
||||
public:
|
||||
enum { Dimensions = DIMS};
|
||||
T elems[DIMS];
|
||||
static constexpr bool IsAtLeast1D = D >= 1; // Should always be true for a proper vector.
|
||||
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,11 +55,12 @@ namespace J3ML::LinearAlgebra {
|
||||
Vector2(float X, float Y);
|
||||
/// Constructs this float2 from a C array, to the value (data[0], data[1]).
|
||||
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);
|
||||
Vector2(const Vector2& rhs); // Copy Constructor
|
||||
//Vector2(Vector2&&) = default; // Move Constructor
|
||||
|
||||
explicit Vector2(const Vector2i& rhs);
|
||||
/// 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 GetY() const;
|
||||
@@ -110,17 +111,15 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// Tests if two vectors are equal, up to the given epsilon.
|
||||
/** @see IsPerpendicular(). */
|
||||
bool Equals(const Vector2& rhs, float epsilon = 1e-3f) const {
|
||||
return Math::EqualAbs(x, rhs.x, epsilon) &&
|
||||
Math::EqualAbs(y, rhs.y, epsilon);
|
||||
}
|
||||
bool Equals(float x_, float y_, float epsilon = 1e-3f) const {
|
||||
return Math::EqualAbs(x, x_, epsilon) &&
|
||||
Math::EqualAbs(y, y_, epsilon);
|
||||
}
|
||||
bool Equals(const Vector2& rhs, float epsilon = 1e-3f) const;
|
||||
bool Equals(float x_, float y_, float epsilon = 1e-3f) const;
|
||||
|
||||
bool PreciselyEquals(const Vector2& rhs) const;
|
||||
|
||||
bool operator == (const Vector2& rhs) const;
|
||||
bool operator != (const Vector2& rhs) const;
|
||||
bool operator > (const Vector2& rhs) const;
|
||||
bool operator < (const Vector2& rhs) const;
|
||||
|
||||
/// Returns an element-wise minimum between two vectors.
|
||||
[[nodiscard]] Vector2 Min(const Vector2& min) const;
|
||||
@@ -385,6 +384,7 @@ namespace J3ML::LinearAlgebra {
|
||||
static Vector2 RandomBox(Algorithm::RNG& rng, float minElem, float maxElem);
|
||||
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
|
||||
};
|
||||
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs);
|
||||
|
@@ -1,11 +1,34 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "Vector2.hpp"
|
||||
|
||||
namespace J3ML::LinearAlgebra
|
||||
{
|
||||
class Vector2i
|
||||
{
|
||||
public:
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
}
|
||||
namespace J3ML::LinearAlgebra {
|
||||
class Vector2i;
|
||||
}
|
||||
|
||||
class J3ML::LinearAlgebra::Vector2i {
|
||||
public:
|
||||
int x, y;
|
||||
public:
|
||||
Vector2i();
|
||||
Vector2i(int x, int y) : x(x), y(y) {}
|
||||
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:
|
||||
bool operator == (const Vector2i& rhs) const;
|
||||
bool operator != (const Vector2i& rhs) const;
|
||||
Vector2i& operator =(const Vector2i& rhs);
|
||||
Vector2i& operator +=(const Vector2i& rhs);
|
||||
Vector2i& operator -=(const Vector2i& rhs);
|
||||
Vector2i& operator *=(const Vector2i& rhs);
|
||||
Vector2i& operator /=(const Vector2i& rhs);
|
||||
Vector2i operator +(const Vector2i& rhs) const;
|
||||
Vector2i operator -(const Vector2i& rhs) const;
|
||||
Vector2i operator *(const Vector2i& rhs) const;
|
||||
Vector2i operator *(int rhs) const;
|
||||
Vector2i operator /(const Vector2i& rhs) const;
|
||||
Vector2i operator /(int rhs) const;
|
||||
public:
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
};
|
@@ -68,15 +68,15 @@ public:
|
||||
/** @note Due to static data initialization order being undefined in C++, do NOT use this
|
||||
member to initialize other static data in other compilation units! */
|
||||
static const Vector3 NegativeInfinity;
|
||||
/// Specifies a compile-time constant Vector3 with value (1,1,1).
|
||||
/// Specifies a compile-time constant Vector3 with value (1,0,0).
|
||||
/** @note Due to static data initialization order being undefined in C++, do NOT use this
|
||||
member to initialize other static data in other compilation units! */
|
||||
static const Vector3 UnitX;
|
||||
/// Specifies a compile-time constant Vector3 with value (1,1,1).
|
||||
/// Specifies a compile-time constant Vector3 with value (0,1,0).
|
||||
/** @note Due to static data initialization order being undefined in C++, do NOT use this
|
||||
member to initialize other static data in other compilation units! */
|
||||
static const Vector3 UnitY;
|
||||
/// Specifies a compile-time constant Vector3 with value (1,1,1).
|
||||
/// Specifies a compile-time constant Vector3 with value (0,0,1).
|
||||
/** @note Due to static data initialization order being undefined in C++, do NOT use this
|
||||
member to initialize other static data in other compilation units! */
|
||||
static const Vector3 UnitZ;
|
||||
|
@@ -30,6 +30,9 @@ namespace J3ML::LinearAlgebra {
|
||||
because there is a considerable SIMD performance benefit in the first form.
|
||||
@see x, y, z, 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.
|
||||
Vector4(const Vector4& copy) { Set(copy); }
|
||||
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
|
||||
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. */
|
||||
inline float* ptr();
|
||||
float* ptr();
|
||||
[[nodiscard]] const float* ptr() const;
|
||||
|
||||
/// 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.
|
||||
/** @see NormalizeW(), IsWZeroOrOne(), IsZero4(), IsNormalized3(), IsNormalized4(). */
|
||||
[[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 IsZero4(float epsilonSq = 1e-6f) const;
|
||||
|
||||
/// Tests if this vector contains valid finite elements.
|
||||
[[nodiscard]] bool IsFinite() const;
|
||||
|
||||
@@ -202,6 +202,7 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
[[nodiscard]] float Magnitude() 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.
|
||||
/** @note This function ignores the w component of this vector (assumes w=0).
|
||||
@see Dot4(), Cross3(). */
|
||||
@@ -209,10 +210,9 @@ namespace J3ML::LinearAlgebra {
|
||||
[[nodiscard]] float Dot3(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
|
||||
// You should consider instead looking at Gram-Schmidt Orthogonalization
|
||||
// to find orthonormal vectors.
|
||||
|
||||
/// 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 to find orthonormal vectors.
|
||||
[[nodiscard]] Vector4 Cross3(const Vector3& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
|
||||
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
|
||||
@@ -220,7 +220,11 @@ namespace J3ML::LinearAlgebra {
|
||||
[[nodiscard]] Vector4 Normalized() 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 AngleBetween4(const Vector4& rhs) const;
|
||||
|
||||
/// Adds two vectors. [indexTitle: operators +,-,*,/]
|
||||
/** 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().
|
||||
@return float4(x * scalar, y * scalar, z * scalar, w * scalar); */
|
||||
Vector4 operator *(float rhs) const;
|
||||
[[nodiscard]] Vector4 Mul(float scalar) const;
|
||||
static Vector4 Mul(const Vector4& lhs, float rhs);
|
||||
[[nodiscard]] Vector4 Mul(float scalar) const { return *this * scalar;}
|
||||
static Vector4 Mul(const Vector4& lhs, float rhs) {return lhs * rhs; }
|
||||
|
||||
/// Divides this vector by a scalar. [similarOverload: operator+] [hideIndex]
|
||||
/** This function is identical to the member function Div().
|
||||
@return float4(x / scalar, y / scalar, z / scalar, w * scalar); */
|
||||
Vector4 operator /(float rhs) const;
|
||||
[[nodiscard]] Vector4 Div(float scalar) const;
|
||||
static Vector4 Div(const Vector4& rhs, float scalar);
|
||||
[[nodiscard]] Vector4 Div(float scalar) const { return *this / 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]
|
||||
/** This function is identical to the member function Neg().
|
||||
@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);
|
||||
}
|
76
main.cpp
76
main.cpp
@@ -11,21 +11,91 @@
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <J3ML/Geometry.hpp>
|
||||
#include "J3ML/J3ML.hpp"
|
||||
#include <J3ML/J3ML.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)
|
||||
{
|
||||
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;
|
||||
|
||||
// Test quadrant
|
||||
for (float r = 0; r < TwoPi; r+=0.25f)
|
||||
{
|
||||
Quadrant q = QuadrantOf(r);
|
||||
if (q == Quadrant::I)
|
||||
std::cout << "I" << std::endl;
|
||||
if (q == Quadrant::II)
|
||||
std::cout << "II" << std::endl;
|
||||
if (q == Quadrant::III)
|
||||
std::cout << "III" << std::endl;
|
||||
if (q == Quadrant::IV)
|
||||
std::cout << "IV" << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 10; i < 9999999; i*=1.5f) {
|
||||
std::cout << J3ML::Math::Functions::Truncate(i) << std::endl;
|
||||
}
|
||||
|
||||
Ray a({420, 0, 0}, {1, 0, 0});
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,13 @@
|
||||
#include <J3ML/Algorithm/Bezier.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
|
||||
namespace J3ML::Algorithm
|
||||
{
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
Vector2 BezierNormal(float t, const Vector2 &p0, const Vector2 &p1,
|
||||
const Vector2 &p2, const Vector2 &p3) {
|
||||
auto derived = BezierDerivative(t, p0, p1, p2, p3);
|
||||
Vector2 derived = BezierDerivative(t, p0, p1, p2, p3);
|
||||
return derived.Normalized();
|
||||
}
|
||||
|
||||
@@ -16,5 +18,24 @@ namespace J3ML::Algorithm
|
||||
Vector2 Bezier(float t, const Vector2 &p0, const Vector2 &p1, const Vector2 &p2, const Vector2 &p3) {
|
||||
return {Bezier(t, p0.x, p1.x, p2.x, p3.x), Bezier(t, p0.y, p1.y, p2.y, p3.y)};
|
||||
}
|
||||
|
||||
Vector3 BezierDerivative(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3)
|
||||
{
|
||||
return 3 * Square(1 - t) * (p1 - p0) + 6 * (1 - t) * t * (p2 - p1) + 3 * Square(t) * (p3 - p2);
|
||||
}
|
||||
|
||||
Vector3 BezierNormal(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3)
|
||||
{
|
||||
Vector3 derived = BezierDerivative(t, p0, p1, p2, p3);
|
||||
return derived.Normalized();
|
||||
}
|
||||
|
||||
Vector3 Bezier(float t, const Vector3& p0, const Vector3& p1, const Vector3& p2, const Vector3& p3)
|
||||
{
|
||||
return {
|
||||
Bezier(t, p0.x, p1.x, p2.x, p3.x),
|
||||
Bezier(t, p0.y, p1.y, p2.y, p3.y),
|
||||
Bezier(t, p0.z, p1.z, p2.z, p3.z)};
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -77,4 +77,20 @@ namespace J3ML::Geometry
|
||||
a.maxPoint = maxPoint - pt;
|
||||
return a;
|
||||
}
|
||||
|
||||
Vector2 AABB2D::Centroid() const {
|
||||
return (minPoint + (maxPoint / 2.f));
|
||||
}
|
||||
|
||||
Vector2 AABB2D::CornerPoint(int cornerIndex) {
|
||||
assert(0 <= cornerIndex && cornerIndex <= 3);
|
||||
switch(cornerIndex)
|
||||
{
|
||||
default:
|
||||
case 0: return minPoint;
|
||||
case 1: return {minPoint.x, maxPoint.y};
|
||||
case 2: return {maxPoint.x, minPoint.y};
|
||||
case 3: return maxPoint;
|
||||
}
|
||||
}
|
||||
}
|
@@ -129,23 +129,6 @@ namespace J3ML::Geometry
|
||||
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> frustumVolume;
|
||||
frustumVolume.p[0] = NearPlane();
|
||||
|
6
src/J3ML/Geometry/Icosahedron.cpp
Normal file
6
src/J3ML/Geometry/Icosahedron.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <J3ML/Geometry/Icosahedron.hpp>
|
||||
|
||||
namespace J3ML
|
||||
{
|
||||
|
||||
}
|
165
src/J3ML/Geometry/LineSegment2D.cpp
Normal file
165
src/J3ML/Geometry/LineSegment2D.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include <J3ML/Geometry/LineSegment2D.hpp>
|
||||
|
||||
void Line2DClosestPointLineLine(const Vector2& v0, const Vector2& v10, const Vector2& v2, const Vector2& v32, float& d, float& d2) // TODO: Move to Line2D when that exists
|
||||
{
|
||||
// assert(!v10.IsZero());
|
||||
// assert(!v32.IsZero());
|
||||
Vector2 v02 = v0 - v2;
|
||||
float d0232 = v02.Dot(v32);
|
||||
float d3210 = v32.Dot(v10);
|
||||
float d3232 = v32.Dot(v32);
|
||||
// assert(d3232 != 0.f); // Don't call with a zero direction vector.
|
||||
float d0210 = v02.Dot(v10);
|
||||
float d1010 = v10.Dot(v10);
|
||||
float denom = d1010*d3232 - d3210*d3210;
|
||||
|
||||
d = (denom !=0) ? (d0232*d3210 - d0210*d3232) / denom : 0;
|
||||
|
||||
d2 = (d0232 + d * d3210) / d3232;
|
||||
}
|
||||
|
||||
Geometry::LineSegment2D::LineSegment2D(const Vector2 &a, const Vector2 &b)
|
||||
: A(a), B(b) {}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::GetPoint(float d) const {
|
||||
return (1.f - d) * A + d * B;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::CenterPoint() const {
|
||||
return (A + B) * 0.5f;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::Centroid() const {
|
||||
return CenterPoint();
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Reverse() {
|
||||
Swap(A, B);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::Dir() const {
|
||||
return (B - A).Normalized();
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::AnyPointFast() const { return A; }
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ExtremePoint(const Vector2 &direction) const {
|
||||
return Vector2::Dot(direction, B - A) >= 0.f ? B : A;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ExtremePoint(const Vector2 &direction, float &projectionDistance) const {
|
||||
Vector2 extremePoint = ExtremePoint(direction);
|
||||
projectionDistance = extremePoint.Dot(direction);
|
||||
return extremePoint;
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Translate(const Vector2 &offset) {
|
||||
A += offset;
|
||||
B += offset;
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Matrix3x3 &transform) {
|
||||
A = transform.Mul(A);
|
||||
B = transform.Mul(B);
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Matrix4x4 &transform) {
|
||||
A = transform.Mul(A);
|
||||
B = transform.Mul(B);
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::Transform(const Quaternion &transform) {
|
||||
//A = transform.Mul(A);
|
||||
//B = transform.Mul(B);
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::Length() const { return A.Distance(B); }
|
||||
|
||||
float Geometry::LineSegment2D::LengthSq() const { return A.DistanceSq(B); }
|
||||
|
||||
float Geometry::LineSegment2D::LengthSquared() const { return LengthSq(); }
|
||||
|
||||
bool Geometry::LineSegment2D::IsFinite() const { return A.IsFinite() && B.IsFinite(); }
|
||||
|
||||
bool Geometry::LineSegment2D::Equals(const Geometry::LineSegment2D &rhs, float epsilon) const {
|
||||
return (A.Equals(rhs.A, epsilon) && B.Equals(rhs.B, epsilon) ||
|
||||
A.Equals(rhs.B, epsilon) && B.Equals(rhs.A, epsilon));
|
||||
}
|
||||
|
||||
bool Geometry::LineSegment2D::Contains(const Vector2 &point, float epsilon) const {
|
||||
return ClosestPoint(point).DistanceSq(point) <= epsilon;
|
||||
}
|
||||
|
||||
bool Geometry::LineSegment2D::Contains(const Geometry::LineSegment2D &rhs, float epsilon) const {
|
||||
return Contains(rhs.A, epsilon) && Contains(rhs.B, epsilon);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Vector2 &point) const {
|
||||
float d;
|
||||
return ClosestPoint(point, d);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Vector2 &point, float &d) const {
|
||||
Vector2 dir = B - A;
|
||||
d = J3ML::Math::Clamp01(Vector2::Dot(point - A, dir) / dir.LengthSquared());
|
||||
return A + d * dir;
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other) const {
|
||||
float d, d2;
|
||||
return ClosestPoint(other, d, d2);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other, float &d) const {
|
||||
float d2; return ClosestPoint(other, d, d2);
|
||||
}
|
||||
|
||||
Vector2 Geometry::LineSegment2D::ClosestPoint(const Geometry::LineSegment2D &other, float &d, float &d2) const {
|
||||
Vector2 dir = B - A;
|
||||
Line2DClosestPointLineLine(A, B - A, other.A, other.B - other.A, d, d2);
|
||||
|
||||
|
||||
return Vector2::Zero;
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::Distance(const Vector2 &point) const { float d; return Distance(point, d); }
|
||||
|
||||
float Geometry::LineSegment2D::Distance(const Vector2 &point, float &d) const {
|
||||
/// See Christer Ericson's Real-Time Collision Detection, p. 130.
|
||||
Vector2 closestPoint = ClosestPoint(point, d);
|
||||
return closestPoint.Distance(point);
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::Distance(const Geometry::LineSegment2D &other) const { float d, d2; return Distance(other, d, d2);}
|
||||
|
||||
float Geometry::LineSegment2D::Distance(const Geometry::LineSegment2D &other, float &d) const { float d2; return Distance(other, d, d2); }
|
||||
|
||||
float Geometry::LineSegment2D::Distance(const Geometry::LineSegment2D &other, float &d, float &d2) const {
|
||||
ClosestPoint(other, d, d2);
|
||||
return GetPoint(d).Distance(other.GetPoint(d2));
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::DistanceSq(const Geometry::LineSegment2D &other) const {
|
||||
float d, d2;
|
||||
ClosestPoint(other, d, d2);
|
||||
return GetPoint(d).DistanceSq(other.GetPoint(d2));
|
||||
}
|
||||
|
||||
float Geometry::LineSegment2D::DistanceSq(const Vector2 &point) const {
|
||||
float d;
|
||||
/// See Christer Ericson's Real-Time Collision Detection, p.130.
|
||||
Vector2 closestPoint = ClosestPoint(point, d);
|
||||
return closestPoint.DistanceSq(point);
|
||||
}
|
||||
|
||||
bool Geometry::LineSegment2D::Intersects(const Geometry::LineSegment2D &lineSegment, float epsilon) const {
|
||||
return Distance(lineSegment) <= epsilon;
|
||||
}
|
||||
|
||||
void Geometry::LineSegment2D::ProjectToAxis(const Vector2 &direction, float &outMin, float &outMax) const {
|
||||
outMin = Vector2::Dot(direction, A);
|
||||
outMax = Vector2::Dot(direction, B);
|
||||
|
||||
if (outMax < outMin)
|
||||
Swap(outMin, outMax);
|
||||
}
|
@@ -372,7 +372,7 @@ namespace J3ML::Geometry
|
||||
Vector4 b = Vector4(poly.v[face.v[1]], 1.f);
|
||||
Vector4 c = Vector4(poly.v[face.v[2]], 1.f);
|
||||
Vector4 normal = (b-a).Cross(c-a);
|
||||
normal.Normalized();
|
||||
normal.Normalize();
|
||||
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();
|
||||
}
|
||||
@@ -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
|
||||
v0 = v1;
|
||||
}
|
||||
normal.Normalized();
|
||||
normal.Normalize();
|
||||
return normal;
|
||||
#if 0
|
||||
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;}
|
||||
|
||||
|
||||
}
|
@@ -9,18 +9,107 @@ namespace J3ML::Geometry
|
||||
return Contains(lineseg.A) && Contains(lineseg.B);
|
||||
}
|
||||
|
||||
TriangleMesh Sphere::GenerateUVSphere() const
|
||||
TriangleMesh Sphere::GenerateUVSphere(int subdivisions) const
|
||||
{
|
||||
// TODO: Implement this later
|
||||
return TriangleMesh();
|
||||
// http://www.songho.ca/opengl/gl_sphere.html
|
||||
|
||||
TriangleMesh mesh;
|
||||
|
||||
float x, y, z, xy; // Vertex Position
|
||||
float nx, ny, nz, lengthInv = 1.f / Radius; // Vertex Normal
|
||||
float s, t; // Vertex TexCoord
|
||||
|
||||
int sectorCount = subdivisions;
|
||||
int stackCount = subdivisions;
|
||||
|
||||
float sectorStep = 2.f * Math::Pi / sectorCount;
|
||||
float stackStep = Math::Pi / stackCount;
|
||||
float sectorAngle, stackAngle;
|
||||
|
||||
for (int i = 0; i <= stackCount; ++i)
|
||||
{
|
||||
stackAngle = Math::Pi / 2.f - i * stackStep; // starting from pi/2 to -pi/2
|
||||
xy = Radius * Math::Cos(stackAngle); // r * cos(u)
|
||||
z = Radius * Math::Sin(stackAngle); // r * sin(u)
|
||||
|
||||
// add (sectorCount + 1) vertices per stack
|
||||
// first and last vertices have same position and normal, but different tex coords
|
||||
for (int j = 0; j <= sectorCount; ++j)
|
||||
{
|
||||
sectorAngle = j * sectorStep; // starting from 0 to 2pi
|
||||
|
||||
// vertex position (x, y, z)
|
||||
x = xy * Math::Cos(sectorAngle);
|
||||
y = xy * Math::Sin(sectorAngle);
|
||||
|
||||
Vector3 vertex = {x, y, z};
|
||||
|
||||
mesh.Vertices.push_back(vertex);
|
||||
|
||||
// normalized vertex normal (nx, ny, nz)
|
||||
nx = x * lengthInv;
|
||||
ny = y * lengthInv;
|
||||
nz = z * lengthInv;
|
||||
|
||||
Vector3 normal = {nx, ny, nz};
|
||||
|
||||
mesh.Normals.push_back(normal);
|
||||
|
||||
// vertex tex coord (s, t) range between [0, 1]
|
||||
s = (float)j / sectorCount;
|
||||
t = (float)i / stackCount;
|
||||
|
||||
Vector2 TexCoords = {s, t};
|
||||
|
||||
mesh.UVs.push_back(normal);
|
||||
}
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
TriangleMesh Sphere::GenerateIcososphere() const
|
||||
{
|
||||
// TODO: Implement this later
|
||||
return TriangleMesh();
|
||||
|
||||
// Generate 12 vertices of an icosahedron for a given radius.
|
||||
|
||||
const float h_angle = Math::Pi / 180.f * 72.f; // 72 degree = 360 / 5;
|
||||
const float v_angle = Math::Atan(1.f / 2.f);
|
||||
|
||||
TriangleMesh mesh;
|
||||
|
||||
int i1, i2;
|
||||
float z, xy;
|
||||
float hAngle1 = -Math::Pi / 2.f - h_angle / 2.f;
|
||||
float hAngle2 = -Math::Pi / 2;
|
||||
|
||||
// the first top vertex at (0,0,r)
|
||||
Vector3 top_vertex = {0, 0, Radius};
|
||||
|
||||
// compute 10 vertices at 1st and 2nd rows
|
||||
for (int i = 1; i <= 5; ++i)
|
||||
{
|
||||
i1 = i * 3; // index for 1st row
|
||||
i2 = (i + 5) * 3; // index for 2nd row
|
||||
|
||||
z = Radius * Math::Sin(v_angle); // elevation
|
||||
xy = Radius * Math::Cos(v_angle); // length on XY plane
|
||||
|
||||
Vector3 vert_0 = {xy * Math::Cos(hAngle1), xy * Math::Sin(hAngle1), z};
|
||||
Vector3 vert_1 = {xy * Math::Cos(hAngle2), xy * Math::Sin(hAngle2), -z};
|
||||
|
||||
// next horizontal angles
|
||||
hAngle1 += h_angle;
|
||||
hAngle2 += h_angle;
|
||||
}
|
||||
|
||||
// the last bottom vertex at (0, 0, -r)
|
||||
i1 = 11 * 3;
|
||||
Vector3 last_vertex = {0,0, -Radius};
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
void Sphere::ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const
|
||||
{
|
||||
float d = Vector3::Dot(direction, Position);
|
||||
|
@@ -10,8 +10,7 @@
|
||||
|
||||
#include <format>
|
||||
#include <iomanip>
|
||||
#include <strstream>
|
||||
#include "J3ML/J3ML.hpp"
|
||||
#include <J3ML/J3ML.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -38,22 +37,104 @@ float PowUInt(float base, u32 exponent)
|
||||
}
|
||||
|
||||
|
||||
namespace J3ML
|
||||
{
|
||||
namespace J3ML::Math::Functions::Trigonometric {
|
||||
enum Sign SignOfSin(float radians) {
|
||||
enum Quadrant q = QuadrantOf(radians);
|
||||
if (q == Quadrant::I || q == Quadrant::II)
|
||||
return Sign::POSITIVE;
|
||||
|
||||
float Math::Functions::Radians(float degrees) { return degrees * (Pi/180.f); }
|
||||
// ReSharper disable once CppDFAConstantConditions
|
||||
if (q == Quadrant::II || q == Quadrant::IV)
|
||||
return Sign::NEGATIVE;
|
||||
|
||||
float Math::Functions::Degrees(float radians) { return radians * (180.f/Pi); }
|
||||
// ReSharper disable once CppDFAUnreachableCode
|
||||
return Sign::ZERO;
|
||||
}
|
||||
|
||||
enum Sign SignOfCos(float radians) {
|
||||
enum Quadrant q = QuadrantOf(radians);
|
||||
if (q == Quadrant::I || q == Quadrant::IV)
|
||||
return Sign::POSITIVE;
|
||||
|
||||
// ReSharper disable once CppDFAConstantConditions
|
||||
if (q == Quadrant::II || q == Quadrant::III)
|
||||
return Sign::NEGATIVE;
|
||||
|
||||
Math::Rotation Math::operator ""_degrees(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
// ReSharper disable once CppDFAUnreachableCode
|
||||
return Sign::ZERO;
|
||||
}
|
||||
|
||||
Math::Rotation Math::operator ""_deg(long double rads) { return {Functions::Radians((float)rads)}; }
|
||||
enum Sign SignOfTan(float radians) {
|
||||
enum Quadrant q = QuadrantOf(radians);
|
||||
if (q == Quadrant::I || q == Quadrant::III)
|
||||
return Sign::POSITIVE;
|
||||
|
||||
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
|
||||
// ReSharper disable once CppDFAConstantConditions
|
||||
if (q == Quadrant::II || q == Quadrant::IV)
|
||||
return Sign::NEGATIVE;
|
||||
|
||||
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
|
||||
// ReSharper disable once CppDFAUnreachableCode
|
||||
return Sign::ZERO;
|
||||
}
|
||||
|
||||
Quadrant QuadrantOf(float radians) {
|
||||
if (radians > ThreePiOverTwo) {
|
||||
return Quadrant::IV;
|
||||
} else if (radians >= Pi) {
|
||||
return Quadrant::III;
|
||||
} else if (radians >= PiOverTwo) {
|
||||
return Quadrant::II;
|
||||
} else {
|
||||
return Quadrant::I;;
|
||||
}
|
||||
}
|
||||
|
||||
float Radians(float degrees) { return degrees * (Pi/180.f); }
|
||||
|
||||
float Degrees(float radians) { return radians * (180.f/Pi); }
|
||||
|
||||
float Sin(float x) {
|
||||
#ifdef USE_LOOKUP_TABLES
|
||||
#elif USE_SSE
|
||||
#else
|
||||
return std::sin(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
float Cos(float x) {
|
||||
#ifdef USE_LOOKUP_TABLES
|
||||
#elif USE_SSE
|
||||
#else
|
||||
return std::cos(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
float Tan(float x) { return std::tan(x); }
|
||||
|
||||
void SinCos(float x, float &outSin, float &outCos) {
|
||||
outSin = Sin(x);
|
||||
outCos = Cos(x);
|
||||
}
|
||||
|
||||
float Asin(float x) { return std::asin(x); }
|
||||
|
||||
float Acos(float x) { return std::acos(x); }
|
||||
|
||||
float Atan(float x) { return std::atan(x); }
|
||||
|
||||
float Atan2(float y, float x) { return std::atan2(y, x); }
|
||||
|
||||
float Sinh(float x) { return std::sinh(x); }
|
||||
|
||||
float Cosh(float x) { return std::cosh(x); }
|
||||
|
||||
float Tanh(float x) { return std::tanh(x); }
|
||||
|
||||
}
|
||||
|
||||
namespace J3ML::Math::Functions { }
|
||||
|
||||
namespace J3ML {
|
||||
|
||||
float Math::Functions::FastRSqrt(float x) {
|
||||
return 1.f / FastSqrt(x);
|
||||
@@ -77,9 +158,6 @@ namespace J3ML
|
||||
return 1.f / Sqrt(x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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};
|
||||
@@ -149,6 +227,20 @@ namespace J3ML
|
||||
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::LerpMod(float a, float b, float mod, float t) {
|
||||
@@ -207,60 +299,9 @@ namespace J3ML
|
||||
|
||||
|
||||
|
||||
Math::Rotation::Rotation() : valueInRadians(0) {}
|
||||
|
||||
Math::Rotation::Rotation(float value) : valueInRadians(value) {}
|
||||
|
||||
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) {
|
||||
return {valueInRadians + rhs.valueInRadians};
|
||||
}
|
||||
|
||||
float Math::Interp::SmoothStart(float t) {
|
||||
assert(t >= 0.f && t <= 1.f);
|
||||
return t*t;
|
||||
}
|
||||
|
||||
int Math::BitTwiddling::CountBitsSet(u32 value) {
|
||||
|
||||
}
|
||||
// int BitTwiddling::CountBitsSet(u32 value) { }
|
||||
|
||||
namespace Math::Functions {
|
||||
float Sin(float x) {
|
||||
#ifdef USE_LOOKUP_TABLES
|
||||
#elif USE_SSE
|
||||
#else
|
||||
return std::sin(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
float Cos(float x) {
|
||||
#ifdef USE_LOOKUP_TABLES
|
||||
#elif USE_SSE
|
||||
#else
|
||||
return std::cos(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
float Tan(float x) { return std::tan(x); }
|
||||
|
||||
void SinCos(float x, float &outSin, float &outCos) {
|
||||
outSin = Sin(x);
|
||||
outCos = Cos(x);
|
||||
}
|
||||
|
||||
float Asin(float x) { return std::asin(x); }
|
||||
|
||||
float Acos(float x) { return std::acos(x); }
|
||||
|
||||
float Atan(float x) { return std::atan(x); }
|
||||
|
||||
float Atan2(float y, float x) { return std::atan2(y, x); }
|
||||
|
||||
float Sinh(float x) { return std::sinh(x); }
|
||||
|
||||
float Cosh(float x) { return std::cosh(x); }
|
||||
|
||||
float Tanh(float x) { return std::tanh(x); }
|
||||
|
||||
bool IsPow2(u32 number) {
|
||||
return (number & (number - 1)) == 0;
|
||||
@@ -311,3 +352,10 @@ namespace J3ML
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace J3ML::Math::Functions::Interpolation {
|
||||
float SmoothStart(float t) {
|
||||
assert(t >= 0.f && t <= 1.f);
|
||||
return t*t;
|
||||
}
|
||||
}
|
||||
|
@@ -1,61 +1,82 @@
|
||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
AxisAngle::AxisAngle() : axis(Vector3::Zero) {}
|
||||
|
||||
AxisAngle::AxisAngle(const Vector3 &axis, float angle) : axis(axis), angle(angle) {}
|
||||
AxisAngle::AxisAngle(const Vector3& axis, float angle) : axis(axis), angle(angle) {}
|
||||
|
||||
Quaternion AxisAngle::ToQuaternion() const {
|
||||
return {
|
||||
axis.x * std::sin(angle/2),
|
||||
axis.y * std::sin(angle/2),
|
||||
axis.z * std::sin(angle/2),
|
||||
std::cos(angle/2)
|
||||
};
|
||||
|
||||
AxisAngle::AxisAngle(const Quaternion& rhs) {
|
||||
float halfAngle = std::acos(rhs.w);
|
||||
angle = halfAngle * 2.f;
|
||||
float reciprocalSinAngle = 1.f / std::sqrt(1.f - rhs.w*rhs.w);
|
||||
|
||||
axis = { rhs.x*reciprocalSinAngle, rhs.y*reciprocalSinAngle, rhs.z*reciprocalSinAngle };
|
||||
}
|
||||
|
||||
AxisAngle::AxisAngle(const Quaternion &q) {
|
||||
auto theta = std::acos(q.w) * 2.f;
|
||||
auto ax = q.x / std::sin(std::acos(theta));
|
||||
auto ay = q.y / std::sin(std::acos(theta));
|
||||
auto az = q.z / std::sin(std::acos(theta));
|
||||
|
||||
Quaternion AxisAngle::ToQuaternion() const { return Quaternion(*this); }
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
AxisAngle::AxisAngle(const EulerAngle &e) {
|
||||
Matrix3x3 AxisAngle::ToMatrix3x3() const {
|
||||
return Matrix3x3(*this);
|
||||
}
|
||||
|
||||
// Assuming the angles are in radians
|
||||
void AxisAngle::Inverse() {
|
||||
angle = -angle;
|
||||
}
|
||||
|
||||
float heading = e.pitch;
|
||||
float attitude = e.yaw;
|
||||
float bank = e.roll;
|
||||
AxisAngle AxisAngle::Inverted() const {
|
||||
return {axis, -angle};
|
||||
}
|
||||
|
||||
float c1 = std::cos(heading / 2.f);
|
||||
float s1 = std::sin(heading / 2.f);
|
||||
float c2 = std::cos(attitude / 2.f);
|
||||
float s2 = std::sin(attitude / 2.f);
|
||||
float c3 = std::cos(bank / 2.f);
|
||||
float s3 = std::sin(bank / 2.f);
|
||||
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};
|
||||
}
|
||||
|
||||
float w = c1*c2*c3 - s1*s2*s3;
|
||||
float x = c1*c2*c3 + s1*s2*s3;
|
||||
float y = s1*c2*c3 + c1*s2*s3;
|
||||
float z = c1*s2*c3 - s1*c2*s3;
|
||||
AxisAngle AxisAngle::Slerp(const AxisAngle &rhs, float t) {
|
||||
Quaternion a(*this);
|
||||
Quaternion b(rhs);
|
||||
|
||||
angle = 2.f * std::acos(w);
|
||||
Quaternion intermediate = a.Slerp(b, t);
|
||||
|
||||
double norm = x*x + y*y + z*z;
|
||||
if (norm < 0.001) { // when all euler angles are zero angle=0, so
|
||||
// we can set axis to anything to avoid divide by zero
|
||||
x = 1;
|
||||
y = z = 0;
|
||||
} else {
|
||||
norm = std::sqrt(norm);
|
||||
x /= norm;
|
||||
y /= norm;
|
||||
z /= norm;
|
||||
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;
|
||||
}
|
||||
|
||||
axis = {x, y, z};
|
||||
}
|
||||
|
||||
Vector3 AxisAngle::Axis() const { return axis;}
|
||||
|
||||
float AxisAngle::Angle() const { return angle;}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
#include <J3ML/LinearAlgebra/CoordinateFrame.hpp>
|
@@ -1,147 +0,0 @@
|
||||
#include <J3ML/LinearAlgebra/EulerAngle.hpp>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
EulerAngle::EulerAngle(float pitch, float yaw, float roll): pitch(pitch), yaw(yaw), roll(roll)
|
||||
{}
|
||||
|
||||
float EulerAngle::GetPitch(float pitch_limit) const
|
||||
{ return std::clamp( std::remainderf(pitch,360.f), -pitch_limit, pitch_limit); }
|
||||
|
||||
float EulerAngle::GetYaw(float yaw_limit) const
|
||||
{ return std::clamp(std::remainderf(yaw, 360.f), -yaw_limit, yaw_limit); }
|
||||
|
||||
float EulerAngle::GetRoll(float pitch_limit) const
|
||||
{ return std::clamp( std::remainderf(pitch,360.f), -pitch_limit, pitch_limit); }
|
||||
|
||||
bool EulerAngle::operator==(const EulerAngle& a) const
|
||||
{
|
||||
return (pitch == a.pitch) && (yaw == a.yaw) && (roll == a.roll);
|
||||
}
|
||||
|
||||
void EulerAngle::clamp()
|
||||
{
|
||||
if (this->pitch > 89.0f)
|
||||
this->pitch = 89.0f;
|
||||
if (this->pitch <= -89.0f)
|
||||
this->pitch = -89.0f;
|
||||
//TODO: Make this entirely seamless by getting the amount they rotated passed -180 and +180 by.
|
||||
if (this->yaw <= -180.0f)
|
||||
this->yaw = 180.0f;
|
||||
if (this->yaw >= 180.01f)
|
||||
this->yaw = -179.9f;
|
||||
if (this->roll >= 360.0f)
|
||||
this->roll = 0.0;
|
||||
if (this->roll <= -360.0f)
|
||||
this->roll = 0.0;
|
||||
}
|
||||
|
||||
EulerAngle EulerAngle::movementAngle() const
|
||||
{
|
||||
EulerAngle a;
|
||||
a.pitch = (cos(Math::Radians(yaw)) * cos(Math::Radians(pitch)));
|
||||
a.yaw = -sin(Math::Radians(pitch));
|
||||
a.roll = (sin(Math::Radians(yaw)) * cos(Math::Radians(pitch)));
|
||||
return a;
|
||||
}
|
||||
|
||||
EulerAngle::EulerAngle() : pitch(0), yaw(0), roll(0) {}
|
||||
|
||||
EulerAngle::EulerAngle(const AxisAngle &rhs) {
|
||||
|
||||
float x = rhs.axis.x;
|
||||
float y = rhs.axis.y;
|
||||
float z = rhs.axis.z;
|
||||
float angle = rhs.angle;
|
||||
|
||||
double s = std::sin(rhs.angle);
|
||||
|
||||
double c = std::cos(rhs.angle);
|
||||
|
||||
double t = 1-c;
|
||||
|
||||
// if axis is not already normalized then uncomment this
|
||||
|
||||
// double magnitude = std::sqrt(x*x + y*y + z*z);
|
||||
// if (magnitude == 0) throw error;
|
||||
// x /= magnitude;
|
||||
// y /= magnitude;
|
||||
// z /= magnitude;
|
||||
|
||||
if ((x*y*t + z*s) > 0.998) { // North pole singularity detected
|
||||
pitch = 2 * std::atan2(x * std::sin(angle/2.f), std::cos(angle/2.f));
|
||||
yaw = Math::Pi / 2.f;
|
||||
roll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((x*y*t + z*s) < -0.998) { // South pole singularity detected
|
||||
pitch = -2 * std::atan2(x * std::sin(angle/2.f), std::cos(angle/2.f));
|
||||
yaw = -Math::Pi / 2.f;
|
||||
roll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
pitch = std::atan2(y * s-x * z * t, 1 - (y*y + z*z) * t);
|
||||
yaw = std::asin(x * y * t + z * s);
|
||||
roll = std::atan2(x * s - y * z * t, 1 - (x*x + z*z) * t);
|
||||
}
|
||||
|
||||
AxisAngle EulerAngle::ToAxisAngle() const {
|
||||
auto c1 = std::cos(yaw / 2);
|
||||
auto c2 = std::cos(pitch / 2);
|
||||
auto c3 = std::cos(roll / 2);
|
||||
auto s1 = std::sin(yaw / 2);
|
||||
auto s2 = std::sin(pitch / 2);
|
||||
auto s3 = std::sin(roll / 2);
|
||||
|
||||
auto angle = 2 * std::acos(c1*c2*c3 - s1*s2*s3);
|
||||
|
||||
auto x = s1*s2*c3 + c1*c2*s3;
|
||||
auto y = s1*c2*c3 + c1*s2*s3;
|
||||
auto z = c1*s2*c3 - s1*c2*s3;
|
||||
|
||||
// todo: normalize?
|
||||
// sqrt(x^2 + y^2 + z^2) = sqrt((s1 s2 c3 +c1 c2 s3)^2+(s1 c2 c3 + c1 s2 s3)^2+(c1 s2 c3 - s1 c2 s3)^2)
|
||||
|
||||
return {{x,y,z}, angle};
|
||||
}
|
||||
|
||||
Quaternion EulerAngle::ToQuaternion() const {
|
||||
auto c1 = std::cos(yaw / 2);
|
||||
auto c2 = std::cos(pitch / 2);
|
||||
auto c3 = std::cos(roll / 2);
|
||||
auto s1 = std::sin(yaw / 2);
|
||||
auto s2 = std::sin(pitch / 2);
|
||||
auto s3 = std::sin(roll / 2);
|
||||
|
||||
auto w = c1*c2*c3 - s1*s2*s3;
|
||||
auto x = s1*s2*c3 + c1*c2*s3;
|
||||
auto y = s1*c2*c3 + c1*s2*s3;
|
||||
auto z = c1*s2*c3 - s1*c2*s3;
|
||||
|
||||
return {w,x,y,z};
|
||||
}
|
||||
|
||||
EulerAngle::EulerAngle(const Quaternion &rhs) {
|
||||
double test = rhs.x * rhs.y + rhs.z * rhs.w;
|
||||
if (test > 0.499) { // Singularity at north pole
|
||||
pitch = 2 * std::atan2(rhs.x, rhs.w);
|
||||
yaw = Math::Pi / 2.f;
|
||||
roll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (test < -0.499) { // Singularity at south pole
|
||||
pitch = -2 * std::atan2(rhs.x, rhs.y);
|
||||
yaw = - Math::Pi / 2.f;
|
||||
roll = 0;
|
||||
return;
|
||||
}
|
||||
float sqx = rhs.x * rhs.x;
|
||||
float sqy = rhs.y * rhs.y;
|
||||
float sqz = rhs.z * rhs.z;
|
||||
}
|
||||
}
|
@@ -109,27 +109,8 @@ namespace J3ML::LinearAlgebra {
|
||||
//this->elems[2][2] = r3.z;
|
||||
}
|
||||
|
||||
Matrix3x3::Matrix3x3(const Quaternion &orientation) {
|
||||
SetRotatePart(orientation);
|
||||
}
|
||||
Matrix3x3::Matrix3x3(const Quaternion& orientation) {
|
||||
|
||||
Matrix3x3::Matrix3x3(const EulerAngle &orientation) {
|
||||
auto sa = std::sin(orientation.pitch);
|
||||
auto ca = std::cos(orientation.pitch);
|
||||
auto sb = std::sin(orientation.roll);
|
||||
auto cb = std::cos(orientation.roll);
|
||||
auto sh = std::sin(orientation.yaw);
|
||||
auto ch = std::cos(orientation.yaw);
|
||||
|
||||
At(0, 0) = ch*ca;
|
||||
At(0, 1) = -ch*sa*cb + sh*sh;
|
||||
At(0, 2) = ch*sa*sb + sh*cb;
|
||||
At(1, 0) = sa;
|
||||
At(1, 1) = ca*cb;
|
||||
At(1, 2) = -ca*cb;
|
||||
At(2, 0) = -sh*ca;
|
||||
At(2, 1) = sh*sa*cb + ch*sb;
|
||||
At(2, 2) = -sh*sa*sb + ch*cb;
|
||||
}
|
||||
|
||||
float Matrix3x3::Determinant() const {
|
||||
@@ -207,7 +188,7 @@ namespace J3ML::LinearAlgebra {
|
||||
};
|
||||
}
|
||||
|
||||
Quaternion Matrix3x3::ToQuat() const {
|
||||
/*Quaternion Matrix3x3::ToQuat() const {
|
||||
auto m00 = At(0,0);
|
||||
auto m01 = At(0, 1);
|
||||
auto m02 = At(0, 2);
|
||||
@@ -226,7 +207,7 @@ namespace J3ML::LinearAlgebra {
|
||||
(m10 - m01) / w4,
|
||||
w
|
||||
};
|
||||
}
|
||||
}*/
|
||||
|
||||
void Matrix3x3::SetRotatePart(const Vector3 &a, float angle) {
|
||||
float s = std::sin(angle);
|
||||
@@ -992,25 +973,12 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
bool Matrix3x3::TryConvertToQuat(Quaternion &q) const {
|
||||
if (IsColOrthogonal() && HasUnitaryScale() && !HasNegativeScale()) {
|
||||
q = ToQuat();
|
||||
q = Quaternion(*this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EulerAngle Matrix3x3::ToEulerAngle() const {
|
||||
auto heading = std::atan2(-At(2, 0), At(0, 0));
|
||||
auto attitude = std::asin(At(1, 0));
|
||||
auto bank = std::atan2(-At(1,2), At(1,1));
|
||||
if (At(1, 0) == 1 || At(1, 0) == -1) // North Pole || South Pole
|
||||
{
|
||||
heading = std::atan2(At(0, 2), At(2,2));
|
||||
bank = 0;
|
||||
}
|
||||
|
||||
return {attitude, heading, bank};
|
||||
}
|
||||
|
||||
void Matrix3x3::BatchTransform(Vector3 *pointArray, int numPoints, int stride) const {
|
||||
assert(pointArray || numPoints == 0);
|
||||
assert(stride >= (int)sizeof(Vector3));
|
||||
@@ -1119,6 +1087,18 @@ namespace J3ML::LinearAlgebra {
|
||||
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/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrices.inl>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
@@ -86,10 +87,6 @@ namespace J3ML::LinearAlgebra {
|
||||
Set3x3Part(Matrix3x3(orientation));
|
||||
}
|
||||
|
||||
Matrix4x4::Matrix4x4(const EulerAngle &orientation) {
|
||||
Set3x3Part(Matrix3x3(orientation));
|
||||
}
|
||||
|
||||
void Matrix4x4::SetTranslatePart(float translateX, float translateY, float translateZ) {
|
||||
elems[0][3] = translateX;
|
||||
elems[1][3] = translateY;
|
||||
@@ -683,6 +680,11 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const Matrix4x4 &rhs) {
|
||||
out << rhs.ToString();
|
||||
return out;
|
||||
}
|
||||
|
||||
void Matrix4x4::InverseOrthonormal()
|
||||
{
|
||||
//assert(!ContainsProjection());
|
||||
@@ -777,19 +779,6 @@ namespace J3ML::LinearAlgebra {
|
||||
};
|
||||
}
|
||||
|
||||
EulerAngle Matrix4x4::ToEulerAngle() const {
|
||||
auto heading = std::atan2(-At(2, 0), At(0, 0));
|
||||
auto attitude = std::asin(At(1, 0));
|
||||
auto bank = std::atan2(-At(1,2), At(1,1));
|
||||
if (At(1, 0) == 1 || At(1, 0) == -1) // North Pole || South Pole
|
||||
{
|
||||
heading = std::atan2(At(0, 2), At(2,2));
|
||||
bank = 0;
|
||||
}
|
||||
|
||||
return {attitude, heading, bank};
|
||||
}
|
||||
|
||||
bool Matrix4x4::InverseOrthogonalUniformScale() {
|
||||
assert(!ContainsProjection());
|
||||
assert(IsColOrthogonal(1e-3f));
|
||||
@@ -1031,6 +1020,46 @@ namespace J3ML::LinearAlgebra {
|
||||
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
|
||||
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) {
|
||||
|
@@ -1,23 +1,81 @@
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/LinearAlgebra/AxisAngle.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector3.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
const Quaternion Quaternion::Identity = Quaternion(0.f, 0.f, 0.f, 1.f);
|
||||
const Quaternion Quaternion::NaN = Quaternion(NAN, NAN, NAN, NAN);
|
||||
|
||||
Quaternion Quaternion::operator-() const
|
||||
{
|
||||
Quaternion Quaternion::operator-() const {
|
||||
return {-x, -y, -z, -w};
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Matrix3x3 &rotationMtrx) {}
|
||||
Quaternion::Quaternion(const Matrix3x3& ro_mat) {
|
||||
// https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||
|
||||
Quaternion::Quaternion(const Matrix4x4 &rotationMtrx) {}
|
||||
auto m = ro_mat;//.Transposed();
|
||||
auto m00 = m.At(0,0);
|
||||
auto m01 = m.At(0, 1);
|
||||
auto m02 = m.At(0, 2);
|
||||
auto m10 = m.At(1, 0);
|
||||
auto m11 = m.At(1, 1);
|
||||
auto m12 = m.At(1, 2);
|
||||
auto m20 = m.At(2, 0);
|
||||
auto m21 = m.At(2, 1);
|
||||
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;
|
||||
float w4 = (4.f * field_w);
|
||||
|
||||
x = (m21 - m12) / w4;
|
||||
y = (m02 - m20) / w4;
|
||||
z = (m10 - m01) / w4;
|
||||
w = field_w;
|
||||
bool success = Normalize();
|
||||
// TODO: Validate normalization success.
|
||||
*/
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Matrix4x4& ro_mat) {
|
||||
auto q = Quaternion(ro_mat.GetRotatePart());
|
||||
x = q.x; y = q.y; z = q.z; w = q.w;
|
||||
}
|
||||
|
||||
Vector3 Quaternion::WorldX() const { return Transform(1.f, 0.f, 0.f); }
|
||||
|
||||
@@ -50,24 +108,8 @@ namespace J3ML::LinearAlgebra {
|
||||
return (*this * (t - 1.f) + b * t).Normalized();
|
||||
}
|
||||
|
||||
void Quaternion::SetFromAxisAngle(const Vector3 &axis, float angle) {
|
||||
float sinz, cosz;
|
||||
sinz = std::sin(angle*0.5f);
|
||||
cosz = std::cos(angle*0.5f);
|
||||
|
||||
x = axis.x * sinz;
|
||||
y = axis.y * sinz;
|
||||
z = axis.z * sinz;
|
||||
w = cosz;
|
||||
}
|
||||
|
||||
void Quaternion::SetFromAxisAngle(const Vector4 &axis, float angle)
|
||||
{
|
||||
SetFromAxisAngle(Vector3(axis.x, axis.y, axis.z), angle);
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -82,11 +124,8 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
Quaternion Quaternion::operator+() const { return *this; }
|
||||
|
||||
Quaternion::Quaternion() {}
|
||||
|
||||
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 {
|
||||
return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w;
|
||||
}
|
||||
@@ -148,20 +187,6 @@ namespace J3ML::LinearAlgebra {
|
||||
return (*this * (a * sign) + q2 * b).Normalized();
|
||||
}
|
||||
|
||||
AxisAngle Quaternion::ToAxisAngle() const {
|
||||
float halfAngle = std::acos(w);
|
||||
float angle = halfAngle * 2.f;
|
||||
// TODO: Can Implement Fast Inverted Sqrt Here
|
||||
float reciprocalSinAngle = 1.f / std::sqrt(1.f - w*w);
|
||||
|
||||
Vector3 axis = {
|
||||
x*reciprocalSinAngle,
|
||||
y*reciprocalSinAngle,
|
||||
z*reciprocalSinAngle
|
||||
};
|
||||
return AxisAngle(axis, angle);
|
||||
}
|
||||
|
||||
float Quaternion::AngleBetween(const Quaternion &target) const {
|
||||
Quaternion delta = target / *this;
|
||||
return delta.Normalized().Angle();
|
||||
@@ -212,47 +237,14 @@ namespace J3ML::LinearAlgebra {
|
||||
return Vector3(x, y, z) * rcpSinAngle;
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Vector3 &rotationAxis, float rotationAngleRadians) {
|
||||
SetFromAxisAngle(rotationAxis, rotationAngleRadians);
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const Vector4 &rotationAxis, float rotationAngleRadians) {
|
||||
SetFromAxisAngle(rotationAxis, rotationAngleRadians);
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const AxisAngle &angle) {
|
||||
double s = std::sin(angle.angle / 2);
|
||||
Quaternion::Quaternion(const AxisAngle& angle) {
|
||||
float s = Math::Sin(angle.angle / 2.f);
|
||||
x = angle.axis.x * s;
|
||||
y = angle.axis.y * s;
|
||||
z = angle.axis.z * s;
|
||||
w = std::cos(angle.angle / 2);
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const EulerAngle &angle) {
|
||||
// Abbreviations for the various angular functions
|
||||
double cr = std::cos(angle.roll * 0.5);
|
||||
double sr = std::sin(angle.roll * 0.5);
|
||||
double cp = std::cos(angle.pitch * 0.5);
|
||||
double sp = std::sin(angle.pitch * 0.5);
|
||||
double cy = std::cos(angle.yaw * 0.5);
|
||||
double sy = std::sin(angle.yaw * 0.5);
|
||||
|
||||
w = cr * cp * cy + sr * sp * sy;
|
||||
x = sr * cp * cy - cr * sp * sy;
|
||||
y = cr * sp * cy + sr * cp * sy;
|
||||
z = cr * cp * sy - sr * sp * cy;
|
||||
}
|
||||
|
||||
void Quaternion::SetFrom(const AxisAngle &angle) {
|
||||
double s = std::sin(angle.angle / 2);
|
||||
x = angle.axis.x * s;
|
||||
y = angle.axis.y * s;
|
||||
z = angle.axis.z * s;
|
||||
w = std::cos(angle.angle / 2);
|
||||
}
|
||||
|
||||
EulerAngle Quaternion::ToEulerAngle() const {
|
||||
return EulerAngle(*this);
|
||||
w = Math::Cos(angle.angle / 2);
|
||||
bool success = Normalize();
|
||||
// TODO: Validate normalization success.
|
||||
}
|
||||
|
||||
Quaternion Quaternion::RandomRotation(RNG &rng) {
|
||||
@@ -271,16 +263,16 @@ namespace J3ML::LinearAlgebra {
|
||||
return Quaternion::Identity;
|
||||
}
|
||||
|
||||
float Quaternion::Normalize() {
|
||||
bool Quaternion::Normalize() {
|
||||
float length = Length();
|
||||
if (length < 1e-4f)
|
||||
return 0.f;
|
||||
return false;
|
||||
float rcpLength = 1.f / length;
|
||||
x *= rcpLength;
|
||||
y *= rcpLength;
|
||||
z *= rcpLength;
|
||||
w *= rcpLength;
|
||||
return length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Quaternion::IsNormalized(float epsilon) const {
|
||||
@@ -325,9 +317,10 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
Quaternion Quaternion::LookAt(const Vector3 &localForward, const Vector3 &targetDirection, const Vector3 &localUp,
|
||||
const Vector3 &worldUp) {
|
||||
return Matrix3x3::LookAt(localForward, targetDirection, localUp, worldUp).ToQuat();
|
||||
return Quaternion(Matrix3x3::LookAt(localForward, targetDirection, localUp, worldUp));
|
||||
}
|
||||
|
||||
/*
|
||||
Quaternion Quaternion::RotateX(float angleRadians) {
|
||||
return {{1,0,0}, angleRadians};
|
||||
}
|
||||
@@ -343,6 +336,7 @@ namespace J3ML::LinearAlgebra {
|
||||
Quaternion Quaternion::RotateAxisAngle(const AxisAngle &axisAngle) {
|
||||
return {axisAngle.axis, axisAngle.angle};
|
||||
}
|
||||
*/
|
||||
|
||||
Quaternion Quaternion::RotateFromTo(const Vector3 &sourceDirection, const Vector3 &targetDirection) {
|
||||
assert(sourceDirection.IsNormalized());
|
||||
@@ -369,14 +363,6 @@ namespace J3ML::LinearAlgebra {
|
||||
return Quaternion::RotateFromTo(sourceDirection.XYZ(), targetDirection.XYZ());
|
||||
}
|
||||
|
||||
Quaternion::Quaternion(const float *data) {
|
||||
assert(data);
|
||||
x = data[0];
|
||||
y = data[1];
|
||||
z = data[2];
|
||||
w = data[3];
|
||||
}
|
||||
|
||||
Quaternion Quaternion::Lerp(const Quaternion &source, const Quaternion &target, float t) { return source.Lerp(target, t);}
|
||||
|
||||
Quaternion Quaternion::Slerp(const Quaternion &source, const Quaternion &target, float t) { return source.Slerp(target, t);}
|
||||
@@ -401,4 +387,30 @@ namespace J3ML::LinearAlgebra {
|
||||
float Quaternion::LengthSquared() const { return x*x + y*y + z*z + w*w;}
|
||||
|
||||
float Quaternion::Length() const { return std::sqrt(LengthSquared()); }
|
||||
|
||||
Quaternion::Quaternion(const Quaternion& rhs) {
|
||||
x = rhs.x;
|
||||
y = rhs.y;
|
||||
z = rhs.z;
|
||||
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 {
|
||||
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)}; }
|
||||
}
|
@@ -7,6 +7,7 @@
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
@@ -36,12 +37,12 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
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
|
||||
{
|
||||
return this->IsWithinMarginOfError(rhs) == false;
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
Vector2 Vector2::Min(const Vector2& min) const
|
||||
@@ -499,6 +500,33 @@ namespace J3ML::LinearAlgebra {
|
||||
return std::format("{},{}", x, y);
|
||||
}
|
||||
|
||||
bool Vector2::operator>(const Vector2 &rhs) const {
|
||||
return this->Magnitude() > rhs.Magnitude();
|
||||
}
|
||||
|
||||
bool Vector2::operator<(const Vector2 &rhs) const {
|
||||
return this->Magnitude() < rhs.Magnitude();
|
||||
}
|
||||
|
||||
Vector2::Vector2(const Vector2i& rhs) {
|
||||
x = rhs.x;
|
||||
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) {
|
||||
return {lhs * rhs.x, lhs * rhs.y};
|
||||
}
|
||||
|
79
src/J3ML/LinearAlgebra/Vector2i.cpp
Normal file
79
src/J3ML/LinearAlgebra/Vector2i.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2i.hpp>
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i &J3ML::LinearAlgebra::Vector2i::operator =(const Vector2i& rhs) {
|
||||
x = rhs.x;
|
||||
y = rhs.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool J3ML::LinearAlgebra::Vector2i::operator ==(const Vector2i& rhs) const {
|
||||
return (x == rhs.x && y == rhs.y);
|
||||
}
|
||||
|
||||
bool J3ML::LinearAlgebra::Vector2i::operator !=(const Vector2i& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i& J3ML::LinearAlgebra::Vector2i::operator +=(const Vector2i& rhs) {
|
||||
x += rhs.x;
|
||||
y += rhs.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i& J3ML::LinearAlgebra::Vector2i::operator -=(const Vector2i& rhs) {
|
||||
x -= rhs.x;
|
||||
y -= rhs.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i& J3ML::LinearAlgebra::Vector2i::operator *=(const Vector2i& rhs) {
|
||||
x *= rhs.x;
|
||||
y *=rhs.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i& J3ML::LinearAlgebra::Vector2i::operator /=(const Vector2i& rhs) {
|
||||
x /= rhs.x;
|
||||
y /=rhs.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator +(const Vector2i& rhs) const {
|
||||
return {x + rhs.x, y + rhs.y};
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator -(const Vector2i& rhs) const {
|
||||
return {x - rhs.x, y - rhs.y};
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator *(const Vector2i& rhs) const {
|
||||
return {x * rhs.x, y * rhs.y};
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator /(const Vector2i& rhs) const {
|
||||
return {x / rhs.x, y / rhs.y};
|
||||
}
|
||||
|
||||
std::string J3ML::LinearAlgebra::Vector2i::ToString() const {
|
||||
return std::string(std::to_string(x) + " " + std::to_string(y));
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i::Vector2i() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator *(const int rhs) const {
|
||||
return {x * rhs, y * rhs};
|
||||
}
|
||||
|
||||
J3ML::LinearAlgebra::Vector2i J3ML::LinearAlgebra::Vector2i::operator/(int rhs) const {
|
||||
return {x / rhs, y / rhs};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
const Vector3 Vector3::Zero = {0,0,0};
|
||||
const Vector3 Vector3::One = {1, 1, 1};
|
||||
const Vector3 Vector3::Up = {0, -1, 0};
|
||||
const Vector3 Vector3::Down = {0, 1, 0};
|
||||
const Vector3 Vector3::Left = {-1, 0, 0};
|
||||
|
@@ -331,5 +331,63 @@ Vector4 Vector4::operator-(const Vector4& rhs) const
|
||||
}
|
||||
|
||||
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
|
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
|
||||
jtest::check(Intersects(xyTriangle, zxTriangle));
|
||||
//jtest::check(Intersects(xyTriangle, zxTriangle));
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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(
|
||||
{0.0f, 0.0f, 0.0f},
|
||||
@@ -74,11 +74,11 @@ namespace TriangleTests {
|
||||
);
|
||||
|
||||
// Should collide on V0-V1 edge
|
||||
jtest::check(Intersects(yxTriangle, yxTriangle));
|
||||
//jtest::check(Intersects(yxTriangle, yxTriangle));
|
||||
// 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
|
||||
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(
|
||||
{0.0f, 1.0f, -1.0f},
|
||||
@@ -86,11 +86,11 @@ namespace TriangleTests {
|
||||
{0.0f, 1.0f, 1.0f}
|
||||
);
|
||||
// Should collide exactly on V1
|
||||
jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
||||
//jtest::check(Intersects(xyTriangle, zyInvertedTriangle));
|
||||
// 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
|
||||
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))));
|
||||
});
|
||||
}
|
||||
|
||||
|
46
tests/LinearAlgebra/AxisAngleTests.hpp
Normal file
46
tests/LinearAlgebra/AxisAngleTests.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
jtest::Unit AxisAngleUnit {"AxisAngle"};
|
||||
|
||||
namespace AxisAngleTests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
|
||||
AxisAngleUnit += Test("CtorFromQuaternion", [] {
|
||||
AxisAngle expected_result({0.3860166, 0.4380138, 0.8118714}, 0.6742209);
|
||||
Quaternion q(0.1276794, 0.1448781, 0.2685358, 0.9437144);
|
||||
|
||||
AxisAngle from_quaternion(q);
|
||||
|
||||
jtest::check(expected_result.Equals(from_quaternion));
|
||||
|
||||
});
|
||||
|
||||
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() {
|
||||
AxisAngleUnit.RunAll();
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// Created by josh on 12/26/2023.
|
||||
//
|
||||
|
||||
#include <jtest/jtest.hpp>
|
||||
#include <jtest/Unit.hpp>
|
||||
|
||||
jtest::Unit EulerAngleUnit {"EulerAngle"};
|
||||
|
||||
namespace EulerAngleTests {
|
||||
inline void Define() {
|
||||
using namespace jtest;
|
||||
|
||||
EulerAngleUnit += Test("Not Implemented", [] {
|
||||
throw("Not Implemented");
|
||||
});
|
||||
}
|
||||
inline void Run() {
|
||||
EulerAngleUnit.RunAll();
|
||||
}
|
||||
}
|
@@ -11,6 +11,42 @@ namespace Matrix3x3Tests
|
||||
using namespace jtest;
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
/*Matrix3x3Unit += Test("AngleTypeRound-TripConversion", [] {
|
||||
EulerAngleXYZ expected_result(8, 60, -27);
|
||||
|
||||
Matrix3x3 m(expected_result);
|
||||
AxisAngle a(expected_result);
|
||||
Quaternion q(a);
|
||||
Matrix3x3 m2(q);
|
||||
Quaternion q2(m2);
|
||||
AxisAngle a2(q2);
|
||||
EulerAngleXYZ round_trip(a2);
|
||||
|
||||
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.yaw), Math::Radians(round_trip.yaw), 1e-6f));
|
||||
});*/
|
||||
|
||||
/*Matrix3x3Unit += Test("From_EulerAngleXYZ", []{
|
||||
Matrix3x3 expected_result(Vector3(0.4455033, 0.2269952, 0.8660254),
|
||||
Vector3(-0.3421816, 0.9370536, -0.0695866),
|
||||
Vector3(-0.8273081, -0.2653369, 0.4951340)
|
||||
);
|
||||
|
||||
EulerAngleXYZ e(8, 60, -27);
|
||||
Matrix3x3 from_euler(e);
|
||||
|
||||
jtest::check(Math::EqualAbs(expected_result.At(0, 0), from_euler.At(0, 0), 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.At(0, 1), from_euler.At(0, 1), 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.At(0, 2), from_euler.At(0, 2), 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.At(1, 0), from_euler.At(1, 0), 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.At(1, 1), from_euler.At(1, 1), 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.At(1, 2), from_euler.At(1, 2), 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, 2), from_euler.At(2, 2), 1e-6f));
|
||||
});*/
|
||||
|
||||
Matrix3x3Unit += Test("Add_Unary", []
|
||||
{
|
||||
Matrix3x3 m(1,2,3, 4,5,6, 7,8,9);
|
||||
|
@@ -11,8 +11,7 @@ namespace Matrix4x4Tests {
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
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 m2 = +m;
|
||||
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", []{
|
||||
RNG rng;
|
||||
Matrix3x3 m = Matrix3x3::RandomGeneral(rng, -10.f, 10.f);
|
||||
@@ -46,16 +52,16 @@ namespace Matrix4x4Tests {
|
||||
|
||||
for (int y = 0; y < 3; ++y)
|
||||
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[2][3], 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][2], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][3], 0.f));
|
||||
jtest::check(Math::EqualAbs(m2[3][3], 0.f));*/
|
||||
});
|
||||
|
||||
Matrix4x4Unit += Test("SetRow", []
|
||||
@@ -104,27 +110,52 @@ namespace Matrix4x4Tests {
|
||||
});
|
||||
|
||||
|
||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {});
|
||||
Matrix4x4Unit += Test("Translate", [] {});
|
||||
Matrix4x4Unit += Test("Scale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthogonalUniformScale", [] {});
|
||||
Matrix4x4Unit += Test("InverseOrthonormal", [] {});
|
||||
Matrix4x4Unit += Test("DeterminantCorrectness", [] { });
|
||||
Matrix4x4Unit += Test("MulMat3x3", [] {});
|
||||
Matrix4x4Unit += Test("CtorFromQuatTrans", [] {
|
||||
RNG rng;
|
||||
constexpr float SCALE = 1e2f;
|
||||
Vector3 t = Vector3::RandomBox(rng, Vector3(-SCALE, -SCALE, -SCALE), Vector3(SCALE, SCALE, SCALE));
|
||||
Quaternion q = Quaternion::RandomRotation(rng);
|
||||
|
||||
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("AngleTypeRoundtripConversion", [] {
|
||||
Matrix4x4 matrix;
|
||||
EulerAngle a(Math::Radians(45), Math::Radians(45), Math::Radians(45));
|
||||
Quaternion q(a);
|
||||
matrix.SetRotatePart(q);
|
||||
//matrix.SetRotatePartX(a.pitch);
|
||||
//matrix.SetRotatePartY(a.yaw);
|
||||
//matrix.SetRotatePartZ(a.roll);
|
||||
EulerAngle fromMatrix = matrix.GetRotatePart().ToQuat().ToEulerAngle();
|
||||
jtest::check(a == fromMatrix);
|
||||
});
|
||||
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() {
|
||||
|
@@ -5,9 +5,13 @@
|
||||
#include <jtest/Unit.hpp>
|
||||
#include <J3ML/LinearAlgebra/Quaternion.hpp>
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
#include <J3ML/Math.hpp>
|
||||
|
||||
jtest::Unit QuaternionUnit {"Quaternion"};
|
||||
namespace QuaternionTests {
|
||||
|
||||
// This is here to check the accuracy of the Slerp inside the Quaternion class.
|
||||
// Although you don't jtest::check anything :shrug: - Redacted.
|
||||
Quaternion PreciseSlerp(const Quaternion &a, const Quaternion& b, float t)
|
||||
{
|
||||
double angle = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
@@ -69,13 +73,65 @@ namespace QuaternionTests {
|
||||
Quaternion lerp = q.Lerp(q2, t);
|
||||
}
|
||||
});
|
||||
QuaternionUnit += Test("Mat4x4Conversion", [] { throw("Not Implemented"); });
|
||||
QuaternionUnit += Test("MulOpQuat", [] { throw("Not Implemented"); });
|
||||
|
||||
QuaternionUnit += Test("Constants", [] {
|
||||
Quaternion id {0.f, 0.f, 0.f, 1.f};
|
||||
|
||||
jtest::check(id.Equals(Quaternion::Identity));
|
||||
});
|
||||
|
||||
QuaternionUnit += Test("From_AxisAngle", [] {
|
||||
Quaternion expected_result(0.0579133, 0.0782044, 0.1765667, 0.9794664);
|
||||
AxisAngle a({0.2872573, 0.3879036, 0.8757934}, 0.4059981);
|
||||
Quaternion from_axis(a);
|
||||
|
||||
jtest::check(Math::EqualAbs(expected_result.x, from_axis.x, 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.y, from_axis.y, 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.z, from_axis.z, 1e-6f));
|
||||
jtest::check(Math::EqualAbs(expected_result.w, from_axis.w, 1e-6f));
|
||||
});
|
||||
|
||||
QuaternionUnit += Test("Ctor_FromMatrix3x3", [] {
|
||||
// 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("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("Transform", [] { throw("Not Implemented"); });
|
||||
|
||||
}
|
||||
|
||||
inline void Run()
|
||||
|
@@ -35,7 +35,7 @@ namespace Vector4Tests
|
||||
jtest::check_float_eq(Input.w, 1);
|
||||
});
|
||||
|
||||
Vector4Unit += Test("Vector4::Addition_Op", [] {
|
||||
Vector4Unit += Test("Addition_Op", [] {
|
||||
Vector4 A (1, 1, 1, 1);
|
||||
Vector4 B (2, 2, 2, 2);
|
||||
|
||||
@@ -43,6 +43,19 @@ namespace Vector4Tests
|
||||
|
||||
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()
|
||||
|
@@ -15,7 +15,7 @@
|
||||
#include "Geometry/AABBTests.hpp"
|
||||
#include "Geometry/FrustumTests.hpp"
|
||||
|
||||
#include "LinearAlgebra/EulerAngleTests.hpp"
|
||||
#include "LinearAlgebra/AxisAngleTests.hpp"
|
||||
#include "LinearAlgebra/Matrix2x2Tests.hpp"
|
||||
#include "LinearAlgebra/Matrix3x3Tests.hpp"
|
||||
#include "LinearAlgebra/Matrix4x4Tests.hpp"
|
||||
@@ -64,10 +64,10 @@ namespace LinearAlgebraTests
|
||||
{
|
||||
void Define()
|
||||
{
|
||||
EulerAngleTests::Define();
|
||||
Vector2Tests::Define();
|
||||
Vector3Tests::Define();
|
||||
Vector4Tests::Define();
|
||||
AxisAngleTests::Define();
|
||||
QuaternionTests::Define();
|
||||
Matrix2x2Tests::Define();
|
||||
Matrix3x3Tests::Define();
|
||||
@@ -76,10 +76,10 @@ namespace LinearAlgebraTests
|
||||
}
|
||||
void Run()
|
||||
{
|
||||
EulerAngleTests::Run();
|
||||
Vector2Tests::Run();
|
||||
Vector3Tests::Run();
|
||||
Vector4Tests::Run();
|
||||
AxisAngleTests::Run();
|
||||
QuaternionTests::Run();
|
||||
Matrix2x2Tests::Run();
|
||||
Matrix3x3Tests::Run();
|
||||
|
Reference in New Issue
Block a user