Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [ master, main ]
branches: [ master, main, work ]
pull_request:

jobs:
Expand Down
22 changes: 19 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_library(vectormatrix
VectorMatrixLib/Matrix3f.cpp
VectorMatrixLib/Matrix4f.cpp
VectorMatrixLib/Quaternionf.cpp
VectorMatrixLib/GeometryTools.cpp
)
target_include_directories(vectormatrix PUBLIC VectorMatrixLib)

Expand All @@ -21,12 +22,27 @@ else()
target_compile_options(vectormatrix PRIVATE -Wall -Wextra -Wpedantic)
endif()

# Demo program (same as the Visual Studio project)
add_executable(vectormatrix_demo VectorMatrixLib/TestMatrix.cpp)
# Console tour of the API (same program as the Visual Studio project)
add_executable(vectormatrix_demo VectorMatrixLib/VectorMatrixDemo.cpp)
target_link_libraries(vectormatrix_demo PRIVATE vectormatrix)

# Unit tests
enable_testing()
add_executable(vectormatrix_tests tests/TestVectorMatrix.cpp)
add_executable(vectormatrix_tests
tests/TestMain.cpp
tests/TestVectorMatrix.cpp
tests/TestVector2f.cpp
tests/TestVector3f.cpp
tests/TestVector4f.cpp
tests/TestMatrix2f.cpp
tests/TestMatrix3f.cpp
tests/TestMatrix4f.cpp
tests/TestQuaternionf.cpp
tests/TestGaussJordanSolver.cpp
tests/TestVector3fMatrix3f.cpp
tests/TestTools.cpp
tests/TestGeometryTools.cpp
)
target_include_directories(vectormatrix_tests PRIVATE tests)
target_link_libraries(vectormatrix_tests PRIVATE vectormatrix)
add_test(NAME vectormatrix_tests COMMAND vectormatrix_tests)
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# VectorMatrixLib

