GithubHelp home page GithubHelp logo

elalish / manifold Goto Github PK

View Code? Open in Web Editor NEW
670.0 670.0 65.0 32.68 MB

Geometry library for topological robustness

License: Apache License 2.0

CMake 2.46% C++ 77.86% C 0.22% Nix 0.45% Python 7.10% HTML 0.91% JavaScript 4.85% CSS 0.44% TypeScript 5.45% Shell 0.26%

manifold's People

Contributors

axel-angel avatar briansturgill avatar cartesian-theatrics avatar cjmayo avatar dasoya avatar elalish avatar eric-vin avatar fire avatar geoffder avatar harmanpa avatar hi-ogawa avatar imciner2 avatar jirihon avatar johnnybigert avatar kintel avatar loosetooth avatar makc avatar mleleszi avatar nodeguy avatar ochafik avatar pca006132 avatar rafern avatar ramcdona avatar sloriot avatar starseeker avatar stephomi avatar virtualritz avatar wrongbad avatar yetigit avatar zalo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

manifold's Issues

Feature request: Intersection Polyline

Hi, thank you for your efforts on doing a fast and robust csg lib

what would be a killer feature is being able to retrieve the intersection data, precisely as naturally ordered polyline(s).
which boils down to just having the intersection points in the right order ; with a topological predicate since there can be several intersection loops.

here a sphere vs a cube
maya_zk2js5vmOH

cube vs cube
maya_qHK3Isv83y

RecursiveEdgeSwap invalid memory access

Compile the following code with address sanitizer enabled:

#include <algorithm>

#include "manifold.h"

using namespace manifold;

std::vector<Manifold> RoundedFrameComponents(float edgeLength, float radius,
                                             int circularSegments) {
  Manifold edge = Manifold::Cylinder(edgeLength, radius, -1, circularSegments);
  Manifold corner = Manifold::Sphere(radius, circularSegments);

  std::vector<Manifold> edge1({corner, edge});
  for (Manifold& m : edge1) {
    m.Rotate(-90).Translate({-edgeLength / 2, -edgeLength / 2, 0});
  }

  std::vector<Manifold> edge2;
  for (Manifold m : edge1) {
    edge2.push_back(Manifold(m).Rotate(0, 0, 180));
    edge2.push_back(
        Manifold(m).Translate({-edgeLength / 2, -edgeLength / 2, 0}));
  }

  std::vector<Manifold> edge4;
  for (Manifold m : edge2) {
    edge4.push_back(Manifold(m).Rotate(0, 0, 90));
    edge4.push_back(Manifold(m));
  }

  std::vector<Manifold> frame;
  for (Manifold m : edge4) {
    frame.push_back(Manifold(m).Translate({0, 0, -edgeLength / 2}));
    frame.push_back(Manifold(m).Rotate(180));
  }

  return frame;
}

int main() {
  auto components = RoundedFrameComponents(100, 10, 4);

  std::vector<unsigned int> indices({5, 8, 10, 2, 1});

  Manifold m;
  for (auto i : indices) {
    m = m + components[i];
    // just to force evaluate
    m.NumVert();
  }
  return 0;
}
cmake -DCMAKE_BUILD_TYPE=Release -DMANIFOLD_PAR="NONE" -DMANIFOLD_USE_CUDA=OFF -DCMAKE_CXX_FLAGS="-g -fsanitize=address" -DCMAKE_CXX_COMPILER="clang++" ..

and it will abort with the following message:

==1210305==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61c000002878 at pc 0x000000566be3 bp 0x7ffffffed250 sp 0x7ffffffed248
READ of size 4 at 0x61c000002878 thread T0
[Detaching after fork from child process 1210309]
    #0 0x566be2 in manifold::Manifold::Impl::RecursiveEdgeSwap(int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:386:23
    #1 0x56691f in manifold::Manifold::Impl::RecursiveEdgeSwap(int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:476:3
    #2 0x560b71 in manifold::Manifold::Impl::SimplifyTopology() /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:186:5
    #3 0x5a00c6 in manifold::Boolean3::Result(manifold::Manifold::OpType) const /home/pca006132/code/test/manifold/manifold/src/boolean_result.cpp:688:8
    #4 0x50abd1 in manifold::Manifold::Boolean(manifold::Manifold const&, manifold::Manifold::OpType) const /home/pca006132/code/test/manifold/manifold/src/manifold.cpp:467:50
    #5 0x50af9a in manifold::Manifold::operator+(manifold::Manifold const&) const /home/pca006132/code/test/manifold/manifold/src/manifold.cpp:475:10
    #6 0x504b7f in main /home/pca006132/code/test/manifold/tools/union.cpp:47:11
    #7 0x7ffff7c8978f in __libc_start_main (/nix/store/qjgj2642srlbr59wwdihnn66sw97ming-glibc-2.33-123/lib/libc.so.6+0x2778f)
    #8 0x423279 in _start /build/glibc-2.33/csu/../sysdeps/x86_64/start.S:120

Tested on both ed272b0 and the current master.

Also, different union order will give a different number of vertices. I suspect this is also related to the problem in #131 (comment) . Changing the order in BatchBoolean will randomly fail some tests, for example by sorting the manifolds instead of using a heap, I managed to get Samples.Sponge4 passed but failed the Samples.FrameReduced test, not sorting/using a heap will lead to a different kind of failure for example.

This case is found by getting a set of manifolds, and repeatedly do a random shuffle and union them until it fails (or executed enough rounds so it can be considered not buggy). And then you can try to reduce the case by doing a random shuffle and discard the last element, similarly until you can no longer reproduce the error after discarding the last element.

Remove thrust option

To make manifold easier to build there was a proposal to remove thrust for C++ primitives.

This is tracking that thrust removal proposal.

manifold_test dump on VS - Windows x64

I had to comment out tests containing specific paths
and this is the result of the suite (click the spoiler )

[==========] Running 86 tests from 4 test cases.
[----------] Global test environment set-up.
[----------] 43 tests from Polygon
[ RUN      ] Polygon.SimpleHole
[       OK ] Polygon.SimpleHole (1 ms)
[ RUN      ] Polygon.SimpleHole2
[       OK ] Polygon.SimpleHole2 (0 ms)
[ RUN      ] Polygon.MultiMerge
[       OK ] Polygon.MultiMerge (0 ms)
[ RUN      ] Polygon.Colinear
[       OK ] Polygon.Colinear (0 ms)
[ RUN      ] Polygon.Merges
[       OK ] Polygon.Merges (0 ms)
[ RUN      ] Polygon.ColinearY
[       OK ] Polygon.ColinearY (0 ms)
[ RUN      ] Polygon.Concave
[       OK ] Polygon.Concave (0 ms)
[ RUN      ] Polygon.Concave2
[       OK ] Polygon.Concave2 (0 ms)
[ RUN      ] Polygon.Sliver
[       OK ] Polygon.Sliver (0 ms)
[ RUN      ] Polygon.Duplicate
[       OK ] Polygon.Duplicate (0 ms)
[ RUN      ] Polygon.Folded
[       OK ] Polygon.Folded (0 ms)
[ RUN      ] Polygon.NearlyLinear
[       OK ] Polygon.NearlyLinear (0 ms)
[ RUN      ] Polygon.Sliver2
[       OK ] Polygon.Sliver2 (0 ms)
[ RUN      ] Polygon.Sliver3
[       OK ] Polygon.Sliver3 (0 ms)
[ RUN      ] Polygon.Sliver4
[       OK ] Polygon.Sliver4 (0 ms)
[ RUN      ] Polygon.Sliver5
[       OK ] Polygon.Sliver5 (0 ms)
[ RUN      ] Polygon.Colinear2
[       OK ] Polygon.Colinear2 (0 ms)
[ RUN      ] Polygon.Split
[       OK ] Polygon.Split (0 ms)
[ RUN      ] Polygon.Duplicates
[       OK ] Polygon.Duplicates (0 ms)
[ RUN      ] Polygon.Simple1
[       OK ] Polygon.Simple1 (0 ms)
[ RUN      ] Polygon.Simple2
[       OK ] Polygon.Simple2 (0 ms)
[ RUN      ] Polygon.Simple3
[       OK ] Polygon.Simple3 (0 ms)
[ RUN      ] Polygon.Simple4
[       OK ] Polygon.Simple4 (0 ms)
[ RUN      ] Polygon.Simple5
[       OK ] Polygon.Simple5 (0 ms)
[ RUN      ] Polygon.Simple6
[       OK ] Polygon.Simple6 (0 ms)
[ RUN      ] Polygon.TouchingHole
[       OK ] Polygon.TouchingHole (0 ms)
[ RUN      ] Polygon.Degenerate
[       OK ] Polygon.Degenerate (0 ms)
[ RUN      ] Polygon.Degenerate2
[       OK ] Polygon.Degenerate2 (0 ms)
[ RUN      ] Polygon.Degenerate3
[       OK ] Polygon.Degenerate3 (0 ms)
[ RUN      ] Polygon.Degenerate4
[       OK ] Polygon.Degenerate4 (0 ms)
[ RUN      ] Polygon.Degenerate5
[       OK ] Polygon.Degenerate5 (0 ms)
[ RUN      ] Polygon.Degenerate6
[       OK ] Polygon.Degenerate6 (0 ms)
[ RUN      ] Polygon.Tricky
[       OK ] Polygon.Tricky (0 ms)
[ RUN      ] Polygon.Tricky2
[       OK ] Polygon.Tricky2 (0 ms)
[ RUN      ] Polygon.Slit
[       OK ] Polygon.Slit (0 ms)
[ RUN      ] Polygon.SharedEdge
[       OK ] Polygon.SharedEdge (0 ms)
[ RUN      ] Polygon.Comb
[       OK ] Polygon.Comb (0 ms)
[ RUN      ] Polygon.Comb2
[       OK ] Polygon.Comb2 (0 ms)
[ RUN      ] Polygon.PointPoly
[       OK ] Polygon.PointPoly (1 ms)
[ RUN      ] Polygon.KissingZigzag
[       OK ] Polygon.KissingZigzag (1 ms)
[ RUN      ] Polygon.Sponge
[       OK ] Polygon.Sponge (1 ms)
[ RUN      ] Polygon.SquareHoles
[       OK ] Polygon.SquareHoles (1 ms)
[ RUN      ] Polygon.BigSponge
[       OK ] Polygon.BigSponge (16 ms)
[----------] 43 tests from Polygon (103 ms total)

