Skip to content

Commit

Permalink
Replace GLM with linalg (elalish#984)
Browse files Browse the repository at this point in the history
* added linalg

* removed GLM

* fix matrix multiplication

* more matrix constructors

* fixed more functions

* fixed matrix notation

* more fixes

* fix ostream

* further fixes

* added more rotation functions

* compiles

* some fixes

* fix2

* fix build

* another warning...

* fix install

* for wasm?

* no warning for unknown options

* proper fix?

* remove legacy warning flags

* format

* misc constexpr

---------

Co-authored-by: pca006132 <[email protected]>
  • Loading branch information
elalish and pca006132 authored Oct 15, 2024
1 parent bd52d30 commit e067653
Show file tree
Hide file tree
Showing 61 changed files with 2,882 additions and 806 deletions.
28 changes: 5 additions & 23 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,16 @@ if(MSVC)
list(APPEND MANIFOLD_FLAGS /DNOMINMAX /bigobj)
else()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
list(APPEND WARNING_FLAGS -Wall -Wno-unknown-warning-option -Wno-unused)
else()
list(
APPEND
WARNING_FLAGS
-Wall
-Wno-unknown-warning-option
-Wno-unused
-Wno-array-bounds
-Wno-stringop-overflow
-Wno-alloc-size-larger-than
-Wno-shorten-64-to-32
)
else()
list(APPEND WARNING_FLAGS -Wall -Wno-unused -Wno-shorten-64-to-32)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
Expand Down Expand Up @@ -218,24 +217,6 @@ function(logmissingdep PKG)
endif()
endfunction()

# GLM is required in all configurations.
find_package(glm QUIET)
if(NOT glm_FOUND)
logmissingdep("glm")
message(STATUS "glm not found, downloading from source")
set(GLM_BUILD_INSTALL "ON" CACHE STRING "")
FetchContent_Declare(
glm
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG 1.0.1
GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(glm)
if(NOT EMSCRIPTEN)
install(TARGETS glm)
endif()
endif()

# If we're building parallel, we need the requisite libraries
if(MANIFOLD_PAR)
find_package(Threads REQUIRED)
Expand Down Expand Up @@ -411,6 +392,7 @@ set(
MANIFOLD_PUBLIC_HDRS
include/manifold/common.h
include/manifold/iters.h
include/manifold/linalg.h
include/manifold/manifold.h
include/manifold/optional_assert.h
include/manifold/parallel.h
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ If you prefer Python to JS/TS, make your own copy of the example notebook above.
This is a modern C++ library that Github's CI verifies builds and runs on a variety of platforms. Additionally, we build bindings for JavaScript ([manifold-3d](https://www.npmjs.com/package/manifold-3d) on npm), Python ([manifold3d](https://pypi.org/project/manifold3d/)), and C to make this library more portable and easy to use.

System Dependencies (note that we will automatically download the dependency if there is no such package on the system):
- [`GLM`](https://github.com/g-truc/glm/): A compact header-only vector library.
- [`tbb`](https://github.com/oneapi-src/oneTBB/): Intel's thread building blocks library. (only when `MANIFOLD_PAR=ON` is enabled)
- [`gtest`](https://github.com/google/googletest/): Google test library (only when test is enabled, i.e. `MANIFOLD_TEST=ON`)

Expand Down
2 changes: 1 addition & 1 deletion bindings/c/box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ ManifoldBox *manifold_box_transform(void *mem, ManifoldBox *b, double x1,
double y1, double z1, double x2, double y2,
double z2, double x3, double y3, double z3,
double x4, double y4, double z4) {
auto mat = mat4x3(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
auto mat = mat3x4({x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}, {x4, y4, z4});
auto transformed = from_c(b)->Transform(mat);
return to_c(new (mem) Box(transformed));
}
Expand Down
2 changes: 1 addition & 1 deletion bindings/c/cross.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ ManifoldCrossSection *manifold_cross_section_transform(void *mem,
double x1, double y1,
double x2, double y2,
double x3, double y3) {
auto mat = mat3x2(x1, y1, x2, y2, x3, y3);
auto mat = mat2x3({x1, y1}, {x2, y2}, {x3, y3});
auto transformed = from_c(cs)->Transform(mat);
return to_c(new (mem) CrossSection(transformed));
}
Expand Down
2 changes: 1 addition & 1 deletion bindings/c/manifoldc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ ManifoldManifold *manifold_transform(void *mem, ManifoldManifold *m, double x1,
double y1, double z1, double x2, double y2,
double z2, double x3, double y3, double z3,
double x4, double y4, double z4) {
auto mat = mat4x3(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4);
auto mat = mat3x4({x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}, {x4, y4, z4});
auto transformed = from_c(m)->Transform(mat);
return to_c(new (mem) Manifold(transformed));
}
Expand Down
2 changes: 1 addition & 1 deletion bindings/c/rect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ ManifoldRect *manifold_rect_union(void *mem, ManifoldRect *a, ManifoldRect *b) {
ManifoldRect *manifold_rect_transform(void *mem, ManifoldRect *r, double x1,
double y1, double x2, double y2,
double x3, double y3) {
auto mat = mat3x2(x1, y1, x2, y2, x3, y3);
auto mat = mat2x3({x1, y1}, {x2, y2}, {x3, y3});
auto transformed = from_c(r)->Transform(mat);
return to_c(new (mem) Rect(transformed));
}
Expand Down
64 changes: 32 additions & 32 deletions bindings/python/manifold3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,36 @@ namespace nb = nanobind;
using namespace manifold;

template <class T>
struct glm_name {};
struct la_name {};
template <>
struct glm_name<vec3> {
struct la_name<vec3> {
static constexpr char const name[] = "Doublex3";
static constexpr char const multi_name[] = "DoubleNx3";
};
template <>
struct glm_name<vec2> {
struct la_name<vec2> {
static constexpr char const name[] = "Doublex2";
static constexpr char const multi_name[] = "DoubleNx2";
};
template <>
struct glm_name<ivec3> {
struct la_name<ivec3> {
static constexpr char const name[] = "Intx3";
static constexpr char const multi_name[] = "IntNx3";
};
template <>
struct glm_name<mat4x3> {
struct la_name<mat3x4> {
static constexpr char const name[] = "Double3x4";
};
template <>
struct glm_name<mat3x2> {
struct la_name<mat2x3> {
static constexpr char const name[] = "Double2x3";
};

// handle glm::vecN
template <class T, int N, glm::qualifier Q>
struct nb::detail::type_caster<glm::vec<N, T, Q>> {
using glm_type = glm::vec<N, T, Q>;
NB_TYPE_CASTER(glm_type, const_name(glm_name<glm_type>::name));
// handle la::vecN
template <class T, int N>
struct nb::detail::type_caster<la::vec<T, N>> {
using la_type = la::vec<T, N>;
NB_TYPE_CASTER(la_type, const_name(la_name<la_type>::name));

bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept {
int size = PyObject_Size(src.ptr()); // negative on failure
Expand All @@ -73,20 +73,20 @@ struct nb::detail::type_caster<glm::vec<N, T, Q>> {
}
return true;
}
static handle from_cpp(glm_type vec, rv_policy policy,
static handle from_cpp(la_type vec, rv_policy policy,
cleanup_list *cleanup) noexcept {
nb::list out;
for (int i = 0; i < N; i++) out.append(vec[i]);
return out.release();
}
};

// handle glm::matMxN
template <class T, int C, int R, glm::qualifier Q>
struct nb::detail::type_caster<glm::mat<C, R, T, Q>> {
using glm_type = glm::mat<C, R, T, Q>;
// handle la::matMxN
template <class T, int C, int R>
struct nb::detail::type_caster<la::mat<T, R, C>> {
using la_type = la::mat<T, R, C>;
using numpy_type = nb::ndarray<nb::numpy, T, nb::shape<R, C>>;
NB_TYPE_CASTER(glm_type, const_name(glm_name<glm_type>::name));
NB_TYPE_CASTER(la_type, const_name(la_name<la_type>::name));

bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept {
int rows = PyObject_Size(src.ptr()); // negative on failure
Expand All @@ -103,13 +103,13 @@ struct nb::detail::type_caster<glm::mat<C, R, T, Q>> {
}
return true;
}
static handle from_cpp(glm_type mat, rv_policy policy,
static handle from_cpp(la_type mat, rv_policy policy,
cleanup_list *cleanup) noexcept {
T *buffer = new T[R * C];
nb::capsule mem_mgr(buffer, [](void *p) noexcept { delete[] (T *)p; });
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
// py is (Rows, Cols), glm is (Cols, Rows)
// py is (Rows, Cols), la is (Cols, Rows)
buffer[i * C + j] = mat[j][i];
}
}
Expand All @@ -119,13 +119,13 @@ struct nb::detail::type_caster<glm::mat<C, R, T, Q>> {
}
};

// handle std::vector<glm::vecN>
template <class T, int N, glm::qualifier Q>
struct nb::detail::type_caster<std::vector<glm::vec<N, T, Q>>> {
using glm_type = glm::vec<N, T, Q>;
// handle std::vector<la::vecN>
template <class T, int N>
struct nb::detail::type_caster<std::vector<la::vec<T, N>>> {
using la_type = la::vec<T, N>;
using numpy_type = nb::ndarray<nb::numpy, T, nb::shape<-1, N>>;
NB_TYPE_CASTER(std::vector<glm_type>,
const_name(glm_name<glm_type>::multi_name));
NB_TYPE_CASTER(std::vector<la_type>,
const_name(la_name<la_type>::multi_name));

bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept {
make_caster<numpy_type> arr_cast;
Expand All @@ -142,7 +142,7 @@ struct nb::detail::type_caster<std::vector<glm::vec<N, T, Q>>> {
if (num_vec == static_cast<size_t>(-1)) return false;
value.resize(num_vec);
for (size_t i = 0; i < num_vec; i++) {
make_caster<glm_type> vec_cast;
make_caster<la_type> vec_cast;
if (!vec_cast.from_python(src[i], flags, cleanup)) return false;
value[i] = vec_cast.value;
}
Expand All @@ -165,13 +165,13 @@ struct nb::detail::type_caster<std::vector<glm::vec<N, T, Q>>> {
}
};

// handle VecView<glm::vec*>
template <class T, int N, glm::qualifier Q>
struct nb::detail::type_caster<manifold::VecView<glm::vec<N, T, Q>>> {
using glm_type = glm::vec<N, T, Q>;
// handle VecView<la::vec*>
template <class T, int N>
struct nb::detail::type_caster<manifold::VecView<la::vec<T, N>>> {
using la_type = la::vec<T, N>;
using numpy_type = nb::ndarray<nb::numpy, T, nb::shape<-1, N>>;
NB_TYPE_CASTER(manifold::VecView<glm_type>,
const_name(glm_name<glm_type>::multi_name));
NB_TYPE_CASTER(manifold::VecView<la_type>,
const_name(la_name<la_type>::multi_name));

bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept {
make_caster<numpy_type> arr_cast;
Expand Down
4 changes: 2 additions & 2 deletions bindings/wasm/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ CrossSection IntersectionN(const std::vector<CrossSection>& cross_sections) {

CrossSection Transform(CrossSection& cross_section, const val& mat) {
std::vector<double> array = convertJSArrayToNumberVector<double>(mat);
mat3x2 matrix;
mat2x3 matrix;
for (const int col : {0, 1, 2})
for (const int row : {0, 1}) matrix[col][row] = array[col * 3 + row];
return cross_section.Transform(matrix);
Expand Down Expand Up @@ -188,7 +188,7 @@ Manifold IntersectionN(const std::vector<Manifold>& manifolds) {

Manifold Transform(Manifold& manifold, const val& mat) {
std::vector<double> array = convertJSArrayToNumberVector<double>(mat);
mat4x3 matrix;
mat3x4 matrix;
for (const int col : {0, 1, 2, 3})
for (const int row : {0, 1, 2}) matrix[col][row] = array[col * 4 + row];
return manifold.Transform(matrix);
Expand Down
10 changes: 5 additions & 5 deletions extras/minimize_testcase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ inline bool intersect(vec2 p0, vec2 p1, vec2 q0, vec2 q1, double precision) {
vec2 r = p1 - p0;
vec2 s = q1 - q0;
// allow some error in the intersection point
double epsilon_r = 2.0 * precision / glm::length(r);
double epsilon_s = 2.0 * precision / glm::length(s);
double epsilon_r = 2.0 * precision / la::length(r);
double epsilon_s = 2.0 * precision / la::length(s);
double rxs = cross(r, s);
// in case they are nearly collinear, ignore them...
// this is to avoid treating degenerate triangles as intersecting
Expand All @@ -45,7 +45,7 @@ inline bool intersect(vec2 p0, vec2 p1, vec2 q0, vec2 q1, double precision) {
// perturbation along r/s is not enough.
//
// in that case, apply perturbation perpendicular to r
vec2 r_orth = glm::normalize(vec2(-r.y, r.x)) * precision;
vec2 r_orth = la::normalize(vec2(-r.y, r.x)) * precision;
double u1 = cross(q0 - p0 + r_orth, r) / rxs;
double u2 = cross(q0 - p0 - r_orth, r) / rxs;
double t1 = cross(q0 - p0 + r_orth, s) / rxs;
Expand Down Expand Up @@ -369,8 +369,8 @@ int main(int argc, char **argv) {
double bound = 0;
for (const SimplePolygon &poly : polys) {
for (const vec2 &pt : poly) {
bound = glm::max(bound, glm::abs(pt.x));
bound = glm::max(bound, glm::abs(pt.y));
bound = la::max(bound, la::abs(pt.x));
bound = la::max(bound, la::abs(pt.y));
}
}
precision = bound * kTolerance;
Expand Down
5 changes: 2 additions & 3 deletions extras/test_hull_performance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include "manifold/meshIO.h"
#include "samples.h"
using namespace std;
using namespace glm;
using namespace manifold;

// Epick = Exact predicates Inexact constructions. Seems fair to use to compare
Expand Down Expand Up @@ -70,7 +69,7 @@ class HullImpl {
vec3 v2 = vertPos[tri[2]];

// Compute the normal of the triangle
vec3 normal = glm::normalize(glm::cross(v1 - v0, v2 - v0));
vec3 normal = la::normalize(la::cross(v1 - v0, v2 - v0));

// Check all other vertices
for (int i = 0; i < (int)vertPos.size(); ++i) {
Expand All @@ -81,7 +80,7 @@ class HullImpl {
vec3 v = vertPos[i];

// Compute the signed distance from the plane
double distance = glm::dot(normal, v - v0);
double distance = la::dot(normal, v - v0);

// If any vertex lies on the opposite side of the normal direction
if (distance > 0) {
Expand Down
3 changes: 0 additions & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
pkg-config
]) ++ build-tools;
buildInputs = with pkgs; [
glm
clipper2
assimp
];
Expand Down Expand Up @@ -86,7 +85,6 @@
mkdir build
cd build
emcmake cmake -DCMAKE_BUILD_TYPE=Release \
-DFETCHCONTENT_SOURCE_DIR_GLM=${pkgs.glm.src} \
-DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=${gtest-src} \
-DFETCHCONTENT_SOURCE_DIR_CLIPPER2=../clipper2 ..
'';
Expand Down Expand Up @@ -114,7 +112,6 @@
];
buildInputs = with pkgs; [
tbb
glm
clipper2
];
nativeBuildInputs = with pkgs; [
Expand Down
Loading

0 comments on commit e067653

Please sign in to comment.