**A small C++17 vector, matrix and quaternion library for 3D graphics, ported from the math package of the [Aventura](https://github.com/obarry/Aventura) Java rendering engine.**

![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)
![C++17](https://img.shields.io/badge/C%2B%2B-17-blue.svg)
![Build: CMake | Visual Studio](https://img.shields.io/badge/build-CMake%20%7C%20Visual%20Studio-informational.svg)

VectorMatrixLib gives you the building blocks of a 3D pipeline: vectors and points in homogeneous coordinates, 2x2, 3x3 and 4x4 matrices with inversion, and quaternions for rotations. It has no dependency other than the C++ standard library, and it follows the same API and semantics as Aventura's `com.aventura.math.vector`, so code and tests move easily from one to the other.

## Highlights

- **Vectors:** `Vector2f`, `Vector3f`, `Vector4f` (points with `w = 1`, vectors with `w = 0`), with dot and cross products, length, distance, normalization and interpolation.
- **Matrices:** `Matrix2f`, `Matrix3f`, `Matrix4f`, with products, transpose, determinant, trace, rows and columns, and inversion by Gauss-Jordan elimination with partial pivoting.
- **Quaternions:** `Quaternionf` from an axis and an angle or from a rotation matrix, Hamilton product, conversion to matrices and to axis-angle, and `slerp`.
- **Helpers:** `Tools::interpolate` and `GeometryTools::center`.
- **Robust comparisons:** `==` and `!=` compare within `EPSILON` (`1e-4`), as in Aventura.
- **Clear errors:** out of bound indices, wrong array sizes and singular matrices throw exceptions derived from `Vector3DException`.
- **Tested:** about 230 unit tests, most of them ported from Aventura's JUnit tests, run by CI on Linux, Windows and macOS.

## Quick start

```cpp
#include <iostream>
#include "Matrix4f.h"
#include "Quaternionf.h"
#include "Vector4f.h"

using namespace vectormatrix;

int main()
{
// A point (w = 1) and a rotation of 90 degrees around the z axis
Vector4f p(1, 0, 0, 1);
Quaternionf q(Vector3f::zAxis(), 3.14159265f / 2);
Matrix4f r = q.toMatrix4();

// Translation of 10 along x, in the last column
Matrix4f t = Matrix4f::identity();
t.setColumn(3, Vector4f(10, 0, 0, 1));

Vector4f moved = t * r * p; // rotate, then translate: (10, 1, 0, 1)
Vector4f back = (t * r).inverse() * moved; // p again
std::cout << (back == p ? "round trip OK" : "KO") << std::endl;
}
```

The demo program prints a guided tour of the whole API, section by section (vectors, homogeneous coordinates, matrices and linear systems, transformations, quaternions and slerp, 2D, geometry helpers, errors). It is the best place to see the library in action.

## Build

### CMake (any platform)

```bash
cmake -S . -B build
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure # unit tests
./build/vectormatrix_demo # console tour (build/Release/ on Windows)
```

Targets:

| Target | What it is |
|---|---|
| `vectormatrix` | the static library |
| `vectormatrix_demo` | the console tour, `VectorMatrixLib/VectorMatrixDemo.cpp` |
| `vectormatrix_tests` | the unit tests, `tests/*.cpp` (an argument filters the suites, e.g. `vectormatrix_tests Matrix`) |

To use the library from your own CMake project, add this repository with `add_subdirectory` and link to `vectormatrix`; its include directory comes with it.

### Visual Studio

Open `VectorMatrixLib.sln` (VS 2019 or later, toolset v142, C++17): it builds the library and the demo. Visual Studio can also open the folder directly and use `CMakeLists.txt`, which includes the tests (Test Explorer runs them through CTest).

## Conventions

A few rules to know before using the library; [docs/API.md](docs/API.md) details all of them.

- **Matrices are row-major and act on column vectors:** `M * v` computes A·V. For compatibility with Aventura's `v.times(M)`, `v * M` computes the same A·V.
- **`*` between two vectors is the cross product**; the dot product is `dot()`.
- **Homogeneous coordinates:** `Vector4f` points have `w = 1` and vectors `w = 0`, so a translation matrix moves points and leaves vectors unchanged.
- **Comparisons use `EPSILON`:** `Vector3f(1, 2, 3) == Vector3f(1, 2, 3.00001f)` is true.
- **Index checks:** vector `get(i)`/`set(i, v)` and matrix rows and columns throw `IndexOutOfBoundException`; matrix `get(i, j)`/`set(i, j, v)` are not checked, for speed.
- **No null:** where Aventura returns `null`, the C++ API returns an empty `std::optional` (`Vector4f::get3DPoint`, `GeometryTools::center`).

## Project layout

```
VectorMatrixLib/ library sources (namespace vectormatrix), demo, Visual Studio project
tests/ unit tests: TestFramework.h, TestMain.cpp, one file per class
docs/ documentation
CMakeLists.txt CMake build (library, demo, tests)
.github/workflows/ CI on Linux, Windows and macOS
```

## Documentation

- [docs/API.md](docs/API.md): the classes, their semantics, and the mapping from Aventura's Java API.
- [docs/HISTORY.md](docs/HISTORY.md): the genesis of this library from the Aventura Java project, and how it was brought up to date.
- [docs/TESTING.md](docs/TESTING.md): the test framework and how the JUnit tests were ported.

## License

MIT, Copyright (c) 2021 - 2026 Olivier BARRY.
27 changes: 14 additions & 13 deletions VectorMatrixLib/GaussJordanSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,8 @@ namespace vectormatrix
}
}

private:
template <int N>
static void swapRows(float (&a)[N][N], int r1, int r2)
{
for (int col = 0; col < N; col++)
{
float tmp = a[r1][col];
a[r1][col] = a[r2][col];
a[r2][col] = tmp;
}
}

// Row index (from pivot row down) of the greatest absolute value in column col
// Row index (from pivot row down) of the greatest absolute value in column col.
// Public so that the partial pivoting can be tested directly (package-private in Aventura).
template <int N>
static int indiceOfMaxRowInColumn(const float (&m)[N][N], int col, int pivot)
{
Expand All @@ -100,6 +89,18 @@ namespace vectormatrix
}
return indiceMax;
}