[----------] 15 tests from Manifold
[ RUN      ] Manifold.GetMesh
[       OK ] Manifold.GetMesh (204 ms)
[ RUN      ] Manifold.Decompose
[       OK ] Manifold.Decompose (26 ms)
[ RUN      ] Manifold.Sphere
[       OK ] Manifold.Sphere (6 ms)
[ RUN      ] Manifold.Normals
[       OK ] Manifold.Normals (4 ms)
[ RUN      ] Manifold.Extrude
[       OK ] Manifold.Extrude (5 ms)
[ RUN      ] Manifold.ExtrudeCone
[       OK ] Manifold.ExtrudeCone (3 ms)
[ RUN      ] Manifold.Revolve
[       OK ] Manifold.Revolve (4 ms)
[ RUN      ] Manifold.Revolve2
[       OK ] Manifold.Revolve2 (4 ms)
[ RUN      ] Manifold.Smooth
[       OK ] Manifold.Smooth (38 ms)
[ RUN      ] Manifold.SmoothSphere
[       OK ] Manifold.SmoothSphere (99 ms)
[ RUN      ] Manifold.ManualSmooth
[       OK ] Manifold.ManualSmooth (74 ms)
[ RUN      ] Manifold.GetProperties
[       OK ] Manifold.GetProperties (4 ms)
[ RUN      ] Manifold.Precision
[       OK ] Manifold.Precision (4 ms)
[ RUN      ] Manifold.GetCurvature
[       OK ] Manifold.GetCurvature (40 ms)
[ RUN      ] Manifold.Transform
[       OK ] Manifold.Transform (4 ms)
[----------] 15 tests from Manifold (530 ms total)

[----------] 19 tests from Boolean
[ RUN      ] Boolean.Tetra
[       OK ] Boolean.Tetra (21 ms)
[ RUN      ] Boolean.SelfSubtract
[       OK ] Boolean.SelfSubtract (12 ms)
[ RUN      ] Boolean.Perturb
[       OK ] Boolean.Perturb (15 ms)
[ RUN      ] Boolean.Coplanar
[       OK ] Boolean.Coplanar (21 ms)
[ RUN      ] Boolean.MultiCoplanar
[       OK ] Boolean.MultiCoplanar (33 ms)
[ RUN      ] Boolean.FaceUnion
[       OK ] Boolean.FaceUnion (19 ms)
[ RUN      ] Boolean.EdgeUnion
[       OK ] Boolean.EdgeUnion (25 ms)
[ RUN      ] Boolean.EdgeUnion2
[       OK ] Boolean.EdgeUnion2 (25 ms)
[ RUN      ] Boolean.CornerUnion
[       OK ] Boolean.CornerUnion (25 ms)
[ RUN      ] Boolean.Split
[       OK ] Boolean.Split (29 ms)
[ RUN      ] Boolean.SplitByPlane
[       OK ] Boolean.SplitByPlane (46 ms)
[ RUN      ] Boolean.SplitByPlane60
[       OK ] Boolean.SplitByPlane60 (45 ms)
[ RUN      ] Boolean.Vug
[       OK ] Boolean.Vug (48 ms)
[ RUN      ] Boolean.Empty
[       OK ] Boolean.Empty (4 ms)
[ RUN      ] Boolean.Winding
[       OK ] Boolean.Winding (22 ms)
[ RUN      ] Boolean.NonIntersecting
[       OK ] Boolean.NonIntersecting (16 ms)
[ RUN      ] Boolean.Precision
[       OK ] Boolean.Precision (24 ms)
[ RUN      ] Boolean.Precision2
[       OK ] Boolean.Precision2 (33 ms)
[ RUN      ] Boolean.Sphere
[       OK ] Boolean.Sphere (25 ms)
[----------] 19 tests from Boolean (499 ms total)

[----------] 9 tests from Samples
[ RUN      ] Samples.Knot13
[       OK ] Samples.Knot13 (23 ms)
[ RUN      ] Samples.Knot42
[       OK ] Samples.Knot42 (29 ms)
[ RUN      ] Samples.Scallop
[       OK ] Samples.Scallop (65 ms)
[ RUN      ] Samples.TetPuzzle
[       OK ] Samples.TetPuzzle (37 ms)
[ RUN      ] Samples.FrameReduced
[       OK ] Samples.FrameReduced (76 ms)
[ RUN      ] Samples.Frame
unknown file: error: C++ exception with description "Error in file: C:\repos\manifold\manifold\src\boolean_result.cu (187): 'edgePos.size() % 2 == 0' is false: Non-manifold edge! Not an even number of points." thrown in the test body.
[  FAILED  ] Samples.Frame (76 ms)
[ RUN      ] Samples.Bracelet
unknown file: error: C++ exception with description "Error in file: C:\repos\manifold\manifold\src\boolean_result.cu (187): 'edgePos.size() % 2 == 0' is false: Non-manifold edge! Not an even number of points." thrown in the test body.
[  FAILED  ] Samples.Bracelet (37 ms)
[ RUN      ] Samples.Sponge1
[       OK ] Samples.Sponge1 (49 ms)
[ RUN      ] Samples.Sponge4
unknown file: error: C++ exception with description "Error in file: C:\repos\manifold\manifold\src\boolean_result.cu (187): 'edgePos.size() % 2 == 0' is false: Non-manifold edge! Not an even number of points." thrown in the test body.
[  FAILED  ] Samples.Sponge4 (716 ms)
[----------] 9 tests from Samples (1113 ms total)

[----------] Global test environment tear-down
[==========] 86 tests from 4 test cases ran. (2248 ms total)
[  PASSED  ] 83 tests.
[  FAILED  ] 3 tests, listed below:
[  FAILED  ] Samples.Frame
[  FAILED  ] Samples.Bracelet
[  FAILED  ] Samples.Sponge4

 3 FAILED TESTS

C:\repos\manifold\build\test\Release\manifold_test.exe (process 19368) exited with code 1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .

reordered sponge4 failure

I managed to repro the problem from #171 on master by manually reordering the sponge operations. Many different orders worked fine, but this one, which is most similar to the result of the other PR, did not:

Manifold tmp1 = hole.Rotate(90) + hole.Rotate(90).Rotate(0, 0, 90);
Manifold tmp2 = hole + tmp1;
result = result - tmp2;

Not only did it come up with 39k degenerate triangles, it also ended up with the wrong genus. It's pretty clear there's a problem:
Screenshot from 2022-08-09 09-35-51

Simple Constraint/Relation API

A simple relation API might serve as an alternative to translate and rotate. For example, one may specify two circles of two different meshes to be concentric with other additional constraints. As the intention of this is to substitute things like translate and rotate, we don't need to store the relations, i.e. we only compute the required transformation immediately and apply it. If the set of constraints do not yield a unique solution, we can give any valid solution or return an error (when the user expects to fully define the object). The problem is that future transformations may violate old constraints.

The API I'm thinking about is something like this:

