Compare commits

...

5 Commits

Author SHA1 Message Date
21ceca62dc Adding more Mat4x4 functionality 2024-01-30 13:13:09 -05:00
32577f79b8 Header implementations 2024-01-29 14:50:00 -05:00
e76a0954d3 Implement Vector-to-Vector Multiplication + division 2024-01-29 14:43:51 -05:00
47b25c695f Partial Implement QuadTree 2024-01-29 14:43:26 -05:00
6c7d63e467 Implement AABB2D 2024-01-29 03:16:50 -05:00
17 changed files with 401 additions and 86 deletions

View File

@@ -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})

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@
namespace Geometry
{
using LinearAlgebra::Vector3;
class LineSegment
{
Vector3 A;

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
#pragma once
namespace Geometry
{
class Polyhedron {
};
}

View File

@@ -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();
}
}
}

View File

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

View File

@@ -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];

View File

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

View File

@@ -1,3 +1,5 @@
//
// Created by dawsh on 1/25/24.
//
#include <J3ML/Geometry/LineSegment.h>
namespace Geometry {
}

View File

@@ -0,0 +1,5 @@
#include <J3ML/Geometry/Polygon.h>
namespace Geometry {
}

View File

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

View File

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

View File

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