private:
template <int N>
static void swapRows(float (&a)[N][N], int r1, int r2)
{
for (int col = 0; col < N; col++)
{
float tmp = a[r1][col];
a[r1][col] = a[r2][col];
a[r2][col] = tmp;
}
}
};
}

Expand Down
48 changes: 48 additions & 0 deletions VectorMatrixLib/GeometryTools.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// MIT License
// Copyright(c) 2021 - 2026 Olivier BARRY
//
// This file is part of the C++ Aventura Project
//
// VectorMatrix Math Library
//

#include "GeometryTools.h"

namespace vectormatrix
{
std::optional<Vector4f> GeometryTools::center(const std::vector<Vector4f>& points)
{
if (points.empty()) return std::nullopt;

float x = 0, y = 0, z = 0;
for (const Vector4f& p : points)
{
x += p.getX();
y += p.getY();
z += p.getZ();
}
float n = static_cast<float>(points.size());
return Vector4f(x / n, y / n, z / n, 1);
}

std::optional<Vector4f> GeometryTools::center(const std::vector<std::vector<Vector4f>>& points)
{
float x = 0, y = 0, z = 0;
size_t count = 0;
for (const std::vector<Vector4f>& row : points)
{
for (const Vector4f& p : row)
{
x += p.getX();
y += p.getY();
z += p.getZ();
}
count += row.size();
}
if (count == 0) return std::nullopt;

float n = static_cast<float>(count);
return Vector4f(x / n, y / n, z / n, 1);
}
}
31 changes: 31 additions & 0 deletions VectorMatrixLib/GeometryTools.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// MIT License
// Copyright(c) 2021 - 2026 Olivier BARRY
//
// This file is part of the C++ Aventura Project
//
// VectorMatrix Math Library
//

#ifndef GEOMETRYTOOLS_H
#define GEOMETRYTOOLS_H

#include <optional>
#include <vector>
#include "Vector4f.h"

namespace vectormatrix
{
// Geometry helpers (same as Aventura GeometryTools)
class GeometryTools
{
public:
// Geometrical center of the points (average of x, y, z, with w = 1),
// or nothing if there is no point (Java returns null)
static std::optional<Vector4f> center(const std::vector<Vector4f>& points);
// Same for a grid of points (rows may have different lengths)
static std::optional<Vector4f> center(const std::vector<std::vector<Vector4f>>& points);
};
}

#endif // GEOMETRYTOOLS_H
53 changes: 0 additions & 53 deletions VectorMatrixLib/TestMatrix.cpp

This file was deleted.

52 changes: 52 additions & 0 deletions VectorMatrixLib/Tools.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// MIT License
// Copyright(c) 2021 - 2026 Olivier BARRY
//
// This file is part of the C++ Aventura Project
//
// VectorMatrix Math Library
//

#ifndef TOOLS_H
#define TOOLS_H

#include "Vector2f.h"
#include "Vector3f.h"
#include "Vector4f.h"

namespace vectormatrix
{
// Linear interpolation helpers (same as Aventura Tools).
// interpolate(a, b, t) = a*(1-t) + b*t, so t=0 gives a, t=1 gives b,
// and t outside [0,1] extrapolates on the (ab) line.
class Tools
{
public:
static Vector4f interpolate(const Vector4f& a, const Vector4f& b, float t)
{
return Vector4f::interpolate(a, b, t);
}

static Vector3f interpolate(const Vector3f& a, const Vector3f& b, float t)
{
return Vector3f::interpolate(a, b, t);
}

static Vector2f interpolate(const Vector2f& a, const Vector2f& b, float t)
{
return Vector2f::interpolate(a, b, t);
}

static double interpolate(double a, double b, double t)
{
return a * (1 - t) + b * t;
}

static float interpolate(float a, float b, float t)
{
return a * (1 - t) + b * t;
}
};
}

#endif // TOOLS_H
Loading
Loading