a_tran = place([a]).such_that([a.hole1.concentric(b.hole1)])[0]

where the place([a]) specifies the objects we want to move (a in this case), and the such_that clause specifies the set of constraints. The function will return a list of rigid transformations, or return an error if there is no solution.

Vertex/Edge/Face Selection

For some functions such as smooth, it might be desirable to only operate on a subset of vertices/edges, for example to make round edges or add fillet. I think it may make sense to allow users to filter edges/vertices via custom predicate, and allow users to mark vertices with unique IDs for tracking after other operations.

heap-buffer-overflow for manifold_test

I've built the project with address sanitizer enabled:

cmake -DCMAKE_BUILD_TYPE=Release -DMANIFOLD_USE_CPP=on -DCMAKE_CUDA_COMPILER=$CUDACXX -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang ..

and Manifold.ManualSmooth reports the following error:

==39777==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f2cc3a027dc at pc 0x0000021183e3 bp 0x7ffda836e930 sp 0x7ffda836e928
READ of size 4 at 0x7f2cc3a027dc thread T0
    #0 0x21183e2 in Manifold_ManualSmooth_Test::TestBody() /home/pca006132/code/manifold/test/mesh_test.cpp:308:36
    #1 0x21c3b10 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2443:10
    #2 0x21c3b10 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2479:14
    #3 0x218353f in testing::Test::Run() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2517:5
    #4 0x2185399 in testing::TestInfo::Run() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2693:11
    #5 0x2186cc6 in testing::TestCase::Run() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2811:28
    #6 0x21a0607 in testing::internal::UnitTestImpl::RunAllTests() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:5177:43
    #7 0x21c767f in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2443:10
    #8 0x21c767f in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:2479:14
    #9 0x219ef3e in testing::UnitTest::Run() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/src/gtest.cc:4786:10
    #10 0x20e4ef5 in RUN_ALL_TESTS() /home/pca006132/code/manifold/build/third_party/google_test/googletest-src/googletest/include/gtest/gtest.h:2341:46
    #11 0x20e4ef5 in main /home/pca006132/code/manifold/test/test_main.cpp:50:10
    #12 0x7f2cc910778f in __libc_start_main (/nix/store/qjgj2642srlbr59wwdihnn66sw97ming-glibc-2.33-123/lib/libc.so.6+0x2778f)
    #13 0x2004589 in _start /build/glibc-2.33/csu/../sysdeps/x86_64/start.S:120

0x7f2cc3a027dc is located 36 bytes to the left of 494496-byte region [0x7f2cc3a02800,0x7f2cc3a7b3a0)
allocated by thread T0 here:
    #0 0x20e20e7 in operator new(unsigned long) (/home/pca006132/code/manifold/build/test/manifold_test+0x20e20e7)
    #1 0x21e7609 in __gnu_cxx::new_allocator<glm::vec<3, float, (glm::qualifier)0> >::allocate(unsigned long, void const*) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/ext/new_allocator.h:115:42
    #2 0x21e7609 in std::allocator_traits<std::allocator<glm::vec<3, float, (glm::qualifier)0> > >::allocate(std::allocator<glm::vec<3, float, (glm::qualifier)0> >&, unsigned long) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/bits/alloc_traits.h:460:22
    #3 0x21e7609 in std::_Vector_base<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > >::_M_allocate(unsigned long) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/bits/stl_vector.h:346:36
    #4 0x21e7609 in void std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > >::_M_range_insert<thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*> >(__gnu_cxx::__normal_iterator<glm::vec<3, float, (glm::qualifier)0>*, std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > > >, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, std::forward_iterator_tag) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/bits/vector.tcc:769:38
    #5 0x21e7609 in void std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > >::_M_insert_dispatch<thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*> >(__gnu_cxx::__normal_iterator<glm::vec<3, float, (glm::qualifier)0>*, std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > > >, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, std::__false_type) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/bits/stl_vector.h:1665:16
    #6 0x21e7609 in __gnu_cxx::__normal_iterator<glm::vec<3, float, (glm::qualifier)0>*, std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > > > std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > >::insert<thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, void>(__gnu_cxx::__normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*, std::vector<glm::vec<3, float, (glm::qualifier)0>, std::allocator<glm::vec<3, float, (glm::qualifier)0> > > >, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>, thrust::detail::normal_iterator<glm::vec<3, float, (glm::qualifier)0> const*>) /nix/store/wly4zlhr614xi6mb97d4r040d69ikkfw-gcc-10.3.0/include/c++/10.3.0/bits/stl_vector.h:1383:19
    #7 0x21e7609 in manifold::Manifold::GetMeshRelation() const /home/pca006132/code/manifold/manifold/src/manifold.cu:277:111

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/pca006132/code/manifold/test/mesh_test.cpp:308:36 in Manifold_ManualSmooth_Test::TestBody()
Shadow bytes around the buggy address:
  0x0fe6187384a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0fe6187384b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0fe6187384c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0fe6187384d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0fe6187384e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0fe6187384f0: fa fa fa fa fa fa fa fa fa fa fa[fa]fa fa fa fa
  0x0fe618738500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe618738510: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe618738520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe618738530: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0fe618738540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==39777==ABORTING

Performance tracking

As this library is intended to be fast, I guess we should probably open an issue to track its performance?

I did some microbenchmark using the perfTest binary and a unionPerfTest code that I wrote to test lazy union (union 100 spheres with diameter=2.5 with varying separation distance, i.e. may or may not overlap). I've tested single thread using CPP backend, OpenMP backend and CUDA backend all on the same laptop with i5-8300H and GTX1050 Mobile. Here is my spreadsheet, and here is my branch for some optimizations that looks quite effective for CUDA and small meshes :). I will open a separate PR for the branch, after the build script PR is merged.

From the results, we can see that:

  1. For small meshes, OMP > CPP > CUDA. Wondering if we can run the thrust APIs on OMP for operations involving only < 1k vertices or something.
  2. For more complicated models, using the backend GPU may exhaust GPU memory. Is it possible to fallback to CPP mode after that?
  3. We have to be careful about copying vector, eliminating unnecessary copying reduces the execution time for CUDA backend significantly (-30% in the microbenchmark). One way would be to disable copy constructor for VecDH and provide an explicit copy method.
  4. It seems that the multithread cannot help much in our case, even though my computer has 4 cores 8 threads. Perhaps we should look into this because quite a lot of users may not have a GPU with CUDA (my main laptop is using AMD, so no CUDA here).

Non-manifold input to SimplifyTopology in Boolean.Close test

First noticed in #171, but subsequently the same failure was found on master when running CUDA. The infinite loop is a byproduct of the mesh not being manifold. Technically IsManifold() checks two different things: first, is the data structure sane, and second are there any duplicated edges (which make it not a 2-manifold - two triangles attached to every edge). SimplifyTopology is designed to fix meshes that are not 2-manifold into ones that are 2-manifold. However, we should not be producing any intermediate mesh that isn't sane. I need to add an assert about this to make these problems easier to spot (this is the second time I've run into something like this).

Suggestion: Simple Three.js robust Booleans example

I think it would be cool once you have a JS interface and a WASM module to create a Three.js example of just simple CSG Booleans and submit it to Three.js as PR. It wouldn't even need all the other functionality that this library offers to start -- and that may help get it accepted as the WASM bundle will be smaller.

Robust CSG booleans have been missing from Three.js and other online WebGL/WebGPU library and this could fulfill that need. I think that just robust CSG booleans would be very interesting to the Three.js project.

Removing exceptions

  • remove STL containers exceptions
  • remove Thrust exceptions
  • remove Manifold exceptions

Create strategy to change exception code to return codes.

Some discussion is in the Godot issue.

thrust universal vector

Just googled for unified memory support in thrust. It seems that they have something called universal_vector which can be accessed from both the host and the device. I guess we can probably use this instead of VecDH with cleaner code and support for complex modeling with GPUs that only has a small RAM? And perhaps we can choose to run the operations on the host or device depending on the workload without much code duplication. I haven't tried this yet though, not sure about its performance or if there is any quirks.

Flesh out 2D subsystem

We currently use Polygons as input to several Manifold constructors, and they could easily be output as well (think Slice), but we have no way to operate on them in 2D. I would like to think of Polygon as the 2D equivalent to Mesh, and I'd like to create a CrossSection class that is the 2D equivalent to Manifold.

A CrossSection will always be geometrically-valid (non-overlapping), as any input Polygons will be automatically fixed up according to winding number. Clipper lib seems like a good candidate to support useful 2D operations. I propose we adopt the "strictly positive" fill rule; this will allow Boolean-style operations simply by adding Polygons with the proper winding direction. This class will be totally independent of the Manifold class; they can simply interact through exported Polygons.

