Compare commits
5 Commits
Prerelease
...
Prerelease
Author | SHA1 | Date | |
---|---|---|---|
21ceca62dc | |||
32577f79b8 | |||
e76a0954d3 | |||
47b25c695f | |||
6c7d63e467 |
@@ -54,7 +54,10 @@ add_library(J3ML SHARED ${J3ML_SRC}
|
||||
src/J3ML/Geometry/TriangleMesh.cpp
|
||||
src/J3ML/Geometry/QuadTree.cpp
|
||||
src/J3ML/Geometry/LineSegment.cpp
|
||||
include/J3ML/Geometry/AABB2D.h)
|
||||
include/J3ML/Geometry/AABB2D.h
|
||||
src/J3ML/Geometry/Polygon.cpp
|
||||
include/J3ML/Geometry/Polyhedron.h
|
||||
src/J3ML/Geometry/Polyhedron.cpp)
|
||||
set_target_properties(J3ML PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})
|
||||
|
@@ -1,15 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||
#include "Plane.h"
|
||||
#include "Sphere.h"
|
||||
#include "OBB.h"
|
||||
#include "LineSegment.h"
|
||||
#include <J3ML/Geometry/Plane.h>
|
||||
#include <J3ML/Geometry/Sphere.h>
|
||||
#include <J3ML/Geometry/OBB.h>
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
#include <J3ML/Geometry/Triangle.h>
|
||||
#include <J3ML/Geometry/Polygon.h>
|
||||
#include <J3ML/Geometry/Frustum.h>
|
||||
#include <J3ML/Geometry/Capsule.h>
|
||||
#include <J3ML/Geometry/Ray.h>
|
||||
#include <J3ML/Geometry/TriangleMesh.h>
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
|
||||
|
||||
// TODO: Fix circular include between AABB and OBB
|
||||
|
||||
|
||||
using namespace LinearAlgebra;
|
||||
|
||||
namespace 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
|
||||
// computations can be avoided. In physics systems, bounding boxes are used as an efficient early-out test for geometry
|
||||
|
@@ -12,6 +12,7 @@ namespace Geometry
|
||||
|
||||
Vector2 minPoint;
|
||||
Vector2 maxPoint;
|
||||
AABB2D() {}
|
||||
AABB2D(const Vector2& min, const Vector2& max):
|
||||
minPoint(min), maxPoint(max)
|
||||
{}
|
||||
@@ -33,7 +34,7 @@ namespace Geometry
|
||||
maxPoint = Vector2::Max(maxPoint, point);
|
||||
}
|
||||
|
||||
bool Intersects(const AABB2D &rhs) const
|
||||
bool Intersects(const AABB2D& rhs) const
|
||||
{
|
||||
return maxPoint.x >= rhs.minPoint.x &&
|
||||
maxPoint.y >= rhs.minPoint.y &&
|
||||
@@ -41,13 +42,13 @@ namespace Geometry
|
||||
rhs.maxPoint.y >= minPoint.y;
|
||||
}
|
||||
|
||||
bool Contains(const AABB2D &rhs) const
|
||||
bool Contains(const AABB2D& rhs) const
|
||||
{
|
||||
return rhs.minPoint.x >= minPoint.x && rhs.minPoint.y >= minPoint.y
|
||||
&& rhs.maxPoint.x <= maxPoint.x && rhs.maxPoint.y <= maxPoint.y;
|
||||
}
|
||||
|
||||
bool Contains(const vec2d &pt) const
|
||||
bool Contains(const Vector2& pt) const
|
||||
{
|
||||
return pt.x >= minPoint.x && pt.y >= minPoint.y
|
||||
&& pt.x <= maxPoint.x && pt.y <= maxPoint.y;
|
||||
@@ -79,9 +80,27 @@ namespace Geometry
|
||||
return minPoint + normalizedPos.Mul(maxPoint - minPoint);
|
||||
}
|
||||
|
||||
Vector2 ToNormalizedLocalSpace(const vec2d &pt) const
|
||||
Vector2 ToNormalizedLocalSpace(const Vector2 &pt) const
|
||||
{
|
||||
return (pt - minPoint).Div(maxPoint - minPoint);
|
||||
}
|
||||
|
||||
|
||||
AABB2D operator+(const Vector2& pt) const
|
||||
{
|
||||
AABB2D a;
|
||||
a.minPoint = minPoint + pt;
|
||||
a.maxPoint = maxPoint + pt;
|
||||
return a;
|
||||
}
|
||||
|
||||
AABB2D operator-(const Vector2& pt) const
|
||||
{
|
||||
AABB2D a;
|
||||
a.minPoint = minPoint - pt;
|
||||
a.maxPoint = maxPoint - pt;
|
||||
return a;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Plane.h"
|
||||
#include <J3ML/LinearAlgebra/CoordinateFrame.h>
|
||||
|
||||
namespace Geometry
|
||||
{
|
||||
@@ -32,11 +33,10 @@ namespace Geometry
|
||||
Plane LeftFace;
|
||||
Plane FarFace;
|
||||
Plane NearFace;
|
||||
static Frustum CreateFrustumFromCamera(const Camera& cam, float aspect, float fovY, float zNear, float zFar);
|
||||
|
||||
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
|
||||
};
|
||||
|
||||
Frustum Frustum::CreateFrustumFromCamera(const Camera &cam, float aspect, float fovY, float zNear, float zFar) {
|
||||
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;
|
||||
@@ -51,5 +51,4 @@ namespace Geometry
|
||||
frustum.BottomFace = Plane{cam.Position, Vector3::Cross(frontMultFar + cam.Up * halfVSide, cam.Right)};
|
||||
return frustum;
|
||||
}
|
||||
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
|
||||
namespace Geometry
|
||||
{
|
||||
using LinearAlgebra::Vector3;
|
||||
class LineSegment
|
||||
{
|
||||
Vector3 A;
|
||||
|
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "AABB.h"
|
||||
#include <J3ML/Geometry/AABB.h>
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
|
||||
namespace Geometry {
|
||||
class OBB
|
||||
@@ -15,14 +17,14 @@ namespace Geometry {
|
||||
|
||||
OBB() {}
|
||||
OBB(const Vector3& pos, const Vector3& radii, const Vector3& axis0, const Vector3& axis1, const Vector3& axis2);
|
||||
OBB(const AABB& aabb);
|
||||
OBB(const Geometry::AABB& aabb);
|
||||
inline static int NumFaces() { return 6; }
|
||||
inline static int NumEdges() { return 12; }
|
||||
inline static int NumVertices() { return 8; }
|
||||
|
||||
Polyhedron ToPolyhedron() const;
|
||||
|
||||
AABB MinimalEnclosingAABB() const;
|
||||
Geometry::AABB MinimalEnclosingAABB() const;
|
||||
|
||||
Sphere MinimalEnclosingSphere() const;
|
||||
Sphere MaximalContainedSphere() const;
|
||||
@@ -39,7 +41,7 @@ namespace Geometry {
|
||||
|
||||
float Volume();
|
||||
float SurfaceArea();
|
||||
LineSegment Edge(int edgeIndex) const;
|
||||
Geometry::LineSegment Edge(int edgeIndex) const;
|
||||
Vector3 CornerPoint(int cornerIndex) const;
|
||||
};
|
||||
}
|
@@ -1,8 +1,7 @@
|
||||
//
|
||||
// Created by dawsh on 1/25/24.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#ifndef J3ML_POLYGON_H
|
||||
#define J3ML_POLYGON_H
|
||||
namespace Geometry {
|
||||
class Polygon {
|
||||
|
||||
#endif //J3ML_POLYGON_H
|
||||
};
|
||||
}
|
8
include/J3ML/Geometry/Polyhedron.h
Normal file
8
include/J3ML/Geometry/Polyhedron.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace Geometry
|
||||
{
|
||||
class Polyhedron {
|
||||
|
||||
};
|
||||
}
|
@@ -5,15 +5,13 @@
|
||||
#include <J3ML/LinearAlgebra/Vector2.h>
|
||||
#include "AABB2D.h"
|
||||
|
||||
namespace Geometry
|
||||
{
|
||||
namespace Geometry {
|
||||
using LinearAlgebra::Vector2;
|
||||
template <typename T>
|
||||
class QuadTree
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class QuadTree {
|
||||
public:
|
||||
struct Node
|
||||
{
|
||||
struct Node {
|
||||
Node *parent;
|
||||
uint32_t childIndex;
|
||||
std::vector<T> objects;
|
||||
@@ -21,19 +19,22 @@ namespace Geometry
|
||||
Vector2 center;
|
||||
Vector2 radius;
|
||||
|
||||
bool IsLeaf() const { return childIndex == 0xFFFFFFFF;}
|
||||
bool IsLeaf() const { return childIndex == 0xFFFFFFFF; }
|
||||
|
||||
uint32_t TopLeftChildIndex() const { return childIndex;}
|
||||
uint32_t TopRightChildIndex() const { return childIndex+1;}
|
||||
uint32_t BottomLeftChildIndex() const { return childIndex+2;}
|
||||
uint32_t BottomRightChildIndex() const { return childIndex+3;}
|
||||
uint32_t TopLeftChildIndex() const { return childIndex; }
|
||||
|
||||
uint32_t TopRightChildIndex() const { return childIndex + 1; }
|
||||
|
||||
uint32_t BottomLeftChildIndex() const { return childIndex + 2; }
|
||||
|
||||
uint32_t BottomRightChildIndex() const { return childIndex + 3; }
|
||||
|
||||
/// This assumes that the QuadTree contains unique objects and never duplicates
|
||||
void Remove(const T &object)
|
||||
{
|
||||
for (size_t i = 0; i < objects.size(); ++i){
|
||||
void Remove(const T &object) {
|
||||
for (size_t i = 0; i < objects.size(); ++i) {
|
||||
if (objects[i] == object) {
|
||||
AssociateQuadTreeNode(object, 0); // Mark in the object that it has been removed from the QuadTree.
|
||||
AssociateQuadTreeNode(object,
|
||||
0); // Mark in the object that it has been removed from the QuadTree.
|
||||
std::swap(objects[i], objects.back());
|
||||
objects.pop_back();
|
||||
return;
|
||||
@@ -41,11 +42,9 @@ namespace Geometry
|
||||
}
|
||||
}
|
||||
|
||||
AABB2D ComputeAABB()
|
||||
{}
|
||||
AABB2D ComputeAABB() {}
|
||||
|
||||
float DistanceSq(const Vector2& point) const
|
||||
{
|
||||
float DistanceSq(const Vector2 &point) const {
|
||||
Vector2 centered = point - center;
|
||||
Vector2 closestPoint = centered.Clamp(-radius, radius);
|
||||
return closestPoint.DistanceSq(centered);
|
||||
@@ -54,30 +53,28 @@ namespace Geometry
|
||||
};
|
||||
|
||||
// Helper struct used when traversing through the tree
|
||||
struct TraversalStackItem
|
||||
{
|
||||
struct TraversalStackItem {
|
||||
Node *node;
|
||||
};
|
||||
|
||||
QuadTree():
|
||||
rootNodeIndex(-1),
|
||||
boundingAABB(Vector2(0,0), Vector2(0,0))
|
||||
{
|
||||
QuadTree() :
|
||||
rootNodeIndex(-1),
|
||||
boundingAABB(Vector2(0, 0), Vector2(0, 0)) {
|
||||
// TODO: currently storing persistent raw pointers to this array outside the array
|
||||
nodes.reserve(200000);
|
||||
}
|
||||
|
||||
/// Removes all nodes and objects in this tree and reintializes the tree to a single root node.
|
||||
void Clear(const Vector2& minXY = Vector2(-1, -1), const Vector2& maxXY = Vector2(1, 1));
|
||||
void Clear(const Vector2 &minXY = Vector2(-1, -1), const Vector2 &maxXY = Vector2(1, 1));
|
||||
|
||||
/// Places the given object onto the proper (leaf) node of the tree. After placing, if the leaf split rule is
|
||||
/// satisfied, subdivides the leaf node into 4 subquadrants and reassings the objects to the new leaves.
|
||||
void Add(const T& object);
|
||||
void Add(const T &object);
|
||||
|
||||
/// Removes the given object from this tree.
|
||||
/// To call this function, you must define a function QuadTree<T>::Node *GetQuadTreeNode(const T& object)
|
||||
/// which returns the node of this quadtree where the object resides in.
|
||||
void Remove(const T& object);
|
||||
void Remove(const T &object);
|
||||
|
||||
/// @return The bounding rectangle for the whole tree.
|
||||
/// @note This bounding rectangle does not tightly bound the objects themselves, only the root node of the tree.
|
||||
@@ -85,6 +82,7 @@ namespace Geometry
|
||||
|
||||
/// @return The topmost node in the tree.
|
||||
Node *Root();
|
||||
|
||||
const Node *Root() const;
|
||||
|
||||
/// Returns the total number of nodes (all nodes, i.e. inner nodes + leaves) in the tree.
|
||||
@@ -123,6 +121,7 @@ namespace Geometry
|
||||
/// specified callback function.
|
||||
template<typename Func>
|
||||
inline void CollidingPairsQuery(const AABB2D &aabb, Func &callback);
|
||||
|
||||
/// Performs various consistency checks on the given node. Use only for debugging purposes.
|
||||
void DebugSanityCheckNode(Node *n);
|
||||
|
||||
@@ -139,8 +138,11 @@ namespace Geometry
|
||||
AABB2D boundingAABB;
|
||||
|
||||
void GrowRootTopLeft();
|
||||
|
||||
void GrowRootTopRight();
|
||||
|
||||
void GrowRootBottomLeft();
|
||||
|
||||
void GrowRootBottomRight();
|
||||
|
||||
void GrowImpl(int quadrantForRoot);
|
||||
@@ -151,9 +153,8 @@ namespace Geometry
|
||||
// but the presence of the implementation file is a requirement
|
||||
|
||||
|
||||
template <typename T>
|
||||
void QuadTree<T>::Clear(const Vector2& minXY, const Vector2& maxXY)
|
||||
{
|
||||
template<typename T>
|
||||
void QuadTree<T>::Clear(const Vector2 &minXY, const Vector2 &maxXY) {
|
||||
nodes.clear();
|
||||
|
||||
boundingAABB.minPoint = minXY;
|
||||
@@ -165,4 +166,193 @@ namespace Geometry
|
||||
root->center = (minXY + maxXY) * 0.5f;
|
||||
root->radius = maxXY - root->center;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void QuadTree<T>::Add(const T &object) {
|
||||
Node *n = Root();
|
||||
AABB2D objectAABB = GetAABB2D(object);
|
||||
|
||||
// Ramen Noodle Bowls of nested if statements are generally bad practice
|
||||
// Unfortunately, sometimes the problem domain makes this unavoidable
|
||||
|
||||
if (objectAABB.minPoint.x >= boundingAABB.minPoint.x) {
|
||||
// object fits left.
|
||||
if (objectAABB.maxPoint.x <= boundingAABB.maxPoint.x) {
|
||||
// object fits left and right.
|
||||
if (objectAABB.minPoint.y >= boundingAABB.minPoint.y) {
|
||||
// Object fits left, right, and top.
|
||||
if (objectAABB.maxPoint.y <= boundingAABB.maxPoint.y) {
|
||||
// Object fits the whole root AABB. Can safely add into the existing tree size.
|
||||
AddObject(object, n);
|
||||
return;
|
||||
} else {
|
||||
// Object fits left, right, and top, but not bottom.
|
||||
GrowRootBottomRight(); // Could grow bottom-left as well, wouldn't matter here.
|
||||
}
|
||||
} else {
|
||||
// Object fits left and right, but not to top.
|
||||
GrowRootTopRight(); // Could grow top-left as well, wouldn't matter here.
|
||||
}
|
||||
} else {
|
||||
// Object fits left, but not to right. We must grow right. Check whether to grow top or bottom;
|
||||
if (objectAABB.minPoint.y < boundingAABB.minPoint.y)
|
||||
GrowRootTopRight();
|
||||
else
|
||||
GrowRootBottomRight();
|
||||
}
|
||||
} else {
|
||||
// We must grow left. Check whether to grow top or bottom.
|
||||
if (objectAABB.minPoint.y < boundingAABB.minPoint.y)
|
||||
GrowRootTopLeft();
|
||||
else
|
||||
GrowRootBottomLeft();
|
||||
}
|
||||
// Now that we have grown the tree root node, try adding again.
|
||||
Add(object);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void QuadTree<T>::Remove(const T &object) {
|
||||
Node *n = GetQuadTreeNode(object);
|
||||
if (n) {
|
||||
n->Remove(object);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void QuadTree<T>::Add(const T &object, Node *n) {
|
||||
for (;;) {
|
||||
// Traverse the QuadTree to decide which quad to place this object on.
|
||||
float left = n->center.x - MinX(object); // If left > 0.f, then the object overlaps with the left quadrant.
|
||||
float right = MaxX(object) - n->center.x; // If right > 0.f, then the object overlaps with the right quadrant.
|
||||
|
||||
float top = n->center.y - MinY(object); // If top > 0.f, then the object overlaps with the top quadrant
|
||||
float bottom =
|
||||
MaxY(object) - n->center.y; // If bottom > 0.f, then the object overlaps with the bottom quadrant
|
||||
float leftAndRight = std::min(left, right); // If > 0.f, then the object straddles left-right halves.
|
||||
float topAndBottom = std::min(top, bottom); // If > 0.f, then the object straddles top-bottom halves.
|
||||
float straddledEitherOne = std::max(leftAndRight,
|
||||
topAndBottom); // If > 0.f, thne the object is in two or more quadrants.
|
||||
|
||||
// Note: It can happen that !left && !right, or !top && !bottom.
|
||||
// but the if()s are setup below so that right/bottom is taken if no left/top, so that is ok.
|
||||
|
||||
// We must put the object onto this node if
|
||||
// a) the object straddled the parent->child split lines.
|
||||
// b) this object is a leaf
|
||||
if (straddledEitherOne > 0.f) {
|
||||
n->objects.push_back(object);
|
||||
AssociateQuadTreeNode(object, n);
|
||||
return;
|
||||
}
|
||||
if (n->IsLeaf()) {
|
||||
n->objects.push_back(object);
|
||||
AssociateQuadTreeNode(object, n);
|
||||
|
||||
if ((int) n->objects.size() > minQuadTreeNodeObjectCount &&
|
||||
std::min(n->radius.x, n->radius.y) >= minQuadTreeQuadrantSize) {
|
||||
SplitLeaf(n);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (left > 0.f) {
|
||||
if (top > 0.f) {
|
||||
n = &nodes[n->TopLeftChildIndex()];
|
||||
} else {
|
||||
n = &nodes[n->BottomLeftChildIndex()];
|
||||
}
|
||||
} else {
|
||||
if (top > 0.f) {
|
||||
n = &nodes[n->TopRightChildIndex()];
|
||||
} else {
|
||||
n = &nodes[n->BottomRightChildIndex()];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename QuadTree<T>::Node *QuadTree<T>::Root() {
|
||||
return nodes.empty() ? 0 : &nodes[rootNodeIndex];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const typename QuadTree<T>::Node *QuadTree<T>::Root() const {
|
||||
return nodes.empty() ? 0 : &nodes[rootNodeIndex];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int QuadTree<T>::AllocateNodeGroup(Node* parent) {
|
||||
size_t oldCap = nodes.capacity();
|
||||
|
||||
int index = (int)nodes.size();
|
||||
Node n;
|
||||
n.parent = parent;
|
||||
n.childIndex = 0xFFFFFFFF;
|
||||
if (parent) {
|
||||
n.radius = parent->radius * 0.5f;
|
||||
n.center = parent->center - n.radius;
|
||||
}
|
||||
|
||||
nodes.push_back(n);
|
||||
if (parent)
|
||||
n.center.x = parent->center.x + n.radius.x;
|
||||
nodes.push_back(n);
|
||||
|
||||
if (parent) {
|
||||
n.center.x = parent->center.x - n.radius.x;
|
||||
n.center.y = parent->center.y + n.radius.y;
|
||||
}
|
||||
|
||||
nodes.push_back(n);
|
||||
if (parent)
|
||||
n.center.x = parent->center.x + n.radius.x;
|
||||
nodes.push_back(n);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void QuadTree<T>::SplitLeaf(Node *leaf) {
|
||||
leaf->childIndex = AllocateNodeGroup(leaf);
|
||||
|
||||
size_t i = 0;
|
||||
while (i < leaf->objects.size()) {
|
||||
const T& object = leaf->objects[i];
|
||||
|
||||
// Traverse the QuadTree to decide which quad to place this object into
|
||||
float left = leaf->center.x - MinX(object);
|
||||
float right = MaxX(object) - leaf->center;
|
||||
float top = leaf->center.y - MinY(object);
|
||||
float bottom = MaxY(object) - leaf->center.y;
|
||||
float leftAndRight = std::min(left, right);
|
||||
float topAndBottom = std::min(top, bottom);
|
||||
|
||||
float straddledEitherOne = std::max(leftAndRight, topAndBottom);
|
||||
|
||||
if (straddledEitherOne > 0.f) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (left > 0.f) {
|
||||
if (top > 0.f) {
|
||||
Add(object, &nodes[leaf->TopLeftChildIndex()]);
|
||||
} else {
|
||||
Add(object, &nodes[leaf->BottomLeftChildIndex()]);
|
||||
}
|
||||
} else {
|
||||
if (top > 0.f) {
|
||||
Add(object, &nodes[leaf->TopRightChildIndex()]);
|
||||
} else {
|
||||
Add(object, &nodes[leaf->BottomRightChildIndex()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the object we added to a child from this node.
|
||||
leaf->objects[i] = leaf->objects.back();
|
||||
leaf->objects.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,20 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra.h>
|
||||
#include <J3ML/LinearAlgebra/Vector3.h>
|
||||
|
||||
namespace LinearAlgebra
|
||||
{
|
||||
/// The CFrame is fundamentally 4 vectors (position, forward, right, up vector)
|
||||
class CoordinateFrame
|
||||
{
|
||||
Vector3 getPosition();
|
||||
Vector3 getLookVector();
|
||||
Vector3 getRightVector();
|
||||
Vector3 getUpVector();
|
||||
AxisAngle GetAxisAngle();
|
||||
EulerAngle GetEulerAngleXYZ();
|
||||
EulerAngle GetWorldAngleYZX();
|
||||
Vector3 Position;
|
||||
Vector3 Front;
|
||||
Vector3 Right;
|
||||
Vector3 Up;
|
||||
};
|
||||
|
||||
|
||||
}
|
@@ -23,24 +23,38 @@ namespace LinearAlgebra {
|
||||
enum { Rows = 4 };
|
||||
enum { Cols = 4 };
|
||||
|
||||
// A constant matrix that has zeroes in all its entries
|
||||
/// A constant matrix that has zeroes in all its entries
|
||||
static const Matrix4x4 Zero;
|
||||
// A constant matrix that is the identity.
|
||||
/// A constant matrix that is the identity.
|
||||
static const Matrix4x4 Identity;
|
||||
|
||||
// A compile-time constant float4x4 which has NaN in each element.
|
||||
// For this constant, each element has the value of quet NaN, or Not-A-Number.
|
||||
// Never compare a matrix to this value. Due to how IEEE floats work, "nan == nan" returns false!
|
||||
/// A compile-time constant float4x4 which has NaN in each element.
|
||||
/// For this constant, each element has the value of quet NaN, or Not-A-Number.
|
||||
/// Never compare a matrix to this value. Due to how IEEE floats work, "nan == nan" returns false!
|
||||
static const Matrix4x4 NaN;
|
||||
|
||||
/// Creates a new float4x4 with uninitialized member values.
|
||||
Matrix4x4() {}
|
||||
Matrix4x4(float val);
|
||||
/// Constructs this float4x4 to represent the same transformation as the given float3x3.
|
||||
/** This function expands the last row and column of this matrix with the elements from the identity matrix. */
|
||||
Matrix4x4(const Matrix3x3&);
|
||||
|
||||
/// Constructs a new float4x4 by explicitly specifying all the matrix elements.
|
||||
/// The elements are specified in row-major format, i.e. the first row first followed by the second and third row.
|
||||
/// E.g. The element _10 denotes the scalar at second (index 1) row, first (index 0) column.
|
||||
Matrix4x4(float m00, float m01, float m02, float m03,
|
||||
float m10, float m11, float m12, float m13,
|
||||
float m20, float m21, float m22, float m23,
|
||||
float m30, float m31, float m32, float m33);
|
||||
/// Constructs the matrix by explicitly specifying the four column vectors.
|
||||
/** @param col0 The first column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local X axis.
|
||||
@param col1 The second column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local Y axis.
|
||||
@param col2 The third column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local Z axis.
|
||||
@param col3 The fourth column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
position of the local space pivot. */
|
||||
Matrix4x4(const Vector4& r1, const Vector4& r2, const Vector4& r3, const Vector4& r4);
|
||||
|
||||
|
||||
@@ -70,10 +84,15 @@ namespace LinearAlgebra {
|
||||
|
||||
Vector4 GetRow(int index) const;
|
||||
Vector4 GetColumn(int index) const;
|
||||
float At(int x, int y) const
|
||||
{
|
||||
return elems[x][y];
|
||||
}
|
||||
float At(int x, int y) const;
|
||||
|
||||
/// Tests if this matrix does not contain any NaNs or infs.
|
||||
/** @return Returns true if the entries of this float4x4 are all finite, and do not contain NaN or infs. */
|
||||
bool IsFinite() const;
|
||||
|
||||
/// Tests if this matrix has an inverse.
|
||||
/** @return Returns true if this matrix can be inverted, up to the given epsilon. */
|
||||
bool IsInvertible(float epsilon = 1e-3f) const;
|
||||
|
||||
Vector4 Diagonal() const;
|
||||
Vector4 WorldX() const;
|
||||
@@ -84,10 +103,7 @@ namespace LinearAlgebra {
|
||||
// If the determinant is nonzero, this matrix is invertible.
|
||||
float Determinant() const;
|
||||
|
||||
Matrix4x4 Inverse() const
|
||||
{
|
||||
|
||||
}
|
||||
Matrix4x4 Inverse() const;
|
||||
|
||||
Matrix4x4 Transpose() const;
|
||||
|
||||
@@ -117,6 +133,53 @@ namespace LinearAlgebra {
|
||||
return Vector4{elems[row][0], elems[row][1], elems[row][2], elems[row][3]};
|
||||
}
|
||||
|
||||
Matrix4x4 operator-() const;
|
||||
Matrix4x4 operator +(const Matrix4x4& rhs) const;
|
||||
Matrix4x4 operator - (const Matrix4x4& rhs) const;
|
||||
|
||||
Matrix4x4 operator *(float scalar) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Vector2 operator * (const Vector2& rhs) const;
|
||||
Vector3 operator * (const Vector3& rhs) const;
|
||||
Vector4 operator * (const Vector4& rhs) const;
|
||||
|
||||
Matrix4x4 operator * (const Matrix3x3 &rhs) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Matrix4x4 operator +() const { return *this; }
|
||||
|
||||
Matrix4x4 operator * (const Matrix4x4& rhs) const
|
||||
{
|
||||
|
||||
|
||||
float r00 = At(0, 0) * rhs.At(0, 0) + At(0, 1) * rhs.At(1, 0) + At(0, 2) * rhs.At(2, 0) + At(0, 3) * rhs.At(3, 0);
|
||||
float r01 = At(0, 0) * rhs.At(0, 1) + At(0, 1) * rhs.At(1, 1) + At(0, 2) * rhs.At(2, 1) + At(0, 3) * rhs.At(3, 1);
|
||||
float r02 = At(0, 0) * rhs.At(0, 2) + At(0, 1) * rhs.At(1, 2) + At(0, 2) * rhs.At(2, 2) + At(0, 3) * rhs.At(3, 2);
|
||||
float r03 = At(0, 0) * rhs.At(0, 3) + At(0, 1) * rhs.At(1, 3) + At(0, 2) * rhs.At(2, 3) + At(0, 3) * rhs.At(3, 3);
|
||||
|
||||
float r10 = At(1, 0) * rhs.At(0, 0) + At(1, 1) * rhs.At(1, 0) + At(1, 2) * rhs.At(2, 0) + At(1, 3) * rhs.At(3, 0);
|
||||
float r11 = At(1, 0) * rhs.At(0, 1) + At(1, 1) * rhs.At(1, 1) + At(1, 2) * rhs.At(2, 1) + At(1, 3) * rhs.At(3, 1);
|
||||
float r12 = At(1, 0) * rhs.At(0, 2) + At(1, 1) * rhs.At(1, 2) + At(1, 2) * rhs.At(2, 2) + At(1, 3) * rhs.At(3, 2);
|
||||
float r13 = At(1, 0) * rhs.At(0, 3) + At(1, 1) * rhs.At(1, 3) + At(1, 2) * rhs.At(2, 3) + At(1, 3) * rhs.At(3, 3);
|
||||
|
||||
float r20 = At(2, 0) * rhs.At(0, 0) + At(2, 1) * rhs.At(1, 0) + At(2, 2) * rhs.At(2, 0) + At(2, 3) * rhs.At(3, 0);
|
||||
float r21 = At(2, 0) * rhs.At(0, 1) + At(2, 1) * rhs.At(1, 1) + At(2, 2) * rhs.At(2, 1) + At(2, 3) * rhs.At(3, 1);
|
||||
float r22 = At(2, 0) * rhs.At(0, 2) + At(2, 1) * rhs.At(1, 2) + At(2, 2) * rhs.At(2, 2) + At(2, 3) * rhs.At(3, 2);
|
||||
float r23 = At(2, 0) * rhs.At(0, 3) + At(2, 1) * rhs.At(1, 3) + At(2, 2) * rhs.At(2, 3) + At(2, 3) * rhs.At(3, 3);
|
||||
|
||||
float r30 = At(3, 0) * rhs.At(0, 0) + At(3, 1) * rhs.At(1, 0) + At(3, 2) * rhs.At(2, 0) + At(3, 3) * rhs.At(3, 0);
|
||||
float r31 = At(3, 0) * rhs.At(0, 1) + At(3, 1) * rhs.At(1, 1) + At(3, 2) * rhs.At(2, 1) + At(3, 3) * rhs.At(3, 1);
|
||||
float r32 = At(3, 0) * rhs.At(0, 2) + At(3, 1) * rhs.At(1, 2) + At(3, 2) * rhs.At(2, 2) + At(3, 3) * rhs.At(3, 2);
|
||||
float r33 = At(3, 0) * rhs.At(0, 3) + At(3, 1) * rhs.At(1, 3) + At(3, 2) * rhs.At(2, 3) + At(3, 3) * rhs.At(3, 3);
|
||||
return {r00,r01,r02,r03, r10, r11, r12, r13, r20,r21,r22,r23, r30,r31,r32,r33};
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
float elems[4][4];
|
||||
|
||||
|
@@ -112,16 +112,18 @@ namespace LinearAlgebra {
|
||||
/// Multiplies this vector by a vector, element-wise
|
||||
/// @note Mathematically, the multiplication of two vectors is not defined in linear space structures,
|
||||
/// but this function is provided here for syntactical convenience.
|
||||
Vector2 Mul(const Vector2& v) const
|
||||
{
|
||||
return {this->x*v.x, this->y*v.y};
|
||||
}
|
||||
Vector2 Mul(const Vector2& v) const;
|
||||
|
||||
/// Divides this vector by a scalar.
|
||||
Vector2 operator /(float rhs) const;
|
||||
Vector2 Div(float scalar) const;
|
||||
static Vector2 Div(const Vector2& lhs, float rhs);
|
||||
|
||||
/// Divides this vector by a vector, element-wise
|
||||
/// @note Mathematically, the multiplication of two vectors is not defined in linear space structures,
|
||||
/// but this function is provided here for syntactical convenience
|
||||
Vector2 Div(const Vector2& v) const;
|
||||
|
||||
/// Unary operator +
|
||||
Vector2 operator +() const; // TODO: Implement
|
||||
Vector2 operator -() const;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
//
|
||||
// Created by dawsh on 1/25/24.
|
||||
//
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
}
|
5
src/J3ML/Geometry/Polygon.cpp
Normal file
5
src/J3ML/Geometry/Polygon.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <J3ML/Geometry/Polygon.h>
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
}
|
6
src/J3ML/Geometry/Polyhedron.cpp
Normal file
6
src/J3ML/Geometry/Polyhedron.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
|
||||
namespace Geometry
|
||||
{
|
||||
|
||||
}
|
@@ -167,5 +167,9 @@ namespace LinearAlgebra {
|
||||
float p30 = 0; float p31 = 0; float p32 = 0.f; float p33 = 1.f;
|
||||
}
|
||||
|
||||
float Matrix4x4::At(int x, int y) const {
|
||||
return elems[x][y];
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -243,5 +243,9 @@ namespace LinearAlgebra {
|
||||
return std::max(x, y);
|
||||
}
|
||||
|
||||
Vector2 Vector2::Mul(const Vector2 &v) const {
|
||||
return {this->x*v.x, this->y*v.y};
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user