Compare commits

...

15 Commits

57 changed files with 1515 additions and 329 deletions

View File

@@ -57,7 +57,13 @@ add_library(J3ML SHARED ${J3ML_SRC}
include/J3ML/Geometry/AABB2D.h
src/J3ML/Geometry/Polygon.cpp
include/J3ML/Geometry/Polyhedron.h
src/J3ML/Geometry/Polyhedron.cpp)
src/J3ML/Geometry/Polyhedron.cpp
include/J3ML/Algorithm/RNG.h
src/J3ML/Algorithm/RNG.cpp
include/J3ML/Algorithm/Spring.h
include/J3ML/Algorithm/DifferentialSolvers.h
include/J3ML/Units.h
src/J3ML/J3ML.cpp)
set_target_properties(J3ML PROPERTIES LINKER_LANGUAGE CXX)
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

View File

@@ -0,0 +1,42 @@
//
// Created by dawsh on 2/8/24.
//
namespace J3ML::Algorithm
{
/// Implementations for a variety of Differential Equation Solving algorithms
namespace Solvers
{
// Consider a differential equation
// dy/dx = (x + y + xy)
float eq(float x, float y)
{
return (x + y + x*y);
}
// Accelleration = Velocity / Time
// Velocity = Position / Time
// Position = Vector3
//
float euler(float x0, float y, float h, float x)
{
float temp = -0.f;
// Iterating till the point at which we need approximation
while (x0 < x) {
temp = y;
y = y + h * eq(x0, y);
x0 = x0 + h;
}
return y;
}
class EulerMethodSolver {};
class SemiImplicitEulerMethodSolver {};
class GaussSeidelMethodSolver {};
class GradientDescentSolver {};
class VerletIntegrationSolver {};
}
}

View File

@@ -0,0 +1,99 @@
#pragma once
#include "J3ML/J3ML.h"
namespace J3ML::Algorithm
{
/** @brief A linear congruential random number generator.
Uses D.H. Lehmer's Linear Congruential Method (1949) for generating random numbers.
Supports both Multiplicative Congruential Method (increment==0) and
Mixed Congruential Method (increment!=0)
It is perhaps the simplest and fastest method to generate pseudo-random numbers on
a computer. Per default uses the values for Minimal Standard LCG.
http://en.wikipedia.org/wiki/Linear_congruential_generator
http://www.math.rutgers.edu/~greenfie/currentcourses/sem090/pdfstuff/jp.pdf
Pros:
<ul>
<li> Easy to implement.
<li> Fast.
</ul>
Cons:
<ul>
<li> NOT safe for cryptography because of the easily calculatable sequential
correlation between successive calls. A case study:
http://www.cigital.com/papers/download/developer_gambling.php
<li> Tends to have less random low-order bits (compared to the high-order bits)
Thus, NEVER do something like this:
u32 numBetween1And10 = 1 + LCGRand.Int() % 10;
Instead, take into account EVERY bit of the generated number, like this:
u32 numBetween1And10 = 1 + (int)(10.0 * (double)LCGRand.Int()
/(LCGRand.Max()+1.0));
or simply
u32 numBetween1And10 = LCGRand.Float(1.f, 10.f);
</ul> */
class RNG {
public:
/// Initializes the generator from the current system clock.
RNG();
RNG(u32 seed, u32 multiplier = 69621,
u32 increment = 0, u32 modulus = 0x7FFFFFFF) // 2^31 - 1
{
Seed(seed, multiplier, increment, modulus);
}
/// Reinitializes the generator to the new settings.
void Seed(u32 seed, u32 multiplier, u32 increment, u32 modulus = 0x7FFFFFFF);
/// Returns a random integer picked uniformly in the range [0, MaxInt()]
u32 Int();
/// Returns the biggest number the generator can yield. [modulus - 1]
u32 MaxInt() const { return modulus - 1;}
/// Returns a random integer picked uniformly in the range [0, 2^32-1].
/// @note The configurable modulus and increment are not used by this function, but are always increment == 0, modulus=2^32
u32 IntFast();
/// Returns a random integer picked uniformly in the range [a, b]
/// @param a Lower bound, inclusive.
/// @param b Upper bound, inclusive.
/// @return A random integer picked uniformly in the range [a, b]
int Int(int a, int b);
/// Returns a random float picked uniformly in the range [0, 1].
float Float();
/// Returns a random float picked uniformly in the range [0, 1].
/// @note this is much slower than Float()! Prefer that function if possible.
float Float01Incl();
/// Returns a random float picked uniformly in the range ]-1, 1[.
/// @note This function has one more bit of randomness compared to Float(), but has a theoretical bias
/// towards 0.0, since floating point has two representations for 0 (+0, and -0).
float FloatNeg1_1();
/// Returns a random float picked uniformly in the range [a, b[.
/// @param a Lower bound, inclusive.
/// @param b Upper bound, exclusive.
/// @return A random float picked uniformly in the range [a, b[
/// @note This function is slower than RNG::FloatIncl(). If you don't care about the open/closed interval, prefer that function.
float Float(float a, float b);
/// Returns a random float picked uniformly in the range [a, b].
/// @param a Lower bound, inclusive.
/// @param b Upper bound, inclusive.
/// @return A random float picked uniformly in the range [a, b]
float FloatIncl(float a, float b);
u32 multiplier;
u32 increment;
u32 modulus;
u32 lastNumber;
};
}

View File

@@ -0,0 +1,21 @@
//
// Created by dawsh on 2/8/24.
//
namespace J3ML::Algorithm
{
// Numerical model of a "Spring" object
// Simulates any oscillating system i.e. a mass suspended from a spring.
class Spring
{
float Dampening;
float Stiffness;
float Goal;
float RestLength = 1.f;
bool Overdamped() const;
bool Undamped() const;
bool Underdamped() const;
bool CriticallyDamped() const;
};
}

View File