Boolean operation segfault

Apply the following patch:

diff --git a/tools/perf_test.cpp b/tools/perf_test.cpp
index 2ad385a..c002aa0 100644
--- a/tools/perf_test.cpp
+++ b/tools/perf_test.cpp
@@ -23,7 +23,6 @@ int main(int argc, char **argv) {
   for (int i = 0; i < 8; ++i) {
     Manifold sphere = Manifold::Sphere(1, (8 << i) * 4);
     Manifold sphere2 = sphere;
-    sphere2.Translate(glm::vec3(0.5));
     auto start = std::chrono::high_resolution_clock::now();
     Manifold diff = sphere - sphere2;
     auto end = std::chrono::high_resolution_clock::now();

And run perfTest with CPP backend, it will segfault after n=8192. With address sanitizer enabled:

nTri = 512, time = 0.0255094 sec
nTri = 2048, time = 0.101124 sec
nTri = 8192, time = 0.321662 sec
=================================================================
==1540173==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6310002a87f4 at pc 0x00000056519a bp 0x7ffdeba3df50 sp 0x7ffdeba3df48
WRITE of size 4 at 0x6310002a87f4 thread T0
    #0 0x565199 in manifold::Manifold::Impl::RemoveIfFolded(int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:211:50
    #1 0x564728 in manifold::Manifold::Impl::FormLoop(int, int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:193:3
    #2 0x560e31 in manifold::Manifold::Impl::CollapseEdge(int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:294:9
    #3 0x55e2a2 in manifold::Manifold::Impl::SimplifyTopology() /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:131:39
    #4 0x59ae56 in manifold::Boolean3::Result(manifold::Manifold::OpType) const /home/pca006132/code/test/manifold/manifold/src/boolean_result.cpp:690:8
    #5 0x509601 in manifold::Manifold::Boolean(manifold::Manifold const&, manifold::Manifold::OpType) const /home/pca006132/code/test/manifold/manifold/src/manifold.cpp:466:50
    #6 0x509b8d in manifold::Manifold::operator-(manifold::Manifold const&) const /home/pca006132/code/test/manifold/manifold/src/manifold.cpp:489:10
    #7 0x5039bd in main /home/pca006132/code/test/manifold/tools/perf_test.cpp:27:28
    #8 0x7fc9f51c078f in __libc_start_main (/nix/store/qjgj2642srlbr59wwdihnn66sw97ming-glibc-2.33-123/lib/libc.so.6+0x2778f)
    #9 0x423279 in _start /build/glibc-2.33/csu/../sysdeps/x86_64/start.S:120

0x6310002a87f4 is located 12 bytes to the left of 68688-byte region [0x6310002a8800,0x6310002b9450)
allocated by thread T0 here:
    #0 0x4c9497 in __interceptor_malloc (/home/pca006132/code/test/manifold/buildCPP/tools/perfTest+0x4c9497)
    #1 0x5642b9 in manifold::ManagedVec<glm::vec<3, float, (glm::qualifier)0> >::mallocManaged(glm::vec<3, float, (glm::qualifier)0>**, unsigned long) /home/pca006132/code/test/manifold/utilities/include/vec_dh.h:257:36
    #2 0x5642b9 in manifold::ManagedVec<glm::vec<3, float, (glm::qualifier)0> >::reserve(unsigned long) /home/pca006132/code/test/manifold/utilities/include/vec_dh.h:158:7
    #3 0x5642b9 in manifold::ManagedVec<glm::vec<3, float, (glm::qualifier)0> >::push_back(glm::vec<3, float, (glm::qualifier)0> const&) /home/pca006132/code/test/manifold/utilities/include/vec_dh.h:186:7
    #4 0x5642b9 in manifold::VecDH<glm::vec<3, float, (glm::qualifier)0> >::push_back(glm::vec<3, float, (glm::qualifier)0> const&) /home/pca006132/code/test/manifold/utilities/include/vec_dh.h:417:40
    #5 0x5642b9 in manifold::Manifold::Impl::FormLoop(int, int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:178:12
    #6 0x560e31 in manifold::Manifold::Impl::CollapseEdge(int) /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:294:9

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/pca006132/code/test/manifold/manifold/src/edge_op.cpp:211:50 in manifold::Manifold::Impl::RemoveIfFolded(int)

Manifold as Header Library

It would be nice to be able to use manifold as a header library.

Are there any downside or opposition to restructuring it like that?

Feature request: JS interface + WASM module

This is a very interesting endeavor. Congratulations @elalish !

This is a wishlist item:

  • JS interface so one can write JS/TS and integrate it with Three.js for display and manipulation.
  • WASM module so you can use it directly in a browser.

Question : Emscripten integration

Hi !

I'm trying to integrate the library with emscripten and i'm a bit struggling.
I tried a lot of stuff but nothing worked.

Does anyone know a proper way to do it ?

Thanks a lot

exception in polygon.cpp

As discussed previously, here is example input leading to:

Error in file: ...\manifold\polygon\src\polygon.cpp (599): 'skipped.empty() || !vert->IsPast(skipped.back(), precision_)' is false: Not Geometrically Valid! None of the skipped verts is valid.

a.obj:

v 0.000000 0.000000 0.000000
v 0.000000 230.000000 0.000000
v -1630.000000 230.000000 0.000000
v -1400.000000 0.000000 0.000000
v 0.000000 0.000000 -2143.000000
v -1630.000000 230.000000 -2143.000000
v 0.000000 230.000000 -2143.000000
v -1400.000000 0.000000 -2143.000000
f 1 2 3
f 3 4 1
f 5 6 7
f 6 5 8
f 7 3 2
f 7 6 3
f 6 4 3
f 6 8 4
f 8 1 4
f 8 5 1
f 5 2 1
f 5 7 2

b.obj:

v -1185.000000 -70.000000 -2143.000000
v -305.000000 -70.000000 -2143.000000
v -1185.000000 -70.000000 0.000000
v -305.000000 -70.000000 0.000000
v -1185.000000 15320.000000 0.000000
v -305.000000 15320.000000 -2143.000000
v -1185.000000 15320.000000 -2143.000000
v -305.000000 15320.000000 0.000000
v -1185.000000 460.000000 0.000000
v -305.000000 460.000000 0.000000
v -1185.000000 460.000000 -2143.000000
v -305.000000 460.000000 -2143.000000
v -1185.000000 160.000000 -2143.000000
v -305.000000 160.000000 0.000000
v -1185.000000 160.000000 0.000000
v -305.000000 160.000000 -2143.000000
f 1 2 3
f 4 3 2
f 5 6 7
f 6 5 8
f 3 7 1
f 5 7 3
f 4 5 3
f 8 5 4
f 2 8 4
f 6 8 2
f 1 6 2
f 7 6 1
f 9 10 11
f 12 11 10
f 13 14 15
f 14 13 16
f 11 15 9
f 13 15 11
f 12 13 11
f 16 13 12
f 10 16 12
f 14 16 10
f 9 14 10
f 15 14 9

here is what they look like:
a.obj
b.obj

the exception happens when we try to get the result of a - b.

Mesh Offsetting

Mesh offsetting seems very useful for adding tolerance to parts, especially when combined with face selection.

I wonder if I can just offset each vertices according to their tangent? Although we may need to recompute the tangent if we only selected a subset of faces connecting to that vertex. OK this will not work.

union error for manifolds

The following code will union 4 manifolds (should all be valid, checked via IsManifold). With MANIFOLD_USE_OMP=on or using CUDA, it will non-deterministically fail. With MANIFOLD_USE_CPP=on, it will fail for the first run. The commented part is to show that these manifolds don't intersect each other (but they do touch each other). Keeping only the first two elements of the vector will cause OpenMP to union them correctly, but the sequential backend will still throw an error.

#include "manifold.h"

using namespace manifold;

void unionAll(std::vector<Manifold> manifolds, std::vector<int> indices) {
  Manifold result;
  for (int i : indices) {
    // Manifold intersection = result ^ manifolds[i];
    // std::cout << "intersections: " << intersection.NumVert() << std::endl;
    result += manifolds[i];
  }
}

int main() {
  // cannot find a better way to produce this...
  std::vector<glm::vec3> vertPos(
      {{-8.3, -8.3, 0},  {-7, -7, 0},      {-7, -7.05, 1},   {-7, -7, 1},
       {-2.5, -7.05, 1}, {-2.5, -7, 1},    {-2.5, -6.75, 1}, {-8.3, -8.3, 6},
       {-7, -7.05, 6},   {-2.5, -7.05, 6}, {-2.5, -6.75, 6}, {-8.3, 8.3, 0},
       {-7, 7, 0},       {-7, 7, 1},       {-7, 7.05, 1},    {-2.5, 6.75, 1},
       {-2.5, 7, 1},     {-2.5, 7.05, 1},  {-8.3, 8.3, 6},   {-7, 7.05, 6},
       {-2.5, 6.75, 6},  {-2.5, 7.05, 6},  {2.5, -7.05, 1},  {2.5, -7, 1},
       {2.5, -6.75, 1},  {7, -7, 0},       {8.3, -8.3, 0},   {7, -7.05, 1},
       {7, -7, 1},       {2.5, -7.05, 6},  {2.5, -6.75, 6},  {7, -7.05, 6},
       {8.3, -8.3, 6},   {2.5, 6.75, 1},   {2.5, 7, 1},      {2.5, 7.05, 1},
       {7, 7, 0},        {8.3, 8.3, 0},    {7, 7, 1},        {7, 7.05, 1},
       {2.5, 6.75, 6},   {2.5, 7.05, 6},   {7, 7.05, 6},     {8.3, 8.3, 6}});

  std::vector<glm::ivec3> triVerts(
      {{5, 1, 3},    {3, 2, 4},    {2, 8, 4},    {12, 1, 0},   {3, 1, 13},
       {11, 0, 7},   {19, 2, 3},   {1, 26, 0},   {4, 5, 3},    {25, 1, 5},
       {6, 23, 5},   {10, 5, 4},   {6, 5, 10},   {6, 10, 24},  {19, 8, 2},
       {18, 7, 8},   {4, 8, 9},    {7, 0, 32},   {10, 4, 9},   {32, 8, 7},
       {8, 32, 9},   {30, 10, 9},  {11, 12, 0},  {12, 13, 1},  {19, 3, 13},
       {12, 16, 13}, {14, 13, 16}, {13, 14, 19}, {34, 16, 12}, {11, 36, 12},
       {14, 16, 17}, {16, 33, 15}, {37, 11, 18}, {17, 21, 14}, {20, 16, 15},
       {17, 16, 20}, {7, 18, 11},  {8, 19, 18},  {14, 21, 19}, {21, 18, 19},
       {21, 17, 20}, {15, 40, 20}, {18, 21, 41}, {41, 21, 20}, {24, 23, 6},
       {25, 26, 1},  {23, 25, 5},  {27, 23, 22}, {0, 26, 32},  {22, 23, 30},
       {30, 23, 24}, {27, 22, 29}, {28, 25, 23}, {28, 23, 27}, {28, 27, 31},
       {25, 28, 36}, {36, 26, 25}, {38, 28, 31}, {24, 10, 30}, {22, 30, 29},
       {30, 9, 29},  {32, 29, 9},  {27, 29, 31}, {32, 31, 29}, {43, 32, 26},
       {31, 32, 43}, {38, 34, 12}, {34, 33, 16}, {36, 38, 12}, {37, 36, 11},
       {35, 34, 38}, {40, 15, 33}, {33, 34, 40}, {40, 34, 35}, {38, 36, 28},
       {37, 26, 36}, {26, 37, 43}, {39, 38, 31}, {38, 39, 35}, {42, 35, 39},
       {35, 41, 40}, {18, 43, 37}, {41, 35, 42}, {20, 40, 41}, {41, 42, 18},
       {18, 42, 43}, {31, 42, 39}, {43, 42, 31}});

  Manifold m1 = Manifold(Mesh{vertPos, triVerts});
  std::cout << "is m1 a manifold? " << m1.IsManifold() << std::endl;

  Manifold m2 = Manifold::Cube({14, 14, 1}, true).Translate({0, 0, 0.5});

  std::vector<Manifold> manifolds;
  manifolds.push_back(m1);
  manifolds.push_back(m2);

  manifolds.push_back(m1);
  manifolds.back().Translate({18, 0, 0});
  manifolds.push_back(m2);
  manifolds.back().Translate({18, 0, 0});

  for (int i = 0; i < 10; i++) {
    std::cout << "union order: 0 1 2 3" << std::endl;
    unionAll(manifolds, {0, 1, 2, 3});
    std::cout << "union order: 0 2 1 3" << std::endl;
    unionAll(manifolds, {0, 2, 1, 3});
  }
  return 0;
}

Simplify face triangulation

Currently, vertices coming from different meshes are labelled with different meshID, preventing them from merging. However, when joining manifolds face-to-face, it may be desirable to assign vertices with the same original meshID the same meshID and redo/simplify the face triangulation to reduce the number of vertices.

For example, consider the result of the Boolean.FaceUnion test:
image

Can we make it so that it will not have vertices in the middle?

Seg fault on CUDA

Ugh, I really wish our CI had a GPU. I just realized I've been neglecting to test on CUDA locally, and honestly I'm not sure for how long. However, today I noticed that Manifold.SmoothSphere gives: for_each: failed to synchronize: cudaErrorIllegalAddress: an illegal memory access was encountered" thrown in the test body. and then Manifold.ManualSmooth seg faults, but just on CUDA.

I went back to #157 and found the same problem there. I'm having some trouble getting things to build before that, probably because I need different flags or something. @pca006132 Can you repro?

triangulator memory corruption

This tracks the bug mentioned in #160

I managed to reproduce this with address sanitizer enabled, giving some useful backtrace:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from Boolean
[ RUN      ] Boolean.Close
=================================================================
==14036==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x7fff00b0b510 in thread T0
    #0 0x52ae07 in operator delete(void*) (/home/pca006132/code/manifold/build/test/manifold_test+0x52ae07)
    #1 0x5c55bb in __gnu_cxx::new_allocator<std::_List_node<(anonymous namespace)::Monotones::EdgePair> >::deallocate(std::_List_node<(anonymous namespace)::Monotones::EdgePair>*, unsigned long) /nix/store/as1xzrm2921pnxx4jvxj39jn4v88wdy1-gcc-11.3.0/include/c++/11.3.0/ext/new_allocator.h:145:2
    #2 0x5c55bb in std::allocator_traits<std::allocator<std::_List_node<(anonymous namespace)::Monotones::EdgePair> > >::deallocate(std::allocator<std::_List_node<(anonymous namespace)::Monotones::EdgePair> >&, std::_List_node<(anonymous namespace)::Monotones::EdgePair>*, unsigned long) /nix/store/as1xzrm2921pnxx4jvxj39jn4v88wdy1-gcc-11.3.0/include/c++/11.3.0/bits/alloc_traits.h:496:13
    #3 0x5c55bb in std::__cxx11::_List_base<(anonymous namespace)::Monotones::EdgePair, std::allocator<(anonymous namespace)::Monotones::EdgePair> >::_M_put_node(std::_List_node<(anonymous namespace)::Monotones::EdgePair>*) /nix/store/as1xzrm2921pnxx4jvxj39jn4v88wdy1-gcc-11.3.0/include/c++/11.3.0/bits/stl_list.h:446:9
    #4 0x5c55bb in std::__cxx11::_List_base<(anonymous namespace)::Monotones::EdgePair, std::allocator<(anonymous namespace)::Monotones::EdgePair> >::_M_clear() /nix/store/as1xzrm2921pnxx4jvxj39jn4v88wdy1-gcc-11.3.0/include/c++/11.3.0/bits/list.tcc:81:4
    #5 0x5c55bb in std::__cxx11::_List_base<(anonymous namespace)::Monotones::EdgePair, std::allocator<(anonymous namespace)::Monotones::EdgePair> >::~_List_base() /nix/store/as1xzrm2921pnxx4jvxj39jn4v88wdy1-gcc-11.3.0/include/c++/11.3.0/bits/stl_list.h:499:9
    #6 0x5c55bb in (anonymous namespace)::Monotones::~Monotones() /home/pca006132/code/manifold/src/polygon/src/polygon.cpp:65:7
    #7 0x5c55bb in manifold::Triangulate(std::vector<std::vector<manifold::PolyVert, std::allocator<manifold::PolyVert> >, std::allocator<std::vector<manifold::PolyVert, std::allocator<manifold::PolyVert> > > > const&, float) /home/pca006132/code/manifold/src/polygon/src/polygon.cpp:922:3
    #8 0x76ca66 in manifold::Manifold::Impl::Face2Tri(manifold::VecDH<int> const&, manifold::VecDH<manifold::BaryRef> const&, manifold::VecDH<int> const&) /home/pca006132/code/manifold/src/manifold/src/face_op.cpp:152:41
    #9 0x759cdb in manifold::Boolean3::Result(manifold::Manifold::OpType) const /home/pca006132/code/manifold/src/manifold/src/boolean_result.cpp:682:8
    #10 0x6a4fef in manifold::CsgOpNode::ToLeafNode() const /home/pca006132/code/manifold/src/manifold/src/csg_tree.cpp:289:50
    #11 0x6f0a29 in manifold::Manifold::GetCsgLeafNode() const /home/pca006132/code/manifold/src/manifold/src/manifold.cpp:83:22
    #12 0x6f82fb in manifold::Manifold::IsManifold() const /home/pca006132/code/manifold/src/manifold/src/manifold.cpp:333:10
    #13 0x5a6651 in Boolean_Close_Test::TestBody() /home/pca006132/code/manifold/test/mesh_test.cpp:924:5
    #14 0x665a10 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2443:10
    #15 0x665a10 in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2479:14
    #16 0x5fdc8f in testing::Test::Run() /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2517:5
    #17 0x6014db in testing::TestInfo::Run() /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2693:11
    #18 0x602c8f in testing::TestCase::Run() /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2811:28
    #19 0x62b268 in testing::internal::UnitTestImpl::RunAllTests() /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:5177:43
    #20 0x667d50 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2443:10
    #21 0x667d50 in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:2479:14
    #22 0x62a09a in testing::UnitTest::Run() /home/pca006132/code/manifold/test/third_party/google_test/googletest/src/gtest.cc:4786:10
    #23 0x5be4de in RUN_ALL_TESTS() /home/pca006132/code/manifold/test/third_party/google_test/googletest/include/gtest/gtest.h:2341:46
    #24 0x5be4de in main /home/pca006132/code/manifold/test/test_main.cpp:56:10
    #25 0x7fa9d7b0d236 in __libc_start_call_main (/nix/store/scd5n7xsn0hh0lvhhnycr9gx0h8xfzsl-glibc-2.34-210/lib/libc.so.6+0x29236)
    #26 0x7fa9d7b0d2f4 in __libc_start_main@GLIBC_2.2.5 (/nix/store/scd5n7xsn0hh0lvhhnycr9gx0h8xfzsl-glibc-2.34-210/lib/libc.so.6+0x292f4)
    #27 0x44b8c0 in _start /build/glibc-2.34/csu/../sysdeps/x86_64/start.S:116


Address 0x7ffd43ec2b90 is located in stack of thread T0 at offset 1680 in frame
    #0 0x5be6ff in manifold::Triangulate(std::vector<std::vector<manifold::PolyVert, std::allocator<manifold::PolyVert> >, std::allocator<std::vector<manifold::PolyVert, std::allocator<manifold::PolyVert> > > > const&, float) /home/pca006132/code/manifold/src/polygon/src/polygon.cpp:913

  This frame has 32 object(s):
    [32, 40) '__dnew.i.i249.i'
    [64, 72) '__dnew.i.i234.i'
    [96, 104) '__dnew.i.i202.i'
    [128, 136) '__dnew.i.i.i'
    [160, 264) 'triangulator.i' (line 108)
    [304, 336) 'ref.tmp77.i' (line 130)
    [368, 400) 'ref.tmp81.i' (line 130)
    [432, 464) 'ref.tmp118.i' (line 137)
    [496, 528) 'ref.tmp122.i' (line 137)
    [560, 568) '__dnew.i.i304.i.i'
    [592, 600) '__dnew.i.i272.i.i'
    [624, 656) 'ref.tmp26.i.i' (line 805)
    [688, 720) 'ref.tmp28.i.i' (line 805)
    [752, 784) 'ref.tmp51.i.i' (line 808)
    [816, 848) 'ref.tmp55.i.i' (line 808)
    [880, 888) '__dnew.i.i906.i.i'
    [912, 920) '__dnew.i.i891.i.i'
    [944, 952) '__dnew.i.i850.i.i'
    [976, 984) '__dnew.i.i835.i.i'
    [1008, 1016) '__dnew.i.i636.i.i'
    [1040, 1048) '__dnew.i.i543.i.i'
    [1072, 1080) '__dnew.i.i.i.i'
    [1104, 1136) 'nextAttached.i.i' (line 635)
    [1168, 1200) 'ref.tmp79.i.i' (line 673)
    [1232, 1264) 'ref.tmp83.i.i' (line 673)
    [1296, 1328) 'ref.tmp174.i.i' (line 695)
    [1360, 1392) 'ref.tmp178.i.i' (line 695)
    [1424, 1456) 'ref.tmp236.i.i' (line 702)
    [1488, 1520) 'ref.tmp240.i.i' (line 702)
    [1552, 1584) 'ref.tmp266.i.i' (line 704)
    [1616, 1648) 'ref.tmp270.i.i' (line 704)
    [1680, 1760) 'monotones' (line 917) <== Memory access at offset 1680 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)

Triangulation error near precision limit

@pca006132 I'm breaking you're repro out here, since I think it's separate from the issue it's in currently, but definitely worth looking into. I can also repro it locally, which is helpful.

Copied from #139 (comment), which was inspired from #141 (comment)

TEST(Boolean, Close) {
  Manifold a = Manifold::Sphere(10, 256);
  Manifold result = a;
  for (int i = 0; i < 10; i++) {
    std::cout << i << std::endl;
    result ^= a.Translate({a.Precision()/10 * i, 0.0, 0.0});
    EXPECT_TRUE(result.IsManifold());
    EXPECT_TRUE(result.MatchesTriNormals());
  }
}

What I need to check: is this polygon actually epsilon-overlapped, or does the triangulator just have a bug? If it is overlapped, this may imply the precision is not well-bounded (due to nearly-parallel planes?), in which case it may be better to look into making the triangulator robust to overlapping input rather than intentionally failing.

feature request: lazy boolean operations

I guess it might be better to open an issue for this and discuss about the possible implementation for lazy boolean operations. The opt branch of my fork only implements the optimizations for union.

Idea: Apply boolean operations lazily to allow more optimizations, e.g. operation reordering or cheap batch processing for certain operations.

Operation reordering:

  1. Permutation for union and intersection. The idea is to work on manifolds that have smaller number of vertices/faces first. For larger manifolds, the time required for boolean operations is about linear to the number of vertices/faces, so work on manifolds that have smaller number of vertices/faces can reduce the time required for the operation.
  2. De Morgan's Laws (?): a - b - c <=> a - (b + c). Again, the idea is to minimize the number of required operations. For this case, b and c might be disjoint, if so they can be composed together cheaply. If not, the LHS is perhaps the cheapest way to do this.

Batch processing:

  1. Use compose instead of union for a set of pairwise disjoint manifolds. Although checking for pairwise disjointness can take O(n^2) time with a simple implementation, it is still much cheaper in practice than doing union for up to something like 10000 manifolds.
  2. Similarly, we can do batch processing for intersection by discarding disjoint manifolds.

Cache for manifolds that only differ in transformation: We can use a shared_ptr of the underlying CSG tree, and store the transformation separately. When we need to evaluate the CSG tree, e.g. when exporting the object or need to apply some complicated operations on it, we can cache the result and then apply transform to a copy of the result. This way, we can store objects that only differ in transformation (e.g. a grid of objects) cheaply, and allows us to defer the evaluation of the CSG tree as late as possible. This way, copying the manifold is also essentially free: we only need to copy the shared_ptr and the 4x3 matrix.

Python bindings

@pca006132 has in his fork a branch with Python bindings. Just to see how far I get, I tried to apply those patches for python to the most recent upstream manifold which now builds perfectly with CPP compile option on my mac. The python bindings and the example pythonTest seemed to compile perfectly. In the manifold root folder where the python test script test.py I created a symbolic link named pythonTest to the compiled shared library and assumed I could run python test. Well, that is how far I got:

    from pythonTest import ManifoldSet, Polygons
ModuleNotFoundError: No module named 'pythonTest'

I am aware that this is all very early stage and unstable and the examples at pybind are a tiny bit different (using pip to compile and install the examples). So what step am I missing to get that module imported ?

Substract operation failed with memory access exception

Снимок

Steps to reproduce:

  Mesh firstMesh;
  firstMesh.vertPos = {
      {0.000000, 0.000000, 0.000000},
      {1850.000000, 0.000000, 0.000000},
      {1850.000000, 170.000000, 0.000000},
      {0.000000, 170.000000, 0.000000},
      {0.000000, 0.000000, -3380.000000},
      {1850.000000, 170.000000, -3380.000000},
      {1850.000000, 0.000000, -3380.000000},
      {0.000000, 170.000000, -3380.000000}};
  firstMesh.triVerts = {{1, 2, 3}, {3, 4, 1}, {5, 6, 7}, {6, 5, 8},
                    {7, 3, 2}, {7, 6, 3}, {6, 4, 3}, {6, 8, 4},
                    {8, 1, 4}, {8, 5, 1}, {5, 2, 1}, {5, 7, 2}};

  Mesh secondMesh;
  secondMesh.vertPos = {{365.000000, 50105.000000, -3380.000000},
                    {0.000000, 50105.000000, -3380.000000},
                    {365.000000, 50105.000000, -1310.000000},
                    {1375.000000, 50105.000000, -3380.000000},
                    {1375.000000, 50105.000000, -1310.000000},
                    {1850.000000, 50105.000000, -3380.000000},
                    {0.000000, 50105.000000, 0.000000},
                    {1850.000000, 50105.000000, 0.000000},
                    {365.000000, 105.000000, -1310.000000},
                    {0.000000, 105.000000, -3380.000000},
                    {365.000000, 105.000000, -3380.000000},
                    {1850.000000, 105.000000, -3380.000000},
                    {1375.000000, 105.000000, -1310.000000},
                    {1375.000000, 105.000000, -3380.000000},
                    {0.000000, 105.000000, 0.000000},
                    {1850.000000, 105.000000, 0.000000}};
  secondMesh.triVerts = {
      {1, 2, 3},    {4, 5, 6},   {2, 7, 3},   {6, 5, 8},    {7, 8, 3},
      {5, 3, 8},    {5, 3, 8},   {9, 10, 11}, {12, 13, 14}, {9, 15, 10},
      {16, 13, 12}, {9, 16, 15}, {16, 9, 13}, {3, 11, 1},   {9, 11, 3},
      {5, 9, 3},    {13, 9, 5},  {4, 13, 5},  {14, 13, 4},  {6, 14, 4},
      {12, 14, 6},  {8, 12, 6},  {16, 12, 8}, {7, 16, 8},   {15, 16, 7},
      {2, 15, 7},   {10, 15, 2}, {1, 10, 2},  {11, 10, 1}};

  Manifold first(firstMesh);
  Manifold second(secondMesh);

  first -= second;

Submodule access error when trying to fork project

third_party/google_test is not cloneable (the url starts with git@ while the other submodules are all https:// urls and are fine.

Here is the full log:

git clone --recurse-submodules https://github.com/rsaccon/manifold.git
Cloning into 'manifold'...
remote: Enumerating objects: 4847, done.
remote: Counting objects: 100% (485/485), done.
remote: Compressing objects: 100% (171/171), done.
remote: Total 4847 (delta 332), reused 407 (delta 298), pack-reused 4362
Receiving objects: 100% (4847/4847), 24.07 MiB | 3.28 MiB/s, done.
Resolving deltas: 100% (3185/3185), done.
Submodule 'third_party/assimp' (https://github.com/assimp/assimp) registered for path 'third_party/assimp'
Submodule 'third_party/glm' (https://github.com/g-truc/glm) registered for path 'third_party/glm'
Submodule 'third_party/google_test' ([email protected]:google/googletest.git) registered for path 'third_party/google_test'
Submodule 'third_party/thrust' (https://github.com/NVIDIA/thrust) registered for path 'third_party/thrust'
Cloning into '/Users/robertosaccon/cAndCpp/manifold/third_party/assimp'...
remote: Enumerating objects: 71922, done.        
remote: Counting objects: 100% (8/8), done.        
remote: Compressing objects: 100% (4/4), done.        
remote: Total 71922 (delta 5), reused 5 (delta 4), pack-reused 71914        
Receiving objects: 100% (71922/71922), 190.19 MiB | 2.02 MiB/s, done.
Resolving deltas: 100% (51145/51145), done.
Cloning into '/Users/robertosaccon/cAndCpp/manifold/third_party/glm'...
remote: Enumerating objects: 56725, done.        
remote: Counting objects: 100% (435/435), done.        
remote: Compressing objects: 100% (179/179), done.        
remote: Total 56725 (delta 273), reused 329 (delta 256), pack-reused 56290        
Receiving objects: 100% (56725/56725), 69.17 MiB | 3.25 MiB/s, done.
Resolving deltas: 100% (42792/42792), done.
Cloning into '/Users/robertosaccon/cAndCpp/manifold/third_party/google_test'...
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
fatal: clone of '[email protected]:google/googletest.git' into submodule path '/Users/robertosaccon/cAndCpp/manifold/third_party/google_test' failed
Failed to clone 'third_party/google_test'. Retry scheduled
Cloning into '/Users/robertosaccon/cAndCpp/manifold/third_party/thrust'...
remote: Enumerating objects: 48193, done.        
remote: Counting objects: 100% (1687/1687), done.        
remote: Compressing objects: 100% (694/694), done.        
remote: Total 48193 (delta 1026), reused 1536 (delta 937), pack-reused 46506        
Receiving objects: 100% (48193/48193), 16.22 MiB | 3.31 MiB/s, done.
Resolving deltas: 100% (38310/38310), done.
Cloning into '/Users/robertosaccon/cAndCpp/manifold/third_party/google_test'...
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
fatal: clone of '[email protected]:google/googletest.git' into submodule path '/Users/robertosaccon/cAndCpp/manifold/third_party/google_test' failed
Failed to clone 'third_party/google_test' a second time, aborting

Suggestion: Three.js example on on homepage: https://elalish.github.io/manifold/

Once you have a Three.js example, it would be nice to feature it on the homepage of manifold with some type of impressive animation. Two objects moving relatively to each other and showing the complex intersection being resolved by this library in real time. That would immediately sell people on the value of this library.

infinite loop in CollapseEdge

Reproduce:

  1. Apply the following patch so you will notice the infinite loop instead of getting a crash when this goes OOM:
diff --git a/manifold/src/edge_op.cpp b/manifold/src/edge_op.cpp
index 20878e1..ca2267d 100644
--- a/manifold/src/edge_op.cpp
+++ b/manifold/src/edge_op.cpp
@@ -242,9 +242,14 @@ void Manifold::Impl::CollapseEdge(const int edge) {
   std::vector<int> edges;
   // Orbit endVert
   int current = halfedge[tri0edge[1]].pairedHalfedge;
+  int counter = 0;
   while (current != tri1edge[2]) {
     current = NextHalfedge(current);
     edges.push_back(current);
+    if (counter++ >= 10000000 && counter % 10000000 == 0) {
+      std::cout << "CollapseEdge: counter exceeded " << counter << std::endl;
+      std::cout << "cannot find " << tri1edge[2] << ", got " << current << std::endl;
+    }
     current = halfedge[current].pairedHalfedge;
   }
  1. Compile and run the following code:
#include "manifold.h"

using namespace manifold;

int main() {
    Manifold rod = Manifold::Cylinder(1.0, 0.4, -1.0, 20);
    float arrays1[][12] = {
        {  0,  0,  1,  1,    //
          -1,  0,  0,  2,    //
           0, -1,  0,  7 },  //
        {  1,  0,  0,  3,    //
           0,  1,  0,  2,    //
           0,  0,  1,  6 },  //
        {  0,  0,  1,  3,    //
          -1,  0,  0,  3,    //
           0, -1,  0,  6 },  //
        {  0,  0,  1,  3,    //
          -1,  0,  0,  3,    //
           0, -1,  0,  7,},  //
        {  0,  0,  1,  2,    //
          -1,  0,  0,  3,    //
           0, -1,  0,  8,},  //
        {  0,  0,  1,  1,    //
          -1,  0,  0,  3,    //
           0, -1,  0,  7,},  //
        {  1,  0,  0,  3,    //
           0,  0,  1,  4,    //
           0, -1,  0,  6,},  //
        {  1,  0,  0,  4,    //
           0,  0,  1,  4,    //
           0, -1,  0,  6,},  //
    };
    float arrays2[][12] = {
        {  0,  0,  1,  2,    //
          -1,  0,  0,  2,    //
           0, -1,  0,  7 },  //
        {  1,  0,  0,  3,    //
           0,  0,  1,  2,    //
           0, -1,  0,  6 },  //
        {  1,  0,  0,  4,    //
           0,  1,  0,  3,    //
           0,  0,  1,  6 },  //
        {  1,  0,  0,  3,    //
           0,  1,  0,  3,    //
           0,  0,  1,  7 },  //
        {  1,  0,  0,  2,    //
           0,  1,  0,  3,    //
           0,  0,  1,  7 },  //
        {  1,  0,  0,  1,    //
           0,  1,  0,  3,    //
           0,  0,  1,  7 },  //
        {  1,  0,  0,  3,    //
           0,  1,  0,  4,    //
           0,  0,  1,  7 },  //
        {  1,  0,  0,  3,    //
           0,  1,  0,  5,    //
           0,  0,  1,  6 },  //
        {  0,  0,  1,  3,    //
          -1,  0,  0,  4,    //
           0, -1,  0,  6,},  //
    };

    Manifold m1;
    for (auto &array : arrays1) {
        glm::mat4x3 mat;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                mat[i][j] = array[j * 4 + i];
            }
        }
        m1 += Manifold(rod).Transform(mat);
    }

    Manifold m2;
    for (auto &array : arrays2) {
        glm::mat4x3 mat;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                mat[i][j] = array[j * 4 + i];
            }
        }
        m2 += Manifold(rod).Transform(mat);
    }

    m1 += m2;

    return 0;
}

Interestingly, by changing the order of the union operations, it will not trigger this problem. I guess this example can be further reduced, but haven't yet tried doing that. Found this while porting some of the benchmarks in https://gist.github.com/ochafik/2db96400e3c1f73558fcede990b8a355 to the pybind11 binding.

Add clang-format pre-commit hook

I'm pretty sure there's a way to tell Github to run clang-format on any submitted PR, which would be nice both with viewing diffs and with keeping the code base consistent. I have VSCode set up to use the standard google style with clang-format, so that's what I'd like automatically applied for other contributors.

README: clarify arity of mesh faces

The 'Manifoldness' section of the Wiki talks about "triangle meshes".

Can this library work with meshes that contain faces of arity higher than three?

If not this constraint should probably be mentioned in the first sentence of the README as it may save people looking for something that does (and not checking the Wiki) a lot of time. :)

Specifically: If I input a mesh made out of e.g. quads and perform a boolean operation, will the result mesh only contain triangles? Even in areas not affected by the boolean operation at all?

Separate meshIO from manifold bundles

meshIO is not really a core part of this Manifold library. It is the only part that depends on Assimp (a large, complicated dependency) and it is unlikely to fit into other libraries well, as they probably have their own mesh input/output anyway. I only included meshIO as a means to quickly test this library, but the functionality is lacking (no texture/property support for one thing). I don't want to focus on that, as it's a complicated area in its own right and others do it better. For C++, it's easy enough to not include that part, but for building bundles like WASM and Python, I think it's important to keep this separate.

I'm fine with either removing meshIO from these bundles to focus only on our core library, or if we find it to be really useful, then making a separate bundle for meshIO. There is no dependency between meshIO and manifold since they communicate via Mesh, so the separation should be pretty clean.

suggestion: fuzzing

Perhaps we can use https://llvm.org/docs/LibFuzzer.html to test the library? Generate a number of primitive objects, perform random translation/scaling/rotation and boolean operations for them. There are a few things we can test for:

  1. Memory usage.
  2. Should not crash.
  3. Compare with other libraries like CGAL? Not sure about if this is possible.

3D Convex Hull

I was trying to port some tests from OpenSCAD to python for more test cases and performance check. I'm currently looking at https://gist.github.com/ochafik/2db96400e3c1f73558fcede990b8a355 . It seems that quite a lot of the more complicated cases are using hull(), so I guess it would be desirable to implement it.

Not sure if we should implement it by ourselves or use an existing implementation. I saw a header only library here: https://github.com/leomccormack/convhull_3d/blob/master/convhull_3d.h and can probably be parallelized if needed.

Test input that causes the mesh to be invisible

I wasn't able to recreate the steps, but here are the scene files and screenshots. Note that this file isn't an exact reproducable test case.

  1. the meshes separated
  2. bool meshes
  3. By moving the meshes when they are chained, there are configurations that make the mesh disappear.

node_3d.zip

Before:

image

After:

image

Lazy triangulation after boolean operations

In my use case, I have to combine some complicated models together via union, but only have a few faces touching each other (or maybe no intersection). Is it possible to only triangulate the affected faces or somehow limit the computation to neighboring edges/vertices?

Example performance test:

#include "manifold.h"
#include "meshIO.h"
#include "glm/vec3.hpp"
#include <chrono>

using namespace manifold;

int main() {
    Manifold m = ImportMesh("test.stl");
    Manifold result = m;
    for (int i = 0; i < 100; i++) {
        auto start = std::chrono::high_resolution_clock::now();
        result = result + m.Translate(glm::vec3(18*i, 0, 0));
        auto end = std::chrono::high_resolution_clock::now();
        std::cout << "Iteration " << i << ": " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
    }
    return 0;
}

Result: Iteration time increases as result becomes larger.

My model: test.zip (unpack for the test.stl)
The target is something like this:
image

So their bounding boxes will intersect, but they are actually disjoint. (I can probably use combine, but I am a bit afraid that I may accidentally create something that is not valid).

Trying to compile manifold on a Mac

I am using the latest patches for emscripten on an Intel Mac with MacOS 11.6.5. And I believe to have installed all the dependencies. For Mac there is no nvcc. Here is how far I got with the other options:

compiling for CPP:

cmake -DCMAKE_BUILD_TYPE=Release -DTHRUST_BACKEND=CPP .. && make

error:

...
In file included from /Users/robertosaccon/cAndCpp/manifold/collider/src/collider.cpp:15:
In file included from /Users/robertosaccon/cAndCpp/manifold/collider/include/collider.cuh:16:
/Users/robertosaccon/cAndCpp/manifold/utilities/include/sparse.cuh:16:10: fatal error: 'thrust/binary_search.h' file not found
#include <thrust/binary_search.h>
         ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[2]: *** [collider/CMakeFiles/collider.dir/src/collider.cpp.o] Error 1
make[1]: *** [collider/CMakeFiles/collider.dir/all] Error 2
make: *** [all] Error 2

and my attempt for emscripten:

emcmake cmake -DCMAKE_BUILD_TYPE=Release .. && emmake make

error:

...
CMake Error at third_party/CMakeLists.txt:8 (add_subdirectory):
  add_subdirectory given source "assimp" which is not an existing directory.


CMake Error at tools/CMakeLists.txt:16 (find_package):
  By not providing "FindCGAL.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "CGAL", but
  CMake did not find one.

  Could not find a package configuration file provided by "CGAL" with any of
  the following names:

    CGALConfig.cmake
    cgal-config.cmake

  Add the installation prefix of "CGAL" to CMAKE_PREFIX_PATH or set
  "CGAL_DIR" to a directory containing one of the above files.  If "CGAL"
  provides a separate development package or SDK, be sure it has been
  installed.


-- Configuring incomplete, errors occurred!

I have CGAL installed (with brew). Any advice on how to build it on a Mac ?

Read vertNormal for Smooth

Currently the vertNormal supplied in a Mesh is ignored and recalculated instead. Ideally it should be read and used to form the halfedgeTangent vector. Need to ensure vertNormal_ is making it through SimplifyTopology() without getting broken.

Improve Godot Engine's boolean operator engine (CSG) with `elalish/manifold`

  • Restore normals and tangents
  • Postpone running a profiler and see if there's easy bottlenecks
  • Write a Godot Engine proposal
  • Generating CSG nodes is slow on a full character mesh added to a box
  • Can start providing test cases that crash the godot engine patched with manifold
  • Remove exceptions from elalish/manifold ?
  • Propose idea
  • Ask for comments
  • Investigate code details
  • Tech lead of Godot Engine is ok with requiring manifold geometry inputs for CSG
  • Remove requiring Cuda Developer Kit to build.
  • Check performance latency of mesh generation (per frame? per second? per minute?)
  • Blocked on removal of boost dependency
  • The results of boolean operations look great. No gaps.
  • Restore UV coordinates
  • Restore materials

Add SDF system

Signed distance functions (SDF) are another way to represent 3D solids. They can be discrete (voxels) or continuous (mathematical functions). Traditionally they can be converted to a manifold surface mesh via the Marching Cubes algorithm. I think an implementation of this will fit nicely as an alternative way to create complicated manifolds. SDFs naturally handle Boolean-type operations as well, but they do so in ways that scale differently computationally and can also soften the intersections naturally. I also have some ideas to improve on Marching Cubes via my own Marching Tetrahedra algorithm.

Add minGap function

A convenient function would be to measure the minimum gap between two Manifolds (good for checking that mechanisms have the proper tolerances). The signature would be: float Manifold.MinGap(const Manifold& other, float searchLength) const

It would always return a value between zero and searchLength. It would perform an intersection and if that was non-empty, it returns zero (overlapping). If not, it will collide the triangles of each mesh with the verts of the other, expanded into boxes 2*searchLength wide, then for those collisions, calculate point-to-triangle distances. The minimum is returned.

Feature request: Polyline/Curve representation

Another wishlist item, feel free to ignore.

I think this need a Polyline/curve class. At a simplistic level engineering models usually are created first in 2D and then "extrude"-ed into 3D shapes which are then CSG'ed together. You are missing the Polyline/curve class that would create the 2D shapes that are fundamental to CAD. This feels like a gap.

It would be nice to be able to similarly treat them as smoothable Bezier curves like the tri-meshes so they are equally refineable like the trimeshes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.