@@ -3,9 +3,9 @@
#pragma once
namespace Geometry {
using Vector2 = LinearAlgebra::Vector2;
using Vector3 = LinearAlgebra::Vector3;
namespace J3ML::Geometry {
using Vector2 = J3ML::LinearAlgebra::Vector2;
using Vector3 = J3ML::LinearAlgebra::Vector3;
class LineSegment2D
{

View File

@@ -2,7 +2,7 @@
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra.h>
#include "J3ML/LinearAlgebra.h"
#include <J3ML/Geometry.h>
#include <J3ML/Geometry/Plane.h>
@@ -22,9 +22,8 @@
namespace Geometry
namespace J3ML::Geometry
{
using namespace LinearAlgebra;
// A 3D axis-aligned bounding box
// This data structure can be used to represent coarse bounds of objects, in situations where detailed triangle-level
@@ -35,89 +34,74 @@ namespace Geometry
// be arbitrarily oriented in the space with respect to each other.
// If you need to represent a box in 3D space with arbitrary orientation, see the class OBB. */
class AABB
{
class AABB {
public:
Vector3 minPoint;
Vector3 maxPoint;
static int NumFaces() { return 6; }
static int NumEdges() { return 12;}
static int NumVertices() { return 8;}
static AABB FromCenterAndSize(const Vector3& center, const Vector3& size)
{
Vector3 halfSize = size * 0.5f;
return {center - halfSize, center + halfSize};
}
float MinX() const { return minPoint.x; }
float MinY() const { return minPoint.y; }
float MinZ() const { return minPoint.z; }
static int NumEdges() { return 12; }
float MaxX() const { return maxPoint.x; }
float MaxY() const { return maxPoint.y; }
float MaxZ() const { return maxPoint.z; }
static int NumVertices() { return 8; }
static AABB FromCenterAndSize(const Vector3 &center, const Vector3 &size);
float MinX() const;
float MinY() const;
float MinZ() const;
float MaxX() const;
float MaxY() const;
float MaxZ() const;
/// Returns the smallest sphere that contains this AABB.
/// This function computes the minimal volume sphere that contains all the points inside this AABB
Sphere MinimalEnclosingSphere() const
{
return Sphere(Centroid(), Size().Length()*0.5f);
}
Sphere MinimalEnclosingSphere() const;
Vector3 HalfSize() const {
return this->Size()/2.f;
}
Vector3 HalfSize() const;
/// Returns the largest sphere that can fit inside this AABB
/// This function computes the largest sphere that can fit inside this AABB.
Sphere MaximalContainedSphere() const;
bool IsFinite() const;
Vector3 Centroid() const;
Vector3 Size() const;
// Returns the largest sphere that can fit inside this AABB
// This function computes the largest sphere that can fit inside this AABB.
Sphere MaximalContainedSphere() const
{
Vector3 halfSize = HalfSize();
return Sphere(Centroid(), std::min(halfSize.x, std::min(halfSize.y, halfSize.z)));
}
bool IsFinite() const
{
return minPoint.IsFinite() && maxPoint.IsFinite();
}
Vector3 Centroid() const
{
return (minPoint+maxPoint) * 0.5f;
}
Vector3 Size() const
{
return this->maxPoint - this->minPoint;
}
// Quickly returns an arbitrary point inside this AABB
Vector3 AnyPointFast() const;
Vector3 PointInside(float x, float y, float z) const
{
Vector3 d = maxPoint - minPoint;
return minPoint + d.Mul({x, y, z});
}
Vector3 PointInside(float x, float y, float z) const;
// Returns an edge of this AABB
LineSegment Edge(int edgeIndex) const
{
switch(edgeIndex)
{
default:
case 0: return LineSegment(minPoint, {minPoint.x, minPoint.y, maxPoint.z});
}
}
Vector3 CornerPoint(int cornerIndex);
Vector3 ExtremePoint(const Vector3& direction) const;
Vector3 ExtremePoint(const Vector3& direction, float projectionDistance);
LineSegment Edge(int edgeIndex) const;
Vector3 CornerPoint(int cornerIndex) const;
Vector3 ExtremePoint(const Vector3 &direction) const;
Vector3 ExtremePoint(const Vector3 &direction, float &projectionDistance);
Vector3 PointOnEdge(int edgeIndex, float u) const;
Vector3 FaceCenterPoint(int faceIndex) const;
Vector3 FacePoint(int faceIndex, float u, float v) const;
Vector3 FaceNormal(int faceIndex) const;
Plane FacePlane(int faceIndex);
static AABB MinimalEnclosingAABB(const Vector3* pointArray, int numPoints);
Vector3 GetVolume();
float GetVolumeCubed();
float GetSurfaceArea();
Plane FacePlane(int faceIndex) const;
static AABB MinimalEnclosingAABB(const Vector3 *pointArray, int numPoints);
float GetVolume() const;
float GetSurfaceArea() const;
Vector3 GetRandomPointInside();
Vector3 GetRandomPointOnSurface();
Vector3 GetRandomPointOnEdge();
@@ -149,5 +133,26 @@ namespace Geometry
TriangleMesh Triangulate(int numFacesX, int numFacesY, int numFacesZ, bool ccwIsFrontFacing) const;
AABB Intersection(const AABB& rhs) const;
bool IntersectLineAABB(const Vector3& linePos, const Vector3& lineDir, float tNear, float tFar) const;
void SetFrom(const Vector3 *pVector3, int i);
void SetFromCenterAndSize(const Vector3 &center, const Vector3 &size);
void SetFrom(const OBB &obb);
void SetFrom(const Sphere &s);
Vector3 GetRandomPointInside() const;
void SetNegativeInfinity();
void Enclose(const Vector3 &point);
void Enclose(const Vector3 &aabbMinPt, const Vector3 &aabbMaxPt);
void Enclose(const LineSegment &lineSegment);
void Enclose(const OBB &obb);
};
}

View File

@@ -2,7 +2,7 @@
#include <J3ML/LinearAlgebra/Vector2.h>
namespace Geometry
namespace J3ML::Geometry
{
using LinearAlgebra::Vector2;
// CaveGame AABB

View File

@@ -3,7 +3,7 @@
#include "LineSegment.h"
#include <J3ML/LinearAlgebra/Vector3.h>
namespace Geometry
namespace J3ML::Geometry
{
using namespace LinearAlgebra;
class Capsule

View File

@@ -6,9 +6,11 @@
#include "Plane.h"
#include <J3ML/LinearAlgebra/CoordinateFrame.h>
namespace Geometry
namespace J3ML::Geometry
{
using J3ML::LinearAlgebra::CoordinateFrame;
enum class FrustumType
{
Invalid,

View File

@@ -2,7 +2,7 @@
#include <J3ML/LinearAlgebra/Vector3.h>
namespace Geometry
namespace J3ML::Geometry
{
using LinearAlgebra::Vector3;
class LineSegment

View File

@@ -5,7 +5,7 @@
#include <J3ML/Geometry/LineSegment.h>
#include <J3ML/Geometry/Polyhedron.h>
namespace Geometry {
namespace J3ML::Geometry {
class OBB
{
public:

View File

@@ -1,13 +1,17 @@
#pragma once
#include <J3ML/LinearAlgebra/Vector3.h>
using namespace LinearAlgebra;
class Plane
namespace J3ML::Geometry
{
public:
Vector3 Position;
Vector3 Normal;
float distance = 0.f;
using J3ML::LinearAlgebra::Vector3;
};
class Plane
{
public:
Vector3 Position;
Vector3 Normal;
float distance = 0.f;
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
namespace Geometry {
namespace J3ML::Geometry {
class Polygon {
};

View File

@@ -1,6 +1,6 @@
#pragma once
namespace Geometry
namespace J3ML::Geometry
{
class Polyhedron {

View File

@@ -5,7 +5,7 @@
#include <J3ML/LinearAlgebra/Vector2.h>
#include "AABB2D.h"
namespace Geometry {
namespace J3ML::Geometry {
using LinearAlgebra::Vector2;

View File

@@ -6,7 +6,7 @@
#include <J3ML/LinearAlgebra/Vector3.h>
namespace Geometry
namespace J3ML::Geometry
{
using LinearAlgebra::Vector3;
class Ray

View File

@@ -1,15 +1,70 @@
#pragma once
#include "J3ML/Geometry.h"
#include <J3ML/Geometry.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
#include <J3ML/LinearAlgebra/Matrix4x4.h>
#include <J3ML/Geometry/LineSegment.h>
#include <J3ML/Geometry/TriangleMesh.h>
namespace Geometry
namespace J3ML::Geometry
{
using J3ML::LinearAlgebra::Matrix3x3;
using J3ML::LinearAlgebra::Matrix4x4;
// A mathematical representation of a 3-dimensional sphere
class Sphere
{
public:
Sphere(const Vector3& pos, float radius)
Vector3 Position;
float Radius;
Sphere() {}
Sphere(const Vector3& pos, float radius) : Position(pos), Radius(radius) {}
void Translate(const Vector3& offset)
{
Position = Position + offset;
}
void Transform(const Matrix3x3& transform)
{
Position = transform * Position;
}
void Transform(const Matrix4x4& transform)
{
Position = transform * Position;
}
inline float Cube(float inp) const
{
return inp*inp*inp;
}
float Volume() const
{
return 4.f * M_PI * Cube(Radius) / 3.f;
}
float SurfaceArea() const
{
return 4.f * M_PI * Cube(Radius) / 3.f;
}
bool IsFinite() const
{
return Position.IsFinite() && std::isfinite(Radius);
}
bool IsDegenerate()
{
return !(Radius > 0.f) || !Position.IsFinite();
}
bool Contains(const Vector3& point) const
{
return Position.DistanceSquared(point) <= Radius*Radius;
}
bool Contains(const Vector3& point, float epsilon) const
{
return Position.DistanceSquared(point) <= Radius*Radius + epsilon;
}
bool Contains(const LineSegment& lineseg) const
{
}
TriangleMesh GenerateUVSphere() const {}
TriangleMesh GenerateIcososphere() const {}
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
namespace Geometry
namespace J3ML::Geometry
{
class Triangle
{

View File

@@ -1,8 +1,10 @@
//
// Created by dawsh on 1/25/24.
//
#pragma once
#ifndef J3ML_TRIANGLE2D_H
#define J3ML_TRIANGLE2D_H
#endif //J3ML_TRIANGLE2D_H
namespace J3ML::Geometry
{
class Shape2D {};
class Triangle2D {
public:
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
namespace Geometry
namespace J3ML::Geometry
{
class TriangleMesh
{

View File

@@ -1,17 +1,241 @@
#pragma once
//
// Created by josh on 12/25/2023.
//
#include <cstdint>
#include <cmath>
#include <stdfloat>
#include <string>
#include <cassert>
namespace J3ML
namespace J3ML::SizedIntegralTypes
{
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using u128 = __uint128_t;
using s8 = int8_t;
using s16 = int16_t;
using s32 = int32_t;
using s64 = int64_t;
using s128 = __int128_t;
}
namespace J3ML::SizedFloatTypes
{
using f32 = float;
using f64 = double;
using f128 = long double;
}
using namespace J3ML::SizedIntegralTypes;
using namespace J3ML::SizedFloatTypes;
namespace J3ML::Math
{
// Coming soon: Units Namespace
// For Dimensional Analysis
/*
namespace Units
{
struct Unit {};
struct Meters : public Unit { };
struct ImperialInches : public Unit {};
struct Time : public Unit {};
struct Grams : public Unit {};
struct MetersPerSecond : public Unit {};
template <typename TUnit>
struct Quantity
{
public:
float Value;
};
struct Mass : public Quantity<Grams> {};
struct Length : public Quantity<Meters> { };
struct Velocity : public Quantity<MetersPerSecond>{ };
class MetrixPrefix
{
public:
std::string Prefix;
std::string Symbol;
int Power;
float InverseMultiply(float input) const
{
return std::pow(input, -Power);
}
float Multiply(float input) const
{
return std::pow(input, Power);
}
};
namespace Prefixes
{
static constexpr MetrixPrefix Tera {"tera", "T", 12};
static constexpr MetrixPrefix Giga {"giga", "G", 9};
static constexpr MetrixPrefix Mega {"mega", "M", 6};
static constexpr MetrixPrefix Kilo {"kilo", "k", 3};
static constexpr MetrixPrefix Hecto {"hecto", "h", 2};
static constexpr MetrixPrefix Deca {"deca", "da", 1};
static constexpr MetrixPrefix None {"", "", 0};
static constexpr MetrixPrefix Deci {"", "", 0};
static constexpr MetrixPrefix Centi {"", "", 0};
static constexpr MetrixPrefix Milli {"", "", 0};
static constexpr MetrixPrefix Micro {"", "", 0};
static constexpr MetrixPrefix Nano {"", "", 0};
static constexpr MetrixPrefix Pico {"", "", 0};
}
Length operator ""_meters(long double value)
{
return {(float)value};
}
Length operator ""_m(long double value)
{
return {(float)value};
}
constexpr Length operator ""_kilometers(long double value)
{
return Length {(float)value};
}
Length operator ""_km(long double value)
{
return {(float)value};
}
Length operator ""_centimeters(long double value)
{
return {(float)value};
}
Length operator ""_cm(long double value)
{
return {(float)value};
}
Length operator ""_millimeters(long double value)
{
return {(float)value};
}
Length operator ""_mm(long double value)
{
return {(float)value};
}
Velocity operator ""_mps(long double value)
{
return {(float)value};
}
Velocity operator ""_meters_per_second(long double value)
{
return {(float)value};
}
Velocity operator ""_kmps(long double value)
{
return {(float)value};
}
}*/
#pragma region Constants
static const float Pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f;
static const float RecipSqrt2Pi = 0.3989422804014326779399460599343818684758586311649346576659258296706579258993018385012523339073069364f;
static const float GoldenRatio = 1.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375f;
#pragma endregion
#pragma region Math Functions
inline float Radians(float degrees);
inline float Degrees(float radians);
struct NumberRange
{
float LowerBound;
float UpperBound;
};
float NormalizeToRange(float input, float fromLower, float fromUpper, float toLower, float toUpper);
float NormalizeToRange(float input, const NumberRange& from, const NumberRange& to);
// auto rotation_normalized = NormalizeToRange(inp, {0, 360}, {-1, 1});
inline float Lerp(float a, float b, float t);
/// Linearly interpolates from a to b, under the modulus mod.
/// This function takes evaluates a and b in the range [0, mod] and takes the shorter path to reach from a to b.
inline float LerpMod(float a, float b, float mod, float t);
/// Computes the lerp factor a and b have to be Lerp()ed to get x.
inline float InverseLerp(float a, float b, float x);
/// See http://msdn.microsoft.com/en-us/library/bb509665(v=VS.85).aspx
inline float Step(float y, float x);
/// See http://msdn.microsoft.com/en-us/library/bb509658(v=vs.85).aspx
inline float Ramp(float min, float max, float x);
inline float PingPongMod(float x, float mod);
inline float Sqrt(float x);
inline float FastSqrt(float x);
/// Returns 1/Sqrt(x). (The reciprocal of the square root of x)
inline float RSqrt(float x);
inline float FastRSqrt(float x);
#pragma endregion
namespace 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);
}
namespace Interp
{
inline float SmoothStart(float t);
}
struct Rotation
{
public:
Rotation();
Rotation(float value);
float valueInRadians;
float ValueInRadians() const;
float ValueInDegrees() const;
Rotation operator+(const Rotation& rhs);
};
Rotation operator ""_rad(long double rads);
Rotation operator ""_radians(long double rads);
Rotation operator ""_deg(long double rads);
Rotation operator ""_degrees(long double rads);
}

View File

@@ -1,76 +1,30 @@
//// Dawsh Linear Algebra Library - Everything you need for 3D math
/// @file LinearAlgebra.h
/// @description Includes all LinearAlgebra classes and functions
/// @author Josh O'Leary, William Tomasine II
/// @copyright 2024 Redacted Software
/// @license Unlicense - Public Domain
/// @revision 1.3
/// @edited 2024-02-26
#pragma once
#include <cstdint>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <functional>
namespace Math
{
const float Pi = M_PI;
inline float Radians(float degrees) { return degrees * (Pi/180.f); }
inline float Degrees(float radians) { return radians * (180.f/Pi); }
struct NumberRange
{
float LowerBound;
float UpperBound;
};
float NormalizeToRange(float input, float fromLower, float fromUpper, float toLower, float toUpper);
float NormalizeToRange(float input, const NumberRange& from, const NumberRange& to);
// auto rotation_normalized = NormalizeToRange(inp, {0, 360}, {-1, 1});
inline float Lerp(float a, float b, float t);
}
// Dawsh Linear Algebra Library - Everything you need for 3D math
namespace LinearAlgebra {
class Vector2; // A type representing a position in a 2-dimensional coordinate space.
class Vector3; // A type representing a position in a 3-dimensional coordinate space.
class Vector4; // A type representing a position in a 4-dimensional coordinate space.
class 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;
class Matrix3x3;
class Matrix4x4;
class Transform2D;
class Transform3D;
class Quaternion;
using Position = Vector3;
}
// TODO: Enforce Style Consistency (Function Names use MicroSoft Case)
// Note: Josh Linear Algebra Types are designed as Immutable Data Types
// x, y, z, w, etc. values should not and can not be set directly.
// rather, you just construct a new type and assign it.
// This might sound ass-backwards for many object types.
// But mathematically, a vector or matrix is defined by it's size, and values.
// Changing the value of one axis fundamentally changes the definition of the vector/matrix.
// So we enforce this conceptually at code level...
// If you're wondering how it remains performant, it only heap-allocates a tiny space (4*n bytes for vectors) (4*n*m bytes for matrices)
// Just Trust Me Bro - Josjh
#define MUTABLE true // Toggle This For: Ugly math, ugly code, and an ugly genital infection!
#if MUTABLE
#define IMMUTABLE !MUTABLE
#endif
namespace LinearAlgebra
{
// TODO: Implement Templated Linear Algebra
// Library Code //
#include "J3ML/LinearAlgebra/Vector2.h"
#include "J3ML/LinearAlgebra/Vector3.h"
#include "J3ML/LinearAlgebra/Vector4.h"
#include "J3ML/LinearAlgebra/Quaternion.h"
#include "J3ML/LinearAlgebra/AxisAngle.h"
#include "J3ML/LinearAlgebra/EulerAngle.h"
#include "J3ML/LinearAlgebra/Matrix2x2.h"
#include "J3ML/LinearAlgebra/Matrix3x3.h"
#include "J3ML/LinearAlgebra/Matrix4x4.h"
#include "J3ML/LinearAlgebra/Transform2D.h"
#include "J3ML/LinearAlgebra/CoordinateFrame.h"
}
using namespace J3ML::LinearAlgebra;

View File

@@ -1,14 +1,22 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
class Angle2D {
public:
float x;
float y;
Angle2D(Math::Rotation rads);
Angle2D(float X, float Y)
{
x = X;
y = Y;
}
bool operator==(const Angle2D& rhs) const {
return (this->x==rhs.x && this->y==rhs.y);
}
};
}

View File

@@ -1,9 +1,11 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/EulerAngle.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
#include <J3ML/LinearAlgebra/AxisAngle.h>
#include <J3ML/LinearAlgebra/Vector3.h>
namespace LinearAlgebra
namespace J3ML::LinearAlgebra
{
/// Transitional datatype, not useful for internal representation of rotation

View File

@@ -0,0 +1,28 @@
#pragma once
// Forward Declarations for classes that include each other
namespace J3ML::LinearAlgebra
{
class Vector2; // A type representing a position in a 2-dimensional coordinate space.
class Vector3; // A type representing a position in a 3-dimensional coordinate space.
class Vector4; // A type representing a position in a 4-dimensional coordinate space.
class 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;
class Matrix3x3;
class Matrix4x4;
class Transform2D;
class Transform3D;
class Quaternion;
using Position = Vector3;
}
// Methods required by LinearAlgebra types
namespace J3ML::LinearAlgebra
{
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector3.h>
namespace LinearAlgebra
namespace J3ML::LinearAlgebra
{
/// The CFrame is fundamentally 4 vectors (position, forward, right, up vector)
class CoordinateFrame

View File

@@ -1,8 +1,12 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector3.h>
namespace LinearAlgebra {
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
#include <J3ML/LinearAlgebra/AxisAngle.h>
namespace J3ML::LinearAlgebra {
class AxisAngle;
// Essential Reading:
// http://www.essentialmath.com/GDC2012/GDC2012_JMV_Rotations.pdf

View File

@@ -1,9 +1,9 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector2.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
class Matrix2x2 {
public:
enum { Rows = 3 };

View File

@@ -1,11 +1,15 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector2.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
class Quaternion;
/// A 3-by-3 matrix for linear transformations of 3D geometry.
/* This can represent any kind of linear transformations of 3D geometry, which include
* rotation, scale, shear, mirroring, and orthographic projection.
@@ -61,16 +65,7 @@ namespace LinearAlgebra {
void SetColumn(int i, const Vector3& vector);
void SetAt(int x, int y, float value);
void Orthonormalize(int c0, int c1, int c2)
{
Vector3 v0 = GetColumn(c0);
Vector3 v1 = GetColumn(c1);
Vector3 v2 = GetColumn(c2);
Vector3::Orthonormalize(v0, v1, v2);
SetColumn(c0, v0);
SetColumn(c1, v1);
SetColumn(c2, v2);
}
void Orthonormalize(int c0, int c1, int c2);
static Matrix3x3 LookAt(const Vector3& forward, const Vector3& target, const Vector3& localUp, const Vector3& worldUp);
@@ -90,8 +85,8 @@ namespace LinearAlgebra {
/// Creates a new transformation matrix that scales by the given factors.
// This matrix scales with respect to origin.
static Matrix3x3 Scale(float sx, float sy, float sz);
static Matrix3x3 Scale(const Vector3& scale);
static Matrix3x3 FromScale(float sx, float sy, float sz);
static Matrix3x3 FromScale(const Vector3& scale);
/// Returns the main diagonal.
Vector3 Diagonal() const;
@@ -124,10 +119,11 @@ namespace LinearAlgebra {
Vector2 Transform(const Vector2& rhs) const;
Vector3 Transform(const Vector3& rhs) const;
Vector3 operator[](int row) const
{
return Vector3{elems[row][0], elems[row][1], elems[row][2]};
}
Matrix3x3 ScaleBy(const Vector3& rhs);
Vector3 GetScale() const;
Vector3 operator[](int row) const;
Vector3 operator * (const Vector3& rhs) const;
Matrix3x3 operator * (const Matrix3x3& rhs) const;

View File

@@ -1,9 +1,15 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Common.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
#include <J3ML/LinearAlgebra/Vector4.h>
#include <algorithm>
namespace J3ML::LinearAlgebra {
/// A 4-by-4 matrix for affine transformations and perspective projections of 3D geometry.
/* This matrix can represent the most generic form of transformations for 3D objects,
@@ -118,6 +124,12 @@ namespace LinearAlgebra {
Vector3 GetRow3(int index) const;
Vector3 GetColumn3(int index) const;
Vector3 GetScale() const
{
}
Matrix4x4 Scale(const Vector3&);
float &At(int row, int col);
float At(int x, int y) const;
@@ -204,10 +216,10 @@ namespace LinearAlgebra {
static Matrix4x4 D3DPerspProjLH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 D3DPerspProjRH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 OpenGLOrthoProjLH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 OpenGLOrthoProjRH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 OpenGLPerspProjLH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 OpenGLPerspProjRH(float nearPlane, float farPlane, float hViewportSize, float vViewportSize);
static Matrix4x4 OpenGLOrthoProjLH(float n, float f, float h, float v);
static Matrix4x4 OpenGLOrthoProjRH(float n, float f, float h, float v);
static Matrix4x4 OpenGLPerspProjLH(float n, float f, float h, float v);
static Matrix4x4 OpenGLPerspProjRH(float n, float f, float h, float v);
Vector4 operator[](int row);

View File

@@ -1,13 +1,22 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
#include <J3ML/LinearAlgebra/Matrix4x4.h>
#include <J3ML/LinearAlgebra/Vector4.h>
#include <J3ML/LinearAlgebra/AxisAngle.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
//#include <J3ML/LinearAlgebra/AxisAngle.h>
#include <cmath>
namespace LinearAlgebra
namespace J3ML::LinearAlgebra
{
class Matrix3x3;
class Quaternion : public Vector4 {
public:
Quaternion();
@@ -23,13 +32,9 @@ namespace LinearAlgebra
// 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.
Quaternion(const Vector3 &rotationAxis, float rotationAngleBetween) {
SetFromAxisAngle(rotationAxis, rotationAngleBetween);
}
Quaternion(const Vector3 &rotationAxis, float rotationAngleBetween);
Quaternion(const Vector4 &rotationAxis, float rotationAngleBetween) {
SetFromAxisAngle(rotationAxis, rotationAngleBetween);
}
Quaternion(const Vector4 &rotationAxis, float rotationAngleBetween);
//void Inverse();
explicit Quaternion(Vector4 vector4);
@@ -49,15 +54,9 @@ namespace LinearAlgebra
Vector3 GetWorldZ() const;
Vector3 GetAxis() const {
float rcpSinAngle = 1 - (std::sqrt(1 - w * w));
Vector3 GetAxis() const;
return Vector3(x, y, z) * rcpSinAngle;
}
float GetAngle() const {
return std::acos(w) * 2.f;
}
float GetAngle() const;
Matrix3x3 ToMatrix3x3() const;
@@ -102,7 +101,7 @@ namespace LinearAlgebra
Quaternion operator - () const;
float Dot(const Quaternion &quaternion) const;
float Angle() const { return std::acos(w) * 2.f;}
float Angle() const { return acos(w) * 2.f;}
float AngleBetween(const Quaternion& target) const;

View File

@@ -1,9 +1,9 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Matrix3x3.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
class Transform2D {
protected:
Matrix3x3 transformation;

View File

@@ -1,21 +1,26 @@
#pragma clang diagnostic push
#pragma ide diagnostic ignored "modernize-use-nodiscard"
#pragma once
#include <J3ML/J3ML.h>
#include <J3ML/LinearAlgebra.h>
#include <cstddef>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
using namespace J3ML;
/// A 2D (x, y) ordered pair.
class Vector2 {
public:
enum {Dimensions = 2};
/// Default Constructor - Initializes values to zero
Vector2();
/// Constructs a new Vector2 with the value (X, Y)
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}
explicit Vector2(float scalar);
Vector2(const Vector2& rhs); // Copy Constructor
//Vector2(Vector2&&) = default; // Move Constructor
@@ -31,13 +36,36 @@ namespace LinearAlgebra {
void SetX(float newX);
void SetY(float newY);
/// Casts this float2 to a C array.
/** This function does not allocate new memory or make a copy of this float2. This function simply
returns a C pointer view to this data structure. Use ptr()[0] to access the x component of this float2
and ptr()[1] to access the y component.
@note Since the returned pointer points to this class, do not dereference the pointer after this
float2 has been deleted. You should never store a copy of the returned pointer.
@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 []
or the At() function to access the elements of this vector by index.
@return A pointer to the first float element of this class. The data is contiguous in memory.
@see operator [](), At(). */
float* ptr();
const float *ptr() const;
float operator[](std::size_t index) const;
float &operator[](std::size_t index);
const float At(std::size_t index) const;
float &At(std::size_t index);
Vector2 Abs() const;
bool IsWithinMarginOfError(const Vector2& rhs, float margin=0.001f) const;
bool IsNormalized(float epsilonSq = 1e-5f) const;
bool IsZero(float epsilonSq = 1e-6f) const;
bool IsPerpendicular(const Vector2& other, float epsilonSq=1e-5f) const;
float operator[](std::size_t index);
bool operator == (const Vector2& rhs) const;
bool operator != (const Vector2& rhs) const;
@@ -72,10 +100,6 @@ namespace LinearAlgebra {
static float Magnitude(const Vector2& of);
bool IsFinite() const;
static bool IsFinite(const Vector2& v);
@@ -143,8 +167,9 @@ namespace LinearAlgebra {
Vector2 operator +() const; // TODO: Implement
Vector2 operator -() const;
/// Assigns a vector to another
Vector2& operator+=(const Vector2& rhs); // Adds a vector to this vector, in-place.
Vector2& operator-=(const Vector2& rhs); // Subtracts a vector from this vector, in-place
Vector2 &operator =(const Vector2 &rhs);
Vector2& operator+=(const Vector2& rhs);
Vector2& operator-=(const Vector2& rhs);
Vector2& operator*=(float scalar);
Vector2& operator/=(float scalar);
@@ -158,4 +183,5 @@ namespace LinearAlgebra {
{
return rhs * lhs;
}
}
}
#pragma clang diagnostic pop

View File

@@ -1,17 +1,20 @@
#pragma once
#include <J3ML/LinearAlgebra/Vector2.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#include <cstddef>
#include <cstdlib>
#include <J3ML/LinearAlgebra/Angle2D.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
// A 3D (x, y, z) ordered pair.
class Vector3 {
public:
enum {Dimensions = 3};
// Default Constructor - Initializes to zero
Vector3();
// Constructs a new Vector3 with the value (X, Y, Z)
@@ -19,7 +22,7 @@ public:
Vector3(const Vector3& rhs); // Copy Constructor
Vector3(Vector3&&) = default; // Move Constructor
Vector3& operator=(const Vector3& rhs);
explicit Vector3(const float* data);
static const Vector3 Zero;
static const Vector3 Up;
@@ -29,38 +32,28 @@ public:
static const Vector3 Forward;
static const Vector3 Backward;
static const Vector3 NaN;
static const Vector3 Infinity;
static const Vector3 NegativeInfinity;
static void Orthonormalize(Vector3& a, Vector3& b)
{
a = a.Normalize();
b = b - b.ProjectToNorm(a);
b = b.Normalize();
}
float* ptr();
static void Orthonormalize(Vector3& a, Vector3& b);
Vector3 Abs() const;
/// Returns the DirectionVector for a given angle.
static Vector3 Direction(const Vector3 &rhs) ;
static void Orthonormalize(Vector3& a, Vector3& b, Vector3& c)
{
a = a.Normalize();
b = b - b.ProjectToNorm(a);
b = b.Normalize();
c = c - c.ProjectToNorm(a);
c = c - c.ProjectToNorm(b);
c = c.Normalize();
}
static void Orthonormalize(Vector3& a, Vector3& b, Vector3& c);
bool AreOrthonormal(const Vector3& a, const Vector3& b, float epsilon)
{
}
Vector3 ProjectToNorm(const Vector3& direction)
{
return direction * this->Dot(direction);
}
Vector3 ProjectToNorm(const Vector3& direction) const;
float GetX() const;
float GetY() const;
@@ -75,13 +68,11 @@ public:
bool IsPerpendicular(const Vector3& other, float epsilonSq=1e-5f) const;
float operator[](std::size_t index) const;
float &operator[](std::size_t index);
bool operator == (const Vector3& rhs) const;
bool operator != (const Vector3& rhs) const;
bool IsFinite() const
{
return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
}
bool IsFinite() const;
Vector3 Min(const Vector3& min) const;
static Vector3 Min(const Vector3& lhs, const Vector3& rhs);
@@ -96,6 +87,9 @@ public:
float Distance(const Vector3& to) const;
static float Distance(const Vector3& from, const Vector3& to);
float DistanceSquared(const Vector3& to) const;
static float DistanceSquared(const Vector3& from, const Vector3& to);
float Length() const;
static float Length(const Vector3& of);
@@ -179,4 +173,9 @@ public:
float y = 0;
float z = 0;
};
static Vector3 operator*(float lhs, const Vector3& rhs)
{
return rhs * lhs;
}
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Vector3.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
class Vector4 {
public:
// Default Constructor
@@ -16,6 +16,11 @@ namespace LinearAlgebra {
Vector4(Vector4&& move) = default;
Vector4& operator=(const Vector4& rhs);
float* ptr()
{
return &x;
}
float GetX() const;
float GetY() const;
float GetZ() const;

19
include/J3ML/Units.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
namespace J3ML::Units
{
template <typename T>
class Rotation
{
T GetDegrees() const;
T GetRadians() const;
void SetDegrees(T val);
void SetRadians(T val);
};
using Rotationf = Rotation<float>;
using Rotationd = Rotation<double>;
}

154
src/J3ML/Algorithm/RNG.cpp Normal file
View File

@@ -0,0 +1,154 @@
#include <J3ML/Algorithm/RNG.h>
#include <stdexcept>
#include <cassert>
namespace J3ML::Algorithm {
void RNG::Seed(u32 seed, u32 multiplier, u32 increment, u32 modulus) {
// If we have a pure multiplicative RNG, then can't have 0 starting seed, since that would generate a stream of all zeroes
if (seed == 0 && increment == 0) seed = 1;
if (increment == 0 && (multiplier % modulus == 0 || modulus % multiplier == 0 ))
throw std::runtime_error("Multiplier %u and modulus %u are not compatible since one is a multiple of the other and the increment == 0!");
// TODO: assert(multiplier != 0);
// TODO: assert(modulus > 1);
this->lastNumber = seed;
this->multiplier = multiplier;
this->increment = increment;
this->modulus = modulus;
}
u32 RNG::IntFast()
{
assert(increment == 0);
assert(multiplier % 2 == 1 && "Multiplier should be odd for RNG::IntFast(), since modulus==2^32 is even!");
// The configurable modulus and increment are not used by this function.
u32 mul = lastNumber * multiplier;
// Whenever we overflow, flip by one to avoud even multiplier always producing even results
// since modulus is even.
lastNumber = mul + (mul <= lastNumber?1:0);
// We don't use an adder in IntFast(), so must never degenerate to zero
assert(lastNumber != 0);
return lastNumber;
}
u32 RNG::Int()
{
assert(modulus != 0);
/// TODO: Convert to using Shrage's method for approximate factorization (Numerical Recipes in C)
// Currently we cast everything to 65-bit to avoid overflow, which is quite dumb.
// Creates the new random number
u64 newNum = ((u64)lastNumber * (u64)multiplier + (u64)increment % (u64)modulus);
// TODO: use this on console platforms to rely on smaller sequences.
// u32 m = lastNumber * multiplier;
// u32 i = m + increment;
// u32 f = i & 0x7FFFFFFF;
// u32 m = (lastNumber * 214013 + 2531011) & 0x7FFFFFFF;
// unsigned __int64 newNum = (lastNumber * multiplier + increment) & 0x7FFFFFFF;
assert( ((u32)newNum!=0 || increment != 0) && "RNG degenerated to producing a stream of zeroes!");
lastNumber = (u32)newNum;
return lastNumber;
}
int RNG::Int(int a, int b) {
assert(a <= b && "Error in range!");
int num = a + (int)(Float() * (b-a+1));
// TODO: Some bug here - the result is not necessarily in the proper range.
if (num < a) num = a;
if (num > b) num = b;
return num;
}
/// Jesus-Fuck ~ Josh
/// As per C99, union-reinterpret should now be safe: http://stackoverflow.com/questions/8511676/portable-data-reinterpretation
union FloatIntReinterpret
{
float f;
u32 i;
};
template <typename To, typename From>
union ReinterpretOp {
To to;
From from;
};
template <typename To, typename From>
To ReinterpretAs(From input)
{
ReinterpretOp<To, From> fi {};
fi.to = input;
return fi.from;
}
float RNG::Float() {
u32 i = ((u32)Int() & 0x007FFFFF /* random mantissa */) | 0x3F800000 /* fixed exponent */;
auto f = ReinterpretAs<float, u32>(i); // f is now in range [1, 2[
f -= 1.f; // Map to range [0, 1[
assert(f >= 0.f);
assert(f < 1.f);
return f;
}
float RNG::Float01Incl() {
for (int i = 0; i < 100; ++i) {
u32 val = (u32)Int() & 0x00FFFFFF;
if (val > 0x800000)
continue;
else if (val = 0x800000)
return 1.f;
else {
val |= 0x3F800000;
float f = ReinterpretAs<float, u32>(val) - 1.f;
assert(f >= 0.f);
assert(f <= 1.f);
return f;
}
}
return Float();
}
float RNG::FloatNeg1_1() {
u32 i = (u32) Int();
u32 one = ((i & 0x00800000) << 8) /* random sign bit */ | 0x3F800000; /* fixed exponent */
i = one | (i & 0x007FFFFF); // Random mantissa
float f = ReinterpretAs<float, u32>(i); // f is now in range ]-2, -1[ union [1, 2].
float fone = ReinterpretAs<float, u32>(one); // +/- 1, of same sign as f.
f -= fone;
assert(f > -1.f);
assert(f < 1.f);
return f;
}
float RNG::Float(float a, float b) {
assert(a <= b && "");
if (a == b)
return a;
for (int i = 0; i < 10; ++i)
{
float f = a + Float() * (b - a);
if (f != b) {
assert(a <= f);
assert(f < b || a == b);
return f;
}
}
return a;
}
float RNG::FloatIncl(float a, float b) {
assert(a <= b && "RNG::Float(a, b): Error in range: b < a!");
float f = a + Float() * (b - a);
assert( a <= f);
assert(f <= b);
return f;
}
}

View File

@@ -1,5 +1,237 @@
#include <J3ML/Geometry/AABB.h>
#include <cassert>
namespace Geometry {
namespace J3ML::Geometry {
}
AABB AABB::FromCenterAndSize(const J3ML::Geometry::Vector3 &center, const J3ML::Geometry::Vector3 &size) {
Vector3 halfSize = size * 0.5f;
return {center - halfSize, center + halfSize};
}
float AABB::MinX() const { return minPoint.x; }
float AABB::MinY() const { return minPoint.y; }
float AABB::MinZ() const { return minPoint.z; }
float AABB::MaxX() const { return maxPoint.x; }
float AABB::MaxY() const { return maxPoint.y; }
float AABB::MaxZ() const { return maxPoint.z; }
Sphere AABB::MinimalEnclosingSphere() const {
return Sphere(Centroid(), Size().Length()*0.5f);
}
Vector3 AABB::HalfSize() const {
return this->Size()/2.f;
}
Sphere AABB::MaximalContainedSphere() const {
Vector3 halfSize = HalfSize();
return Sphere(Centroid(), std::min(halfSize.x, std::min(halfSize.y, halfSize.z)));
}
bool AABB::IsFinite() const {
return minPoint.IsFinite() && maxPoint.IsFinite();
}
Vector3 AABB::Centroid() const {
return (minPoint+maxPoint) * 0.5f;
}
Vector3 AABB::Size() const {
return this->maxPoint - this->minPoint;
}
Vector3 AABB::PointInside(float x, float y, float z) const {
Vector3 d = maxPoint - minPoint;
return minPoint + d.Mul({x, y, z});
}
LineSegment AABB::Edge(int edgeIndex) const {
switch(edgeIndex)
{
default:
case 0: return LineSegment(minPoint, {minPoint.x, minPoint.y, maxPoint.z});
}
}
Vector3 AABB::CornerPoint(int cornerIndex) const {
// TODO: assert(0 <= cornerIndex && cornerIndex <= 7)
switch(cornerIndex)
{
default:
case 0: return minPoint;
case 1: return {minPoint.x, minPoint.y, maxPoint.z};
case 2: return {minPoint.x, maxPoint.y, minPoint.z};
case 3: return {minPoint.x, maxPoint.y, maxPoint.z};
case 4: return {maxPoint.x, minPoint.y, minPoint.z};
case 5: return {maxPoint.x, minPoint.y, maxPoint.z};
case 6: return {maxPoint.x, maxPoint.y, minPoint.z};
case 7: return maxPoint;
}
}
Vector3 AABB::ExtremePoint(const Vector3 &direction) const {
return {direction.x >= 0.f ? maxPoint.x : minPoint.x,
direction.y >= 0.f ? maxPoint.y : minPoint.y,
direction.z >= 0.f ? maxPoint.z : minPoint.z};
}
Vector3 AABB::ExtremePoint(const Vector3 &direction, float &projectionDistance) {
auto extremePt = ExtremePoint(direction);
projectionDistance = extremePt.Dot(direction);
return extremePt;
}
Vector3 AABB::PointOnEdge(int edgeIndex, float u) const {
// TODO: assert(0 <= edgeIndex && edgeIndex <= 11);
// TODO: assert(0 <= u && u < 1.f);
auto d = maxPoint - minPoint;
switch(edgeIndex) {
default:
case 0: return {minPoint.x, minPoint.y, minPoint.z + u * d.z};
case 1: return {minPoint.x, maxPoint.y, minPoint.z + u * d.z};
case 2: return {maxPoint.x, minPoint.y, minPoint.z + u * d.z};
case 3: return {maxPoint.x, maxPoint.y, minPoint.z + u * d.z};
case 4: return {minPoint.x, minPoint.y + u * d.y, minPoint.z};
case 5: return {maxPoint.x, minPoint.y + u * d.y, minPoint.z};
case 6: return {minPoint.x, minPoint.y + u * d.y, maxPoint.z};
case 7: return {maxPoint.x, minPoint.y + u * d.y, maxPoint.z};
case 8: return {minPoint.x + u * d.x, minPoint.y, minPoint.z};
case 9: return {minPoint.x + u * d.x, minPoint.y, maxPoint.z};
case 10:return {minPoint.x + u * d.x, maxPoint.y, minPoint.z};
case 11:return {minPoint.x + u * d.x, maxPoint.y, maxPoint.z};
}
}
Vector3 AABB::FaceCenterPoint(int faceIndex) const {
// TODO: assert(0 <= faceIndex && faceIndex <= 5)
auto center = (minPoint + maxPoint) * 0.5f;
switch (faceIndex) {
default:
case 0: return {minPoint.x, center.y, center.z};
case 1: return {maxPoint.x, center.y, center.z};
case 2: return {center.x, minPoint.y, center.z};
case 3: return {center.x, maxPoint.y, center.z};
case 4: return {center.x, center.y, minPoint.z};
case 5: return {center.x, center.y, maxPoint.z};
}
}
Vector3 AABB::FacePoint(int faceIndex, float u, float v) const {
// TODO: assert(0 <= faceIndex && faceIndex <= 5);
// TODO: assert(0 <= u && u <= 1.f);
// TODO: assert(0 <= v && v <= 1.f);
auto d = maxPoint - minPoint;
switch(faceIndex)
{
default: // For release builds where assume() is disabled, return always the first option if out-of-bounds.
case 0: return {minPoint.x, minPoint.y + u * d.y, minPoint.z + v * d.z};
case 1: return {maxPoint.x, minPoint.y + u * d.y, minPoint.z + v * d.z};
case 2: return {minPoint.x + u * d.x, minPoint.y, minPoint.z + v * d.z};
case 3: return {minPoint.x + u * d.x, maxPoint.y, minPoint.z + v * d.z};
case 4: return {minPoint.x + u * d.x, minPoint.y + v * d.y, minPoint.z};
case 5: return {minPoint.x + u * d.x, minPoint.y + v * d.y, maxPoint.z};
}
}
Vector3 AABB::FaceNormal(int faceIndex) const {
// TODO: assert(0 <= faceIndex && faceIndex <= 5);
switch(faceIndex) {
default:
case 0: return {-1, 0, 0};
case 1: return { 1, 0, 0};
case 2: return { 0, -1, 0};
case 3: return { 0, 1, 0};
case 4: return { 0, 0, -1};
case 5: return { 0, 0, 1};
}
}
Plane AABB::FacePlane(int faceIndex) const {
// TODO: assert(0 <= faceIndex && faceIndex <= 5);
return Plane(FaceCenterPoint(faceIndex), FaceNormal(faceIndex));
}
AABB AABB::MinimalEnclosingAABB(const Vector3 *pointArray, int numPoints) {
AABB aabb;
aabb.SetFrom(pointArray, numPoints);
return aabb;
}
float AABB::GetVolume() const {
Vector3 sz = Size();
return sz.x * sz.y * sz.z;
}
float AABB::GetSurfaceArea() const {
Vector3 size = Size();
return 2.f * (size.x*size.y + size.x*size.z + size.y*size.z);
}
void AABB::SetFromCenterAndSize(const Vector3& center, const Vector3& size)
{
}
void AABB::SetFrom(const OBB& obb)
{
}
void AABB::SetFrom(const Sphere& s)
{
}
void AABB::SetFrom(const Vector3 *pointArray, int numPoints) {
assert(pointArray || numPoints == 0);
SetNegativeInfinity();
if (!pointArray)
return;
for (int i = 0; i < numPoints; ++i)
Enclose(pointArray[i]);
}
Vector3 AABB::GetRandomPointInside() const {
}
void AABB::SetNegativeInfinity() {
minPoint = Vector3::Infinity;
maxPoint = Vector3::NegativeInfinity;
}
void AABB::Enclose(const Vector3& point) {
minPoint = Vector3::Min(minPoint, point);
maxPoint = Vector3::Max(maxPoint, point);
}
void AABB::Enclose(const Vector3& aabbMinPt, const Vector3& aabbMaxPt)
{
minPoint = Vector3::Min(minPoint, aabbMinPt);
maxPoint = Vector3::Max(maxPoint, aabbMaxPt);
}
void AABB::Enclose(const LineSegment& lineSegment)
{
Enclose(Vector3::Min(lineSegment.A, lineSegment.B), Vector3::Max(lineSegment.A, lineSegment.B));
}
void AABB::Enclose(const OBB& obb)
{
Vector3 absAxis0 = obb.axis[0].Abs();
Vector3 absAxis1 = obb.axis[1].Abs();
Vector3 absAxis2 = obb.axis[2].Abs();
Vector3 d = obb.r.x * absAxis0 + obb.r.y * absAxis1 + obb.r.z * absAxis2;
}
}

View File

@@ -1,6 +1,6 @@
#include <J3ML/Geometry/Capsule.h>
namespace Geometry
namespace J3ML::Geometry
{
Capsule::Capsule() : l() {}

View File

@@ -1,6 +1,7 @@
#include <J3ML/Geometry/Frustum.h>
#include <cmath>
namespace Geometry
namespace J3ML::Geometry
{
Frustum Frustum::CreateFrustumFromCamera(const CoordinateFrame &cam, float aspect, float fovY, float zNear, float zFar) {
Frustum frustum;

View File

@@ -1,6 +1,6 @@
#include <J3ML/Geometry/LineSegment.h>
namespace Geometry {
namespace J3ML::Geometry {
LineSegment::LineSegment(const Vector3 &a, const Vector3 &b) : A(a), B(b)
{

View File

@@ -1 +1,6 @@
#include <J3ML/Geometry/Sphere.h>
#include <J3ML/Geometry/Sphere.h>
namespace J3ML::Geometry
{
}

43
src/J3ML/J3ML.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <J3ML/J3ML.h>
namespace J3ML
{
Math::Rotation Math::operator ""_degrees(long double rads) { return {Radians((float)rads)}; }
Math::Rotation Math::operator ""_deg(long double rads) { return {Radians((float)rads)}; }
Math::Rotation Math::operator ""_radians(long double rads) { return {(float)rads}; }
Math::Rotation Math::operator ""_rad(long double rads) { return {(float)rads}; }
float Math::FastRSqrt(float x) {
return 1.f / FastSqrt(x);
}
float Math::RSqrt(float x) {
return 1.f / Sqrt(x);
}
float Math::Radians(float degrees) { return degrees * (Pi/180.f); }
float Math::Degrees(float radians) { return radians * (180.f/Pi); }
Math::Rotation::Rotation() : valueInRadians(0) {}
Math::Rotation::Rotation(float value) : valueInRadians(value) {}
Math::Rotation Math::Rotation::operator+(const Math::Rotation &rhs) {
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) {
}
}

View File

@@ -1,4 +1,4 @@
#include <J3ML/LinearAlgebra.h>
#include "J3ML/LinearAlgebra.h"
#include <cassert>
namespace LinearAlgebra {

View File

@@ -1,6 +1,6 @@
#include <J3ML/LinearAlgebra/AxisAngle.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
AxisAngle::AxisAngle() : axis(Vector3::Zero) {}

View File

@@ -3,50 +3,49 @@
#include <algorithm>
#pragma region EulerAngle
namespace LinearAlgebra {
EulerAngle::EulerAngle(float pitch, float yaw, float roll): pitch(pitch), yaw(yaw), roll(roll)
{}
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::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::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); }
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);
}
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;
}
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::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) {}
}

View File

@@ -1,6 +1,6 @@
#include <J3ML/LinearAlgebra/Matrix2x2.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
Vector2 Matrix2x2::GetRow(int index) const {
float x = this->elems[index][0];

View File

@@ -1,7 +1,7 @@
#include <J3ML/LinearAlgebra/Matrix3x3.h>
#include <cmath>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
const Matrix3x3 Matrix3x3::Zero = Matrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
const Matrix3x3 Matrix3x3::Identity = Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
@@ -313,16 +313,54 @@ namespace LinearAlgebra {
}
Matrix3x3 Matrix3x3::FromRS(const Quaternion &rotate, const Vector3 &scale) {
return Matrix3x3(rotate) * Matrix3x3::Scale(scale);
return Matrix3x3(rotate) * Matrix3x3::FromScale(scale);
}
Matrix3x3 Matrix3x3::FromRS(const Matrix3x3 &rotate, const Vector3 &scale) {
return rotate * Matrix3x3::Scale(scale);
return rotate * Matrix3x3::FromScale(scale);
}
Matrix3x3 Matrix3x3::FromQuat(const Quaternion &orientation) {
return Matrix3x3(orientation);
}
Matrix3x3 Matrix3x3::ScaleBy(const Vector3 &rhs) {
return *this * FromScale(rhs);
}
Vector3 Matrix3x3::GetScale() const {
return Vector3(GetColumn(0).Length(), GetColumn(1).Length(), GetColumn(2).Length());
}
Vector3 Matrix3x3::operator[](int row) const {
return Vector3{elems[row][0], elems[row][1], elems[row][2]};
}
Matrix3x3 Matrix3x3::FromScale(const Vector3 &scale) {
Matrix3x3 m;
m.At(0,0) = scale.x;
m.At(1,1) = scale.y;
m.At(2,2) = scale.z;
return m;
}
Matrix3x3 Matrix3x3::FromScale(float sx, float sy, float sz) {
Matrix3x3 m;
m.At(0,0) = sx;
m.At(1,1) = sy;
m.At(2,2) = sz;
return m;
}
void Matrix3x3::Orthonormalize(int c0, int c1, int c2) {
Vector3 v0 = GetColumn(c0);
Vector3 v1 = GetColumn(c1);
Vector3 v2 = GetColumn(c2);
Vector3::Orthonormalize(v0, v1, v2);
SetColumn(c0, v0);
SetColumn(c1, v1);
SetColumn(c2, v2);
}
}

View File

@@ -1,7 +1,7 @@
#include <J3ML/LinearAlgebra/Matrix4x4.h>
#include <J3ML/LinearAlgebra/Vector4.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
const Matrix4x4 Matrix4x4::Zero = Matrix4x4(0);
const Matrix4x4 Matrix4x4::Identity = Matrix4x4({1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1});
const Matrix4x4 Matrix4x4::NaN = Matrix4x4(NAN);
@@ -420,6 +420,16 @@ namespace LinearAlgebra {
return GetColumn3(3);
}
Matrix4x4 Matrix4x4::Scale(const Vector3& scale)
{
auto mat = *this;
mat.At(3, 0) *= scale.x;
mat.At(3, 1) *= scale.y;
mat.At(3, 2) *= scale.z;
return mat;
}
Matrix4x4
Matrix4x4::LookAt(const Vector3 &localFwd, const Vector3 &targetDir, const Vector3 &localUp, const Vector3 &worldUp) {
Matrix4x4 m;
@@ -514,4 +524,50 @@ namespace LinearAlgebra {
At(row, 2) *= scalar;
At(row, 3) *= scalar;
}
Matrix4x4 Matrix4x4::OpenGLOrthoProjLH(float n, float f, float h, float v) {
/// Same as OpenGLOrthoProjRH, except that the camera looks towards +Z in view space, instead of -Z.
using f32 = float;
f32 p00 = 2.f / h; f32 p01 = 0; f32 p02 = 0; float p03 = 0.f;
f32 p10 = 0; f32 p11 = 2.f / v; f32 p12 = 0; float p13 = 0.f;
f32 p20 = 0; f32 p21 = 0; f32 p22 = 2.f / (f-n); float p23 = (f+n) / (n-f);
f32 p30 = 0; f32 p31 = 0; f32 p32 = 0; float p33 = 1.f;
return {p00, p01, p02, p03, p10, p11, p12, p13, p20, p21, p22, p23, p30, p31, p32, p33};
}
Matrix4x4 Matrix4x4::OpenGLOrthoProjRH(float n, float f, float h, float v) {
using f32 = float;
f32 p00 = 2.f / h; f32 p01 = 0; f32 p02 = 0; f32 p03 = 0.f;
f32 p10 = 0; f32 p11 = 2.f / v; f32 p12 = 0; f32 p13 = 0.f;
f32 p20 = 0; f32 p21 = 0; f32 p22 = 2.f / (n-f); f32 p23 = (f+n) / (n-f);
f32 p30 = 0; f32 p31 = 0; f32 p32 = 0; f32 p33 = 1.f;
return {p00, p01, p02, p03, p10, p11, p12, p13, p20, p21, p22, p23, p30, p31, p32, p33};
}
Matrix4x4 Matrix4x4::OpenGLPerspProjLH(float n, float f, float h, float v) {
// Same as OpenGLPerspProjRH, except that the camera looks towards +Z in view space, instead of -Z.
using f32 = float;
f32 p00 = 2.f *n / h; f32 p01 = 0; f32 p02 = 0; f32 p03 = 0.f;
f32 p10 = 0; f32 p11 = 2.f * n / v; f32 p12 = 0; f32 p13 = 0.f;
f32 p20 = 0; f32 p21 = 0; f32 p22 = (n+f) / (f-n); f32 p23 = 2.f*n*f / (n-f);
f32 p30 = 0; f32 p31 = 0; f32 p32 = 1.f; f32 p33 = 0.f;
return {p00, p01, p02, p03, p10, p11, p12, p13, p20, p21, p22, p23, p30, p31, p32, p33};
}
Matrix4x4 Matrix4x4::OpenGLPerspProjRH(float n, float f, float h, float v) {
// In OpenGL, the post-perspective unit cube ranges in [-1, 1] in all X, Y and Z directions.
// See http://www.songho.ca/opengl/gl_projectionmatrix.html , unlike in Direct3D, where the
// Z coordinate ranges in [0, 1]. This is the only difference between D3DPerspProjRH and OpenGLPerspProjRH.
using f32 = float;
float p00 = 2.f *n / h; float p01 = 0; float p02 = 0; float p03 = 0.f;
float p10 = 0; float p11 = 2.f * n / v; float p12 = 0; float p13 = 0.f;
float p20 = 0; float p21 = 0; float p22 = (n+f) / (n-f); float p23 = 2.f*n*f / (n-f);
float p30 = 0; float p31 = 0; float p32 = -1.f; float p33 = 0.f;
return {p00, p01, p02, p03, p10, p11, p12, p13, p20, p21, p22, p23, p30, p31, p32, p33};
}
}

View File

@@ -4,7 +4,7 @@
#include <J3ML/LinearAlgebra/Matrix4x4.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
Quaternion Quaternion::operator-() const
{
return {-x, -y, -z, -w};
@@ -47,7 +47,18 @@ namespace LinearAlgebra {
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 {
@@ -172,4 +183,22 @@ namespace LinearAlgebra {
Matrix4x4 Quaternion::ToMatrix4x4(const Vector3 &translation) const {
return {*this, translation};
}
float Quaternion::GetAngle() const {
return std::acos(w) * 2.f;
}
Vector3 Quaternion::GetAxis() const {
float rcpSinAngle = 1 - (std::sqrt(1 - w * w));
return Vector3(x, y, z) * rcpSinAngle;
}
Quaternion::Quaternion(const Vector3 &rotationAxis, float rotationAngleBetween) {
SetFromAxisAngle(rotationAxis, rotationAngleBetween);
}
Quaternion::Quaternion(const Vector4 &rotationAxis, float rotationAngleBetween) {
SetFromAxisAngle(rotationAxis, rotationAngleBetween);
}
}

View File

@@ -1,6 +1,6 @@
#include <J3ML/LinearAlgebra/Transform2D.h>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
const Transform2D Transform2D::Identity = Transform2D({0, 0}, {1, 1}, {0,0}, {0,0}, 0);
const Transform2D Transform2D::FlipX = Transform2D({0, 0}, {-1, 1}, {0,0}, {0,0}, 0);

View File

@@ -4,7 +4,7 @@
#include <valarray>
#include <iostream>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
Vector2::Vector2(): x(0), y(0)
{}
@@ -15,13 +15,16 @@ namespace LinearAlgebra {
Vector2::Vector2(const Vector2& rhs): x(rhs.x), y(rhs.y)
{}
float Vector2::operator[](std::size_t index)
float Vector2::operator[](std::size_t index) const
{
assert(index < 2);
if (index == 0) return x;
if (index == 1) return y;
return 0;
return At(index);
}
float &Vector2::operator[](std::size_t index)
{
return At(index);
}
bool Vector2::IsWithinMarginOfError(const Vector2& rhs, float margin) const
{
return this->Distance(rhs) <= margin;
@@ -253,4 +256,72 @@ namespace LinearAlgebra {
Vector2 Vector2::Div(const Vector2 &v) const {
return {this->x/v.x, this->y/v.y};
}
Vector2 Vector2::Abs() const { return {std::abs(x), std::abs(y)};}
float *Vector2::ptr() {
return &x;
}
const float *Vector2::ptr() const { return &x;}
const float Vector2::At(std::size_t index) const {
assert(index >= 0);
assert(index < Dimensions);
return ptr()[index];
}
float &Vector2::At(std::size_t index) {
assert(index >= 0);
assert(index < Dimensions);
return ptr()[index];
}
Vector2 &Vector2::operator/=(float scalar) {
x /= scalar;
y /= scalar;
return *this;
}
Vector2 &Vector2::operator*=(float scalar) {
x *= scalar;
y *= scalar;
return *this;
}
Vector2 &Vector2::operator-=(const Vector2 &rhs) // Subtracts a vector from this vector, in-place
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
Vector2 &Vector2::operator+=(const Vector2 &rhs) // Adds a vector to this vector, in-place.
{
x += rhs.x;
y += rhs.y;
return *this;
}
Vector2 &Vector2::operator=(const Vector2 &rhs) {
x = rhs.x;
y = rhs.y;
return *this;
}
Vector2::Vector2(const float *data) {
assert(data);
x = data[0];
y = data[1];
}
Vector2::Vector2(float scalar) {
x = scalar;
y = scalar;
}
}

View File

@@ -3,9 +3,7 @@
#include <cassert>
#include <cmath>
namespace LinearAlgebra {
#pragma region vector3
namespace J3ML::LinearAlgebra {
const Vector3 Vector3::Zero = {0,0,0};
const Vector3 Vector3::Up = {0, -1, 0};
@@ -15,6 +13,8 @@ namespace LinearAlgebra {
const Vector3 Vector3::Forward = {0, 0, -1};
const Vector3 Vector3::Backward = {0, 0, 1};
const Vector3 Vector3::NaN = {NAN, NAN, NAN};
const Vector3 Vector3::Infinity = {INFINITY, INFINITY, INFINITY};
const Vector3 Vector3::NegativeInfinity = {-INFINITY, -INFINITY, -INFINITY};
Vector3 Vector3::operator+(const Vector3& rhs) const
{
@@ -80,6 +80,14 @@ namespace LinearAlgebra {
return 0;
}
float &Vector3::operator[](std::size_t index)
{
assert(index < 3);
if (index == 0) return x;
if (index == 1) return y;
if (index == 2) return z;
}
bool Vector3::IsWithinMarginOfError(const Vector3& rhs, float margin) const
{
return this->Distance(rhs) <= margin;
@@ -308,5 +316,42 @@ namespace LinearAlgebra {
return {x, y, z};
}
#pragma endregion
Vector3 Vector3::Abs() const {
return {std::abs(x), std::abs(y), std::abs(z)};
}
float *Vector3::ptr() {
return &x;
}
void Vector3::Orthonormalize(Vector3 &a, Vector3 &b) {
a = a.Normalize();
b = b - b.ProjectToNorm(a);
b = b.Normalize();
}
void Vector3::Orthonormalize(Vector3 &a, Vector3 &b, Vector3 &c) {
a = a.Normalize();
b = b - b.ProjectToNorm(a);
b = b.Normalize();
c = c - c.ProjectToNorm(a);
c = c - c.ProjectToNorm(b);
c = c.Normalize();
}
Vector3 Vector3::ProjectToNorm(const Vector3 &direction) const {
return direction * this->Dot(direction);
}
bool Vector3::IsFinite() const {
return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
}
Vector3::Vector3(const float *data) {
x = data[0];
y = data[1];
z = data[2];
}
}

View File

@@ -7,7 +7,7 @@
#include <cmath>
#include <algorithm>
namespace LinearAlgebra {
namespace J3ML::LinearAlgebra {
const Vector4 Vector4::Zero = {0,0,0,0};
const Vector4 Vector4::NaN = {NAN, NAN, NAN, NAN};

View File

@@ -1,7 +1,7 @@
#include <gtest/gtest.h>
#include <J3ML/LinearAlgebra/Vector2.h>
using Vector2 = LinearAlgebra::Vector2;
using J3ML::LinearAlgebra::Vector2;
TEST(Vector2Test, V2_Constructor_Default)
{

View File

@@ -1,7 +1,7 @@
#include <gtest/gtest.h>
#include <J3ML/LinearAlgebra/Vector3.h>
using Vector3 = LinearAlgebra::Vector3;
using J3ML::LinearAlgebra::Vector3;
void EXPECT_V3_EQ(const Vector3& lhs, const Vector3& rhs)
{
@@ -185,11 +185,12 @@ TEST(Vector3Test, V3_Lerp)
EXPECT_V3_EQ(Start.Lerp(Finish, Percent), ExpectedResult);
}
TEST(Vector3Test, V3_AngleBetween) {
using J3ML::LinearAlgebra::Angle2D;
Vector3 A{ .5f, .5f, .5f};
Vector3 B {.25f, .75f, .25f};
A = A.Normalize();
B = B.Normalize();
LinearAlgebra::Angle2D ExpectedResult {-0.69791365, -2.3561945};
Angle2D ExpectedResult {-0.69791365, -2.3561945};
std::cout << A.AngleBetween(B).x << ", " << A.AngleBetween(B).y << "";
auto angle = A.AngleBetween(B);
EXPECT_FLOAT_EQ(angle.x, ExpectedResult.x);

View File

@@ -1,7 +1,7 @@
#include <gtest/gtest.h>
#include <J3ML/LinearAlgebra/Vector4.h>
using Vector4 = LinearAlgebra::Vector4;
using Vector4 = J3ML::LinearAlgebra::Vector4;
void EXPECT_V4_EQ(const Vector4& lhs, const Vector4& rhs)