From f712fd5f5a9e8003ff500728c5ad9b484de0545b Mon Sep 17 00:00:00 2001 From: Marcell Leleszi Date: Sun, 3 Mar 2024 13:43:07 +0100 Subject: [PATCH 01/48] Add tests for intersection --- test/boolean_test.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index 6705a7aec..8419fa244 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -142,6 +142,28 @@ TEST(Boolean, SelfSubtract) { EXPECT_FLOAT_EQ(prop.surfaceArea, 0.0f); } +TEST(Boolean, SelfIntersect) { + Manifold cube = Manifold::Cube(); + Manifold intersect = cube ^ cube; + + auto cubeProp = cube.GetProperties(); + auto intersectProp = intersect.GetProperties(); + + EXPECT_FLOAT_EQ(cubeProp.volume, intersectProp.volume); + EXPECT_FLOAT_EQ(cubeProp.surfaceArea, intersectProp.surfaceArea); +} + +TEST(Boolean, Intersect) { + Manifold a = Manifold::Cube({1.0f, 1.0f, 1.0f}); + Manifold b = Manifold::Cube({1.0f, 1.0f, 1.0f}).Translate({0.5f, 0.0f, 0.0f}); + Manifold intersect = a ^ b; + + auto prop = intersect.GetProperties(); + + EXPECT_FLOAT_EQ(prop.volume, 0.5f); + EXPECT_FLOAT_EQ(prop.surfaceArea, 4.0f); +} + TEST(Boolean, Perturb) { Mesh tmp; tmp.vertPos = {{0.0f, 0.0f, 0.0f}, From 903c57319c01a1298f7a24a152619ca14bf7232b Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 3 Mar 2024 15:34:11 +0100 Subject: [PATCH 02/48] Add POC MinGap implementation and tests --- src/manifold/include/manifold.h | 2 + src/manifold/src/manifold.cpp | 100 ++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 2 +- test/mingap_test.cpp | 83 ++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 test/mingap_test.cpp diff --git a/src/manifold/include/manifold.h b/src/manifold/include/manifold.h index c1e912af6..de462efec 100644 --- a/src/manifold/include/manifold.h +++ b/src/manifold/include/manifold.h @@ -293,6 +293,8 @@ class Manifold { int NumOverlaps(const Manifold& second) const; ///@} + float MinGap(const Manifold& other, float searchLength) const; + struct Impl; private: diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 0ea4d3511..9a31f38e6 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -881,4 +881,104 @@ Manifold Manifold::Hull() const { return Hull(GetMesh().vertPos); } Manifold Manifold::Hull(const std::vector& manifolds) { return Compose(manifolds).Hull(); } + +float Manifold::MinGap(const Manifold& other, float searchLength) const { + // Get intersection + auto intersect = *this ^ other; + auto prop = intersect.GetProperties(); + + // If intersection is non zero, return zero (overlapping) + if (prop.volume != 0) { + return 0.0f; + } + + auto firstMesh = this->GetMesh(); + auto secondMesh = other.GetMesh(); + + float minDistance = searchLength; + + // Helper functions + auto closestPointOnLineSegment = [](const glm::vec3& v, const glm::vec3& w, + const glm::vec3& p) -> glm::vec3 { + const float t = glm::dot(p - v, w - v) / glm::length(w - v); + + if (t < 0.0f) return v; + if (t > 1.0f) return w; + + return v + t * (w - v); + }; + + // Assumes orientation, not sure if correct + auto triangleDistance = [&closestPointOnLineSegment]( + const glm::vec3& A, const glm::vec3& B, + const glm::vec3& C, const glm::vec3& D, + const glm::vec3& E, const glm::vec3& F) -> float { + glm::vec3 closestAB = closestPointOnLineSegment(A, B, D); + glm::vec3 closestBC = closestPointOnLineSegment(B, C, D); + glm::vec3 closestCA = closestPointOnLineSegment(C, A, D); + + glm::vec3 closestDE = closestPointOnLineSegment(D, E, A); + glm::vec3 closestEF = closestPointOnLineSegment(E, F, A); + glm::vec3 closestFD = closestPointOnLineSegment(F, D, A); + + float distAB_DE = glm::length(closestAB - D); + float distBC_EF = glm::length(closestBC - E); + float distCA_FD = glm::length(closestCA - F); + + return std::min({distAB_DE, distBC_EF, distCA_FD}); + }; + + // Iterate over triangles from the first manifold + for (const auto& firstTriVert : firstMesh.triVerts) { + // Create AABB around the triangles, expanded by 2 * searchLength + glm::vec3 minBoundsFirst = + glm::min(glm::min(firstMesh.vertPos[firstTriVert.x], + firstMesh.vertPos[firstTriVert.y]), + firstMesh.vertPos[firstTriVert.z]) - + glm::vec3(searchLength); + + glm::vec3 maxBoundsFirst = + glm::max(glm::max(firstMesh.vertPos[firstTriVert.x], + firstMesh.vertPos[firstTriVert.y]), + firstMesh.vertPos[firstTriVert.z]) + + glm::vec3(searchLength); + + // Iterate over triangles from the second manifold + for (const auto& secondTriVert : secondMesh.triVerts) { + // Create AABB around the second manifold's triangles, expanded by 2 * + // searchLength + glm::vec3 minBoundsSecond = + glm::min(glm::min(secondMesh.vertPos[secondTriVert.x], + secondMesh.vertPos[secondTriVert.y]), + secondMesh.vertPos[secondTriVert.z]) - + glm::vec3(searchLength); + + glm::vec3 maxBoundsSecond = + glm::max(glm::max(secondMesh.vertPos[secondTriVert.x], + secondMesh.vertPos[secondTriVert.y]), + secondMesh.vertPos[secondTriVert.z]) + + glm::vec3(searchLength); + + // Check for AABB collision + if (minBoundsFirst.x <= maxBoundsSecond.x && + maxBoundsFirst.x >= minBoundsSecond.x && + minBoundsFirst.y <= maxBoundsSecond.y && + maxBoundsFirst.y >= minBoundsSecond.y && + minBoundsFirst.z <= maxBoundsSecond.z && + maxBoundsFirst.z >= minBoundsSecond.z) { + // AABBs overlap, calculate triangle-to-triangle distance + float distance = triangleDistance(firstMesh.vertPos[firstTriVert.x], + firstMesh.vertPos[firstTriVert.y], + firstMesh.vertPos[firstTriVert.z], + secondMesh.vertPos[secondTriVert.x], + secondMesh.vertPos[secondTriVert.y], + secondMesh.vertPos[secondTriVert.z]); + + minDistance = std::min(minDistance, distance); + } + } + } + + return minDistance; +} } // namespace manifold diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b9a45b1f6..9fe090e37 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,7 @@ project(manifold_test) set(CMAKE_CXX_STANDARD 17) enable_testing() -set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp) +set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp mingap_test.cpp) if(MANIFOLD_CBIND AND NOT EMSCRIPTEN) list(APPEND SOURCE_FILES manifoldc_test.cpp) diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp new file mode 100644 index 000000000..6cc63a054 --- /dev/null +++ b/test/mingap_test.cpp @@ -0,0 +1,83 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "manifold.h" +#include "test.h" + +#ifdef MANIFOLD_EXPORT +#include "meshIO.h" +#endif + +TEST(MinGap, CubeCube) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({2.0f, 2.0f, 0.0f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, sqrt(2)); +} + +TEST(MinGap, CubeCube2) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, sqrt(2) * 2); +} + +TEST(MinGap, CubeCubeOutOfBounds) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); + + float distance = a.MinGap(b, 0.1f); + + EXPECT_FLOAT_EQ(distance, 0.1f); +} + +TEST(MinGap, CubeSphereOverlapping) { + auto a = Manifold::Cube(); + auto b = Manifold::Sphere(1.0f); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, 0); +} + +TEST(MinGap, SphereSphere) { + auto a = Manifold::Sphere(1.0f); + auto b = Manifold::Sphere(1.0f).Translate({5.0f, 0.0f, 0.0f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, 3); +} + +TEST(MinGap, SphereSphere2) { + auto a = Manifold::Sphere(1.0f); + auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); +} + +TEST(MinGap, SphereSphereOutOfBounds) { + auto a = Manifold::Sphere(1.0f); + auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); + + float distance = a.MinGap(b, 0.1f); + + EXPECT_FLOAT_EQ(distance, 0.1f); +} From 0d1c8878c72ce697fd1c0293dd37685814aed21c Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 6 Mar 2024 10:28:21 +0100 Subject: [PATCH 03/48] Add tests where closest point falls on the triangle's face or on one of the edges --- test/mingap_test.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 6cc63a054..b6187f7b3 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -81,3 +81,28 @@ TEST(MinGap, SphereSphereOutOfBounds) { EXPECT_FLOAT_EQ(distance, 0.1f); } + +// failing +TEST(MinGap, ClosestPointOnEdge) { + auto a = Manifold::Cube(); + + auto b = Manifold::Sphere(1.0f); + b.Translate({3.0f, 0.0f, 0.5f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, 1); +} + +// failing +TEST(MinGap, ClosestPointOnTriangleFace) { + auto a = Manifold::Cube(); + a.Translate({0.0f, -0.25f, 0.0f}); + + auto b = Manifold::Sphere(1.0f); + b.Translate({3.0f, 0.0f, 0.5f}); + + float distance = a.MinGap(b, 10); + + EXPECT_FLOAT_EQ(distance, 1); +} From d1496a235121861b8ddfe8b9c4fab6175f5b93cb Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 6 Mar 2024 11:14:24 +0100 Subject: [PATCH 04/48] Create TriangleDistance declaration --- src/manifold/src/manifold.cpp | 49 +++++++------------------------- src/manifold/src/triangle_dist.h | 46 ++++++++++++++++++++++++++++++ test/mingap_test.cpp | 2 -- 3 files changed, 56 insertions(+), 41 deletions(-) create mode 100644 src/manifold/src/triangle_dist.h diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 9a31f38e6..336238be5 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -21,6 +21,7 @@ #include "csg_tree.h" #include "impl.h" #include "par.h" +#include "triangle_dist.h" namespace { using namespace manifold; @@ -897,40 +898,9 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { float minDistance = searchLength; - // Helper functions - auto closestPointOnLineSegment = [](const glm::vec3& v, const glm::vec3& w, - const glm::vec3& p) -> glm::vec3 { - const float t = glm::dot(p - v, w - v) / glm::length(w - v); - - if (t < 0.0f) return v; - if (t > 1.0f) return w; - - return v + t * (w - v); - }; - - // Assumes orientation, not sure if correct - auto triangleDistance = [&closestPointOnLineSegment]( - const glm::vec3& A, const glm::vec3& B, - const glm::vec3& C, const glm::vec3& D, - const glm::vec3& E, const glm::vec3& F) -> float { - glm::vec3 closestAB = closestPointOnLineSegment(A, B, D); - glm::vec3 closestBC = closestPointOnLineSegment(B, C, D); - glm::vec3 closestCA = closestPointOnLineSegment(C, A, D); - - glm::vec3 closestDE = closestPointOnLineSegment(D, E, A); - glm::vec3 closestEF = closestPointOnLineSegment(E, F, A); - glm::vec3 closestFD = closestPointOnLineSegment(F, D, A); - - float distAB_DE = glm::length(closestAB - D); - float distBC_EF = glm::length(closestBC - E); - float distCA_FD = glm::length(closestCA - F); - - return std::min({distAB_DE, distBC_EF, distCA_FD}); - }; - // Iterate over triangles from the first manifold for (const auto& firstTriVert : firstMesh.triVerts) { - // Create AABB around the triangles, expanded by 2 * searchLength + // Create AABB around the first triangle, expanded by 2 * searchLength glm::vec3 minBoundsFirst = glm::min(glm::min(firstMesh.vertPos[firstTriVert.x], firstMesh.vertPos[firstTriVert.y]), @@ -945,7 +915,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { // Iterate over triangles from the second manifold for (const auto& secondTriVert : secondMesh.triVerts) { - // Create AABB around the second manifold's triangles, expanded by 2 * + // Create AABB around the second triangle, expanded by 2 * // searchLength glm::vec3 minBoundsSecond = glm::min(glm::min(secondMesh.vertPos[secondTriVert.x], @@ -967,12 +937,13 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { minBoundsFirst.z <= maxBoundsSecond.z && maxBoundsFirst.z >= minBoundsSecond.z) { // AABBs overlap, calculate triangle-to-triangle distance - float distance = triangleDistance(firstMesh.vertPos[firstTriVert.x], - firstMesh.vertPos[firstTriVert.y], - firstMesh.vertPos[firstTriVert.z], - secondMesh.vertPos[secondTriVert.x], - secondMesh.vertPos[secondTriVert.y], - secondMesh.vertPos[secondTriVert.z]); + float distance = + TriangleDistance({firstMesh.vertPos[firstTriVert.x], + firstMesh.vertPos[firstTriVert.y], + firstMesh.vertPos[firstTriVert.z]}, + {secondMesh.vertPos[secondTriVert.x], + secondMesh.vertPos[secondTriVert.y], + secondMesh.vertPos[secondTriVert.z]}); minDistance = std::min(minDistance, distance); } diff --git a/src/manifold/src/triangle_dist.h b/src/manifold/src/triangle_dist.h new file mode 100644 index 000000000..fb49877bd --- /dev/null +++ b/src/manifold/src/triangle_dist.h @@ -0,0 +1,46 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +#include "public.h" + +namespace manifold { + +// The algorithm needs to handle the following cases: +// 1. The minimum distance is along the edges of both triangles (guaranteed +// in 2D) +// 2. One of the closest points is a vertex of one triangle and the other +// closest point is on the face of the other triangle +// 3. The triangles intersect (can't happen in MinGap) +// 4. An edge of one triangle is parallel to the face of the other triangle +// (handled by case 1) +// 5. One or both triangles are degenerate (we may ignore this?) +// +// An implementation can be found in https://gamma.cs.unc.edu/SSV/, TriDist.cpp. +// Probably create an implementation based on this. +// +// Explanation and sources taken from here: +// https://stackoverflow.com/questions/53602907/algorithm-to-find-minimum-distance-between-two-triangles + +/** + * Returns the minimum distance between two triangles. + * + * @param t1 First triangle. + * @param t2 Second triangle. + */ +float TriangleDistance(const std::array& t1, + const std::array& t2); +} // namespace manifold diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index b6187f7b3..7deee4493 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -82,7 +82,6 @@ TEST(MinGap, SphereSphereOutOfBounds) { EXPECT_FLOAT_EQ(distance, 0.1f); } -// failing TEST(MinGap, ClosestPointOnEdge) { auto a = Manifold::Cube(); @@ -94,7 +93,6 @@ TEST(MinGap, ClosestPointOnEdge) { EXPECT_FLOAT_EQ(distance, 1); } -// failing TEST(MinGap, ClosestPointOnTriangleFace) { auto a = Manifold::Cube(); a.Translate({0.0f, -0.25f, 0.0f}); From 849c82c479ded939f77dbe4bbe427358080bae0f Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 6 Mar 2024 11:15:45 +0100 Subject: [PATCH 05/48] Delete intersect tests --- test/boolean_test.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/test/boolean_test.cpp b/test/boolean_test.cpp index 8419fa244..6705a7aec 100644 --- a/test/boolean_test.cpp +++ b/test/boolean_test.cpp @@ -142,28 +142,6 @@ TEST(Boolean, SelfSubtract) { EXPECT_FLOAT_EQ(prop.surfaceArea, 0.0f); } -TEST(Boolean, SelfIntersect) { - Manifold cube = Manifold::Cube(); - Manifold intersect = cube ^ cube; - - auto cubeProp = cube.GetProperties(); - auto intersectProp = intersect.GetProperties(); - - EXPECT_FLOAT_EQ(cubeProp.volume, intersectProp.volume); - EXPECT_FLOAT_EQ(cubeProp.surfaceArea, intersectProp.surfaceArea); -} - -TEST(Boolean, Intersect) { - Manifold a = Manifold::Cube({1.0f, 1.0f, 1.0f}); - Manifold b = Manifold::Cube({1.0f, 1.0f, 1.0f}).Translate({0.5f, 0.0f, 0.0f}); - Manifold intersect = a ^ b; - - auto prop = intersect.GetProperties(); - - EXPECT_FLOAT_EQ(prop.volume, 0.5f); - EXPECT_FLOAT_EQ(prop.surfaceArea, 4.0f); -} - TEST(Boolean, Perturb) { Mesh tmp; tmp.vertPos = {{0.0f, 0.0f, 0.0f}, From 197e6d7f94c2958f7d16ff06c19947702c636c42 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 6 Mar 2024 18:38:55 +0100 Subject: [PATCH 06/48] Add stub MinGap definition --- src/manifold/src/triangle_dist.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/manifold/src/triangle_dist.h b/src/manifold/src/triangle_dist.h index fb49877bd..390e2ee58 100644 --- a/src/manifold/src/triangle_dist.h +++ b/src/manifold/src/triangle_dist.h @@ -42,5 +42,7 @@ namespace manifold { * @param t2 Second triangle. */ float TriangleDistance(const std::array& t1, - const std::array& t2); + const std::array& t2) { + return 0.0f; +} } // namespace manifold From e21c5f2fb305d96400bef705fe4d5c1375a1a54a Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 9 Mar 2024 09:02:44 +0100 Subject: [PATCH 07/48] Add triangle distance impl --- src/manifold/include/tri_dist.h | 34 +++++ src/manifold/src/manifold.cpp | 22 +-- src/manifold/src/tri_dist.cpp | 231 +++++++++++++++++++++++++++++++ src/manifold/src/triangle_dist.h | 48 ------- test/CMakeLists.txt | 2 +- test/tri_dist_test.cpp | 81 +++++++++++ 6 files changed, 360 insertions(+), 58 deletions(-) create mode 100644 src/manifold/include/tri_dist.h create mode 100644 src/manifold/src/tri_dist.cpp delete mode 100644 src/manifold/src/triangle_dist.h create mode 100644 test/tri_dist_test.cpp diff --git a/src/manifold/include/tri_dist.h b/src/manifold/include/tri_dist.h new file mode 100644 index 000000000..370d2f2e2 --- /dev/null +++ b/src/manifold/include/tri_dist.h @@ -0,0 +1,34 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +#include "public.h" + +namespace manifold { + +void edgeEdgeDist(glm::vec3& x, glm::vec3& y, const glm::vec3& p, + const glm::vec3& a, const glm::vec3& q, const glm::vec3& b); + +/** + * Returns the minimum squared distance between two triangles. + * + * @param t1 First triangle. + * @param t2 Second triangle. + */ +float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, + const glm::vec3 p[3], + const glm::vec3 q[3]); +} // namespace manifold diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 336238be5..7a6321a9a 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -21,7 +21,7 @@ #include "csg_tree.h" #include "impl.h" #include "par.h" -#include "triangle_dist.h" +#include "tri_dist.h" namespace { using namespace manifold; @@ -937,19 +937,23 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { minBoundsFirst.z <= maxBoundsSecond.z && maxBoundsFirst.z >= minBoundsSecond.z) { // AABBs overlap, calculate triangle-to-triangle distance - float distance = - TriangleDistance({firstMesh.vertPos[firstTriVert.x], - firstMesh.vertPos[firstTriVert.y], - firstMesh.vertPos[firstTriVert.z]}, - {secondMesh.vertPos[secondTriVert.x], - secondMesh.vertPos[secondTriVert.y], - secondMesh.vertPos[secondTriVert.z]}); + glm::vec3 cp; + glm::vec3 cq; + + glm::vec3 p[3] = {firstMesh.vertPos[firstTriVert.x], + firstMesh.vertPos[firstTriVert.y], + firstMesh.vertPos[firstTriVert.z]}; + glm::vec3 q[3] = {secondMesh.vertPos[secondTriVert.x], + secondMesh.vertPos[secondTriVert.y], + secondMesh.vertPos[secondTriVert.z]}; + + float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); minDistance = std::min(minDistance, distance); } } } - return minDistance; + return sqrt(minDistance); } } // namespace manifold diff --git a/src/manifold/src/tri_dist.cpp b/src/manifold/src/tri_dist.cpp new file mode 100644 index 000000000..3c52ed48b --- /dev/null +++ b/src/manifold/src/tri_dist.cpp @@ -0,0 +1,231 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tri_dist.h" + +namespace manifold { + +void edgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points + const glm::vec3& p, + const glm::vec3& a, // seg 1 origin, vector + const glm::vec3& q, + const glm::vec3& b) // seg 2 origin, vector +{ + const glm::vec3 T = q - p; + const double ADotA = glm::dot(a, a); + const double BDotB = glm::dot(b, b); + const double ADotB = glm::dot(a, b); + const double ADotT = glm::dot(a, T); + const double BDotT = glm::dot(b, T); + + // t parameterizes ray (p, a) + // u parameterizes ray (q, b) + + // Compute t for the closest point on ray (p, a) to ray (q, b) + const double Denom = ADotA * BDotB - ADotB * ADotB; + + double t; // We will clamp result so t is on the segment (p, a) + if (Denom != 0.0f) + t = std::clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0, 1.0); + else + t = 0.0f; + + // find u for point on ray (q, b) closest to point at t + double u; + if (BDotB != 0.0f) { + u = (t * ADotB - BDotT) / BDotB; + + // if u is on segment (q, b), t and u correspond to closest points, + // otherwise, clamp u, recompute and clamp t + if (u < 0.0f) { + u = 0.0f; + if (ADotA != 0.0f) + t = std::clamp(ADotT / ADotA, 0.0, 1.0); + else + t = 0.0f; + } else if (u > 1.0f) { + u = 1.0f; + if (ADotA != 0.0f) + t = std::clamp((ADotB + ADotT) / ADotA, 0.0, 1.0); + else + t = 0.0f; + } + } else { + u = 0.0f; + if (ADotA != 0.0f) + t = std::clamp(ADotT / ADotA, 0.0, 1.0); + else + t = 0.0f; + } + x = p + a * static_cast(t); + y = q + b * static_cast(u); +} + +/** + * Returns the minimum squared distance between two triangles. + * + * @param t1 First triangle. + * @param t2 Second triangle. + */ +float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, + const glm::vec3 p[3], + const glm::vec3 q[3]) { + std::array Sv; + Sv[0] = p[1] - p[0]; + Sv[1] = p[2] - p[1]; + Sv[2] = p[0] - p[2]; + + std::array Tv; + Tv[0] = q[1] - q[0]; + Tv[1] = q[2] - q[1]; + Tv[2] = q[0] - q[2]; + + glm::vec3 minP, minQ; + bool shown_disjoint = false; + + float mindd = std::numeric_limits::max(); + + for (uint32_t i = 0; i < 3; i++) { + for (uint32_t j = 0; j < 3; j++) { + edgeEdgeDist(cp, cq, p[i], Sv[i], q[j], Tv[j]); + const glm::vec3 V = cq - cp; + const float dd = glm::dot(V, V); + + if (dd <= mindd) { + minP = cp; + minQ = cq; + mindd = dd; + + uint32_t id = i + 2; + if (id >= 3) id -= 3; + glm::vec3 Z = p[id] - cp; + float a = glm::dot(Z, V); + id = j + 2; + if (id >= 3) id -= 3; + Z = q[id] - cq; + float b = glm::dot(Z, V); + + if ((a <= 0.0f) && (b >= 0.0f)) { + return glm::dot(V, V); + }; + + if (a <= 0.0f) + a = 0.0f; + else if (b > 0.0f) + b = 0.0f; + + if ((mindd - a + b) > 0.0f) shown_disjoint = true; + } + } + } + + glm::vec3 Sn = glm::cross(Sv[0], Sv[1]); + float Snl = glm::dot(Sn, Sn); + + if (Snl > 1e-15f) { + const glm::vec3 Tp(glm::dot(p[0] - q[0], Sn), glm::dot(p[0] - q[1], Sn), + glm::dot(p[0] - q[2], Sn)); + + int index = -1; + if ((Tp[0] > 0.0f) && (Tp[1] > 0.0f) && (Tp[2] > 0.0f)) { + if (Tp[0] < Tp[1]) + index = 0; + else + index = 1; + if (Tp[2] < Tp[index]) index = 2; + } else if ((Tp[0] < 0.0f) && (Tp[1] < 0.0f) && (Tp[2] < 0.0f)) { + if (Tp[0] > Tp[1]) + index = 0; + else + index = 1; + if (Tp[2] > Tp[index]) index = 2; + } + + if (index >= 0) { + shown_disjoint = true; + + const glm::vec3& qIndex = q[index]; + + glm::vec3 V = qIndex - p[0]; + glm::vec3 Z = glm::cross(Sn, Sv[0]); + if (glm::dot(V, Z) > 0.0f) { + V = qIndex - p[1]; + Z = glm::cross(Sn, Sv[1]); + if (glm::dot(V, Z) > 0.0f) { + V = qIndex - p[2]; + Z = glm::cross(Sn, Sv[2]); + if (glm::dot(V, Z) > 0.0f) { + cp = qIndex + Sn * Tp[index] / Snl; + cq = qIndex; + return glm::dot(cp - cq, cp - cq); + } + } + } + } + } + + glm::vec3 Tn = glm::cross(Tv[0], Tv[1]); + float Tnl = glm::dot(Tn, Tn); + + if (Tnl > 1e-15f) { + const glm::vec3 Sp(glm::dot(q[0] - p[0], Tn), glm::dot(q[0] - p[1], Tn), + glm::dot(q[0] - p[2], Tn)); + + int index = -1; + if ((Sp[0] > 0.0f) && (Sp[1] > 0.0f) && (Sp[2] > 0.0f)) { + if (Sp[0] < Sp[1]) + index = 0; + else + index = 1; + if (Sp[2] < Sp[index]) index = 2; + } else if ((Sp[0] < 0.0f) && (Sp[1] < 0.0f) && (Sp[2] < 0.0f)) { + if (Sp[0] > Sp[1]) + index = 0; + else + index = 1; + if (Sp[2] > Sp[index]) index = 2; + } + + if (index >= 0) { + shown_disjoint = true; + + const glm::vec3& pIndex = p[index]; + + glm::vec3 V = pIndex - q[0]; + glm::vec3 Z = glm::cross(Tn, Tv[0]); + if (glm::dot(V, Z) > 0.0f) { + V = pIndex - q[1]; + Z = glm::cross(Tn, Tv[1]); + if (glm::dot(V, Z) > 0.0f) { + V = pIndex - q[2]; + Z = glm::cross(Tn, Tv[2]); + if (glm::dot(V, Z) > 0.0f) { + cp = pIndex; + cq = pIndex + Tn * Sp[index] / Tnl; + return glm::dot(cp - cq, cp - cq); + } + } + } + } + } + + if (shown_disjoint) { + cp = minP; + cq = minQ; + return mindd; + } else { + return 0.0f; + } +}; +} // namespace manifold diff --git a/src/manifold/src/triangle_dist.h b/src/manifold/src/triangle_dist.h deleted file mode 100644 index 390e2ee58..000000000 --- a/src/manifold/src/triangle_dist.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include - -#include "public.h" - -namespace manifold { - -// The algorithm needs to handle the following cases: -// 1. The minimum distance is along the edges of both triangles (guaranteed -// in 2D) -// 2. One of the closest points is a vertex of one triangle and the other -// closest point is on the face of the other triangle -// 3. The triangles intersect (can't happen in MinGap) -// 4. An edge of one triangle is parallel to the face of the other triangle -// (handled by case 1) -// 5. One or both triangles are degenerate (we may ignore this?) -// -// An implementation can be found in https://gamma.cs.unc.edu/SSV/, TriDist.cpp. -// Probably create an implementation based on this. -// -// Explanation and sources taken from here: -// https://stackoverflow.com/questions/53602907/algorithm-to-find-minimum-distance-between-two-triangles - -/** - * Returns the minimum distance between two triangles. - * - * @param t1 First triangle. - * @param t2 Second triangle. - */ -float TriangleDistance(const std::array& t1, - const std::array& t2) { - return 0.0f; -} -} // namespace manifold diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9fe090e37..53514c9ea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,7 @@ project(manifold_test) set(CMAKE_CXX_STANDARD 17) enable_testing() -set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp mingap_test.cpp) +set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp mingap_test.cpp tri_dist_test.cpp) if(MANIFOLD_CBIND AND NOT EMSCRIPTEN) list(APPEND SOURCE_FILES manifoldc_test.cpp) diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp new file mode 100644 index 000000000..3a8b781bf --- /dev/null +++ b/test/tri_dist_test.cpp @@ -0,0 +1,81 @@ +// Copyright 2024 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tri_dist.h" + +#include "manifold.h" +#include "public.h" +#include "test.h" + +void printVec(glm::vec3 vec) { + std::cout << "{" << vec.x << ", " << vec.y << ", " << vec.z << "}" + << std::endl; +} + +TEST(TriangleDistance, ClosestPointsOnVertices) { + glm::vec3 cp; + glm::vec3 cq; + + glm::vec3 p[3] = { + {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + + glm::vec3 q[3] = {{2.0f, 0.0f, 0.0f}, {4.0f, 0.0f, 0.0f}, {3.0f, 1.0f, 0.0f}}; + float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + + EXPECT_FLOAT_EQ(distance, 1.0f); +} + +TEST(TriangleDistance, ClosestPointOnEdge) { + glm::vec3 cp; + glm::vec3 cq; + + glm::vec3 p[3] = { + {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + + glm::vec3 q[3] = { + {-1.0f, 2.0f, 0.0f}, {1.0f, 2.0f, 0.0f}, {0.0f, 3.0f, 0.0f}}; + + float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + + EXPECT_FLOAT_EQ(distance, 1.0f); +} + +TEST(TriangleDistance, ClosestPointOnFace) { + glm::vec3 cp; + glm::vec3 cq; + + glm::vec3 p[3] = { + {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + + glm::vec3 q[3] = { + {-1.0f, 2.0f, -0.5f}, {1.0f, 2.0f, -0.5f}, {0.0f, 2.0f, 1.5f}}; + + float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + + EXPECT_FLOAT_EQ(distance, 1.0f); +} + +TEST(TriangleDistance, test) { + glm::vec3 cp; + glm::vec3 cq; + + glm::vec3 p[3] = { + {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + + glm::vec3 q[3] = {{1.0f, 1.0f, 0.0f}, {3.0f, 1.0f, 0.0f}, {2.0f, 2.0f, 0.0f}}; + + float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + + EXPECT_FLOAT_EQ(distance, 0.5f); +} From 7bcee3b8065873fb425c2cb1e9d3da0a619a9d51 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 9 Mar 2024 09:24:52 +0100 Subject: [PATCH 08/48] Add comments --- src/manifold/include/tri_dist.h | 18 +++++++++++++++--- src/manifold/src/tri_dist.cpp | 18 ++++++++++-------- test/tri_dist_test.cpp | 14 +++++++------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/manifold/include/tri_dist.h b/src/manifold/include/tri_dist.h index 370d2f2e2..04052c131 100644 --- a/src/manifold/include/tri_dist.h +++ b/src/manifold/include/tri_dist.h @@ -19,14 +19,26 @@ namespace manifold { -void edgeEdgeDist(glm::vec3& x, glm::vec3& y, const glm::vec3& p, +/** + * Returns the distance between two line segments. + * + * @param[out] cq Closest point on line segment pa. + * @param[out] cp Closest point on line segment qb. + * @param[in] p Endpoint of first line segment. + * @param[in] q Endpoint of first line segment. + * @param[in] p Endpoint of second line segment. + * @param[in] q Endpoint of second line segment. + */ +void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, const glm::vec3& p, const glm::vec3& a, const glm::vec3& q, const glm::vec3& b); /** * Returns the minimum squared distance between two triangles. * - * @param t1 First triangle. - * @param t2 Second triangle. + * @param[out] cq Closest point on first triangle. + * @param[out] cp Closest point on second triangle. + * @param[in] p First triangle. + * @param[in] q Second triangle. */ float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, const glm::vec3 p[3], diff --git a/src/manifold/src/tri_dist.cpp b/src/manifold/src/tri_dist.cpp index 3c52ed48b..83ea16bd0 100644 --- a/src/manifold/src/tri_dist.cpp +++ b/src/manifold/src/tri_dist.cpp @@ -16,7 +16,11 @@ namespace manifold { -void edgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points +// From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License +// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md +// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/sweep/GuSweepCapsuleCapsule.cpp +// With minor modifications to use glm::vec3 type. +void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points const glm::vec3& p, const glm::vec3& a, // seg 1 origin, vector const glm::vec3& q, @@ -72,12 +76,10 @@ void edgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points y = q + b * static_cast(u); } -/** - * Returns the minimum squared distance between two triangles. - * - * @param t1 First triangle. - * @param t2 Second triangle. - */ +// From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License +// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md +// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/distance/GuDistanceTriangleTriangle.cpp +// With minor modifications to use glm::vec3 type. float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, const glm::vec3 p[3], const glm::vec3 q[3]) { @@ -98,7 +100,7 @@ float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, for (uint32_t i = 0; i < 3; i++) { for (uint32_t j = 0; j < 3; j++) { - edgeEdgeDist(cp, cq, p[i], Sv[i], q[j], Tv[j]); + EdgeEdgeDist(cp, cq, p[i], Sv[i], q[j], Tv[j]); const glm::vec3 V = cq - cp; const float dd = glm::dot(V, V); diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp index 3a8b781bf..67ab15d31 100644 --- a/test/tri_dist_test.cpp +++ b/test/tri_dist_test.cpp @@ -51,31 +51,31 @@ TEST(TriangleDistance, ClosestPointOnEdge) { EXPECT_FLOAT_EQ(distance, 1.0f); } -TEST(TriangleDistance, ClosestPointOnFace) { +TEST(TriangleDistance, ClosestPointOnEdge2) { glm::vec3 cp; glm::vec3 cq; glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = { - {-1.0f, 2.0f, -0.5f}, {1.0f, 2.0f, -0.5f}, {0.0f, 2.0f, 1.5f}}; + glm::vec3 q[3] = {{1.0f, 1.0f, 0.0f}, {3.0f, 1.0f, 0.0f}, {2.0f, 2.0f, 0.0f}}; float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); - EXPECT_FLOAT_EQ(distance, 1.0f); + EXPECT_FLOAT_EQ(distance, 0.5f); } -TEST(TriangleDistance, test) { +TEST(TriangleDistance, ClosestPointOnFace) { glm::vec3 cp; glm::vec3 cq; glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = {{1.0f, 1.0f, 0.0f}, {3.0f, 1.0f, 0.0f}, {2.0f, 2.0f, 0.0f}}; + glm::vec3 q[3] = { + {-1.0f, 2.0f, -0.5f}, {1.0f, 2.0f, -0.5f}, {0.0f, 2.0f, 1.5f}}; float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); - EXPECT_FLOAT_EQ(distance, 0.5f); + EXPECT_FLOAT_EQ(distance, 1.0f); } From 55cdabdae71bff9b24e88eb1bd16b9c29c939f6a Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 9 Mar 2024 14:33:40 +0100 Subject: [PATCH 09/48] Fix tests --- src/manifold/src/manifold.cpp | 8 ++++---- test/mingap_test.cpp | 11 +++-------- test/tri_dist_test.cpp | 5 ----- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 7a6321a9a..abc537326 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -896,7 +896,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { auto firstMesh = this->GetMesh(); auto secondMesh = other.GetMesh(); - float minDistance = searchLength; + float minDistanceSquared = searchLength * searchLength; // Iterate over triangles from the first manifold for (const auto& firstTriVert : firstMesh.triVerts) { @@ -947,13 +947,13 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { secondMesh.vertPos[secondTriVert.y], secondMesh.vertPos[secondTriVert.z]}; - float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + float distanceSquared = DistanceTriangleTriangleSquared(cp, cq, p, q); - minDistance = std::min(minDistance, distance); + minDistanceSquared = std::min(minDistanceSquared, distanceSquared); } } } - return sqrt(minDistance); + return sqrt(minDistanceSquared); } } // namespace manifold diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 7deee4493..b7f88054e 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -84,9 +84,7 @@ TEST(MinGap, SphereSphereOutOfBounds) { TEST(MinGap, ClosestPointOnEdge) { auto a = Manifold::Cube(); - - auto b = Manifold::Sphere(1.0f); - b.Translate({3.0f, 0.0f, 0.5f}); + auto b = Manifold::Sphere(1.0f).Translate({3.0f, 0.0f, 0.5f}); float distance = a.MinGap(b, 10); @@ -94,11 +92,8 @@ TEST(MinGap, ClosestPointOnEdge) { } TEST(MinGap, ClosestPointOnTriangleFace) { - auto a = Manifold::Cube(); - a.Translate({0.0f, -0.25f, 0.0f}); - - auto b = Manifold::Sphere(1.0f); - b.Translate({3.0f, 0.0f, 0.5f}); + auto a = Manifold::Cube().Translate({0.0f, -0.25f, 0.0f}); + auto b = Manifold::Sphere(1.0f).Translate({13.0f, 0.0f, 0.5f}); float distance = a.MinGap(b, 10); diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp index 67ab15d31..e6b64534e 100644 --- a/test/tri_dist_test.cpp +++ b/test/tri_dist_test.cpp @@ -18,11 +18,6 @@ #include "public.h" #include "test.h" -void printVec(glm::vec3 vec) { - std::cout << "{" << vec.x << ", " << vec.y << ", " << vec.z << "}" - << std::endl; -} - TEST(TriangleDistance, ClosestPointsOnVertices) { glm::vec3 cp; glm::vec3 cq; From d5c5f8440f4c97c27e9ec45a544fcf4b32a056a5 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 9 Mar 2024 14:52:22 +0100 Subject: [PATCH 10/48] Fix build --- src/manifold/src/tri_dist.cpp | 14 ++++++++++---- test/mingap_test.cpp | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/manifold/src/tri_dist.cpp b/src/manifold/src/tri_dist.cpp index 83ea16bd0..ca39bf70b 100644 --- a/src/manifold/src/tri_dist.cpp +++ b/src/manifold/src/tri_dist.cpp @@ -16,6 +16,12 @@ namespace manifold { +template +const T& clamp(const T& v, const T& lo, const T& hi) { + assert(!(hi < lo)); + return (v < lo) ? lo : (hi < v) ? hi : v; +} + // From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/sweep/GuSweepCapsuleCapsule.cpp @@ -41,7 +47,7 @@ void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points double t; // We will clamp result so t is on the segment (p, a) if (Denom != 0.0f) - t = std::clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0, 1.0); + t = clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0, 1.0); else t = 0.0f; @@ -55,20 +61,20 @@ void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points if (u < 0.0f) { u = 0.0f; if (ADotA != 0.0f) - t = std::clamp(ADotT / ADotA, 0.0, 1.0); + t = clamp(ADotT / ADotA, 0.0, 1.0); else t = 0.0f; } else if (u > 1.0f) { u = 1.0f; if (ADotA != 0.0f) - t = std::clamp((ADotB + ADotT) / ADotA, 0.0, 1.0); + t = clamp((ADotB + ADotT) / ADotA, 0.0, 1.0); else t = 0.0f; } } else { u = 0.0f; if (ADotA != 0.0f) - t = std::clamp(ADotT / ADotA, 0.0, 1.0); + t = clamp(ADotT / ADotA, 0.0, 1.0); else t = 0.0f; } diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index b7f88054e..fb6a48213 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -93,7 +93,7 @@ TEST(MinGap, ClosestPointOnEdge) { TEST(MinGap, ClosestPointOnTriangleFace) { auto a = Manifold::Cube().Translate({0.0f, -0.25f, 0.0f}); - auto b = Manifold::Sphere(1.0f).Translate({13.0f, 0.0f, 0.5f}); + auto b = Manifold::Sphere(1.0f).Translate({3.0f, 0.0f, 0.5f}); float distance = a.MinGap(b, 10); From 4c59675d77626d77a89769e8b51e22ee834dcc59 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 10 Mar 2024 10:21:17 +0100 Subject: [PATCH 11/48] Use collider --- .vscode/settings.json | 7 ++++-- src/manifold/include/manifold.h | 1 + src/manifold/src/manifold.cpp | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 377750acb..a7a26215c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -113,7 +113,10 @@ "format": "cpp", "numbers": "cpp", "ranges": "cpp", - "stop_token": "cpp" + "stop_token": "cpp", + "*.inc": "cpp", + "csetjmp": "cpp", + "cuchar": "cpp" }, "C_Cpp.clang_format_fallbackStyle": "google", "editor.formatOnSave": true, @@ -149,4 +152,4 @@ }, "python.formatting.provider": "none", "clang-format.executable": "clang-format", -} \ No newline at end of file +} diff --git a/src/manifold/include/manifold.h b/src/manifold/include/manifold.h index de462efec..2c1e77e2d 100644 --- a/src/manifold/include/manifold.h +++ b/src/manifold/include/manifold.h @@ -294,6 +294,7 @@ class Manifold { ///@} float MinGap(const Manifold& other, float searchLength) const; + float MinGapCollider(const Manifold& other, float searchLength) const; struct Impl; diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index abc537326..78336d41a 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -956,4 +956,46 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { return sqrt(minDistanceSquared); } + +float Manifold::MinGapCollider(const Manifold& other, + float searchLength) const { + // Get intersection + auto intersect = *this ^ other; + auto prop = intersect.GetProperties(); + + // If intersection is non zero, return zero (overlapping) + if (prop.volume != 0) { + return 0.0f; + } + + Vec faceBox; + Vec faceMorton; + + this->GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); + + std::transform(faceBox.begin(), faceBox.end(), faceBox.begin(), + [searchLength](Box box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); + + Vec faceBoxOther; + Vec faceMortonOther; + + other.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); + + std::transform(faceBoxOther.begin(), faceBoxOther.end(), faceBoxOther.begin(), + [searchLength](Box box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); + + Collider collider(faceBox, faceMorton); + + SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); + + std::cout << collisions.size() << std::endl; // 0 + + return 0; +} } // namespace manifold From 3da4b64780083934e7aacf7239bdf47fe0d330e8 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 11 Mar 2024 09:06:38 +0100 Subject: [PATCH 12/48] Collider exploration --- src/manifold/src/manifold.cpp | 70 +++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 78336d41a..0b0a31855 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -971,7 +971,7 @@ float Manifold::MinGapCollider(const Manifold& other, Vec faceBox; Vec faceMorton; - this->GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); + GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); std::transform(faceBox.begin(), faceBox.end(), faceBox.begin(), [searchLength](Box box) { @@ -979,10 +979,22 @@ float Manifold::MinGapCollider(const Manifold& other, box.max + glm::vec3(searchLength)); }); + Vec faceNew2Old(NumTri()); + auto policy = autoPolicy(faceNew2Old.size()); + sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); + + stable_sort(policy, zip(faceMorton.begin(), faceNew2Old.begin()), + zip(faceMorton.end(), faceNew2Old.end()), + [](const thrust::tuple& a, + const thrust::tuple& b) { + return thrust::get<0>(a) < thrust::get<0>(b); + }); + Vec faceBoxOther; Vec faceMortonOther; - other.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); + other.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBoxOther, + faceMortonOther); std::transform(faceBoxOther.begin(), faceBoxOther.end(), faceBoxOther.begin(), [searchLength](Box box) { @@ -990,12 +1002,64 @@ float Manifold::MinGapCollider(const Manifold& other, box.max + glm::vec3(searchLength)); }); + Vec faceNew2Old2(other.NumTri()); + auto policy2 = autoPolicy(faceNew2Old2.size()); + sequence(policy, faceNew2Old2.begin(), faceNew2Old2.end()); + + stable_sort(policy, zip(faceMortonOther.begin(), faceNew2Old2.begin()), + zip(faceMortonOther.end(), faceNew2Old2.end()), + [](const thrust::tuple& a, + const thrust::tuple& b) { + return thrust::get<0>(a) < thrust::get<0>(b); + }); + + // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode + // to sort them to the end, which allows them to be removed. + Collider collider(faceBox, faceMorton); SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); + float minDistanceSquared = searchLength; + + for (int i = 0; i < collisions.size(); ++i) { + const int tri = collisions.Get(i, 0); + const int triOther = collisions.Get(i, 1); + + glm::vec3 p[3]; + glm::vec3 q[3]; + + for (const int j : {0, 1, 2}) { + auto vertPos = GetMesh().vertPos; + auto halfedge = GetCsgLeafNode().GetImpl()->halfedge_; + + const float x = vertPos[halfedge[3 * tri + j].startVert].x; + const float y = vertPos[halfedge[3 * tri + j].startVert].y; + const float z = vertPos[halfedge[3 * tri + j].startVert].z; + + auto vertPosOther = other.GetMesh().vertPos; + auto halfedgeOther = other.GetCsgLeafNode().GetImpl()->halfedge_; + + const float x2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].x; + const float y2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].y; + const float z2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].z; + + p[j] = vertPos[halfedge[3 * tri + j].startVert]; + q[j] = vertPosOther[halfedgeOther[3 * tri + j].startVert]; + + std::cout << "x: " << x << " y: " << y << " z: " << z << std::endl; + std::cout << "x2: " << x2 << " y2: " << y2 << " z2: " << z2 << std::endl; + } + + glm::vec3 cp; + glm::vec3 cq; + + float distanceSquared = DistanceTriangleTriangleSquared(cp, cq, p, q); + minDistanceSquared = std::min(minDistanceSquared, distanceSquared); + } + std::cout << collisions.size() << std::endl; // 0 - return 0; + return sqrt(minDistanceSquared); } } // namespace manifold From bb3b227863a86419a2a57bcf0e3e21caf4de3b82 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 11 Mar 2024 13:08:36 +0100 Subject: [PATCH 13/48] Collider impl, cleanup --- src/manifold/include/manifold.h | 5 +- src/manifold/src/impl.h | 2 + src/manifold/src/manifold.cpp | 155 ++++++-------------------------- src/manifold/src/sort.cpp | 27 ++++++ 4 files changed, 59 insertions(+), 130 deletions(-) diff --git a/src/manifold/include/manifold.h b/src/manifold/include/manifold.h index 2c1e77e2d..895cc25f1 100644 --- a/src/manifold/include/manifold.h +++ b/src/manifold/include/manifold.h @@ -293,8 +293,11 @@ class Manifold { int NumOverlaps(const Manifold& second) const; ///@} + /** @name MinGap + */ + ///@{ float MinGap(const Manifold& other, float searchLength) const; - float MinGapCollider(const Manifold& other, float searchLength) const; + ///@} struct Impl; diff --git a/src/manifold/src/impl.h b/src/manifold/src/impl.h index 496c95d28..2ef7f2c03 100644 --- a/src/manifold/src/impl.h +++ b/src/manifold/src/impl.h @@ -111,6 +111,8 @@ struct Manifold::Impl { void CompactProps(); void GetFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const; void SortFaces(Vec& faceBox, Vec& faceMorton); + void SortFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const; + void GatherFaces(const Vec& faceNew2Old); void GatherFaces(const Impl& old, const Vec& faceNew2Old); diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 0b0a31855..3cbba6225 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -883,90 +883,18 @@ Manifold Manifold::Hull(const std::vector& manifolds) { return Compose(manifolds).Hull(); } +/** + * Compute the minimum distance between two manifolds. Returns a float between 0 + * and searchLength. + * + * @param other The other manifold to compute the minimum distance to. + * @param searchLength The maximum distance to search for a minimum gap. + */ float Manifold::MinGap(const Manifold& other, float searchLength) const { - // Get intersection auto intersect = *this ^ other; auto prop = intersect.GetProperties(); - // If intersection is non zero, return zero (overlapping) - if (prop.volume != 0) { - return 0.0f; - } - - auto firstMesh = this->GetMesh(); - auto secondMesh = other.GetMesh(); - - float minDistanceSquared = searchLength * searchLength; - - // Iterate over triangles from the first manifold - for (const auto& firstTriVert : firstMesh.triVerts) { - // Create AABB around the first triangle, expanded by 2 * searchLength - glm::vec3 minBoundsFirst = - glm::min(glm::min(firstMesh.vertPos[firstTriVert.x], - firstMesh.vertPos[firstTriVert.y]), - firstMesh.vertPos[firstTriVert.z]) - - glm::vec3(searchLength); - - glm::vec3 maxBoundsFirst = - glm::max(glm::max(firstMesh.vertPos[firstTriVert.x], - firstMesh.vertPos[firstTriVert.y]), - firstMesh.vertPos[firstTriVert.z]) + - glm::vec3(searchLength); - - // Iterate over triangles from the second manifold - for (const auto& secondTriVert : secondMesh.triVerts) { - // Create AABB around the second triangle, expanded by 2 * - // searchLength - glm::vec3 minBoundsSecond = - glm::min(glm::min(secondMesh.vertPos[secondTriVert.x], - secondMesh.vertPos[secondTriVert.y]), - secondMesh.vertPos[secondTriVert.z]) - - glm::vec3(searchLength); - - glm::vec3 maxBoundsSecond = - glm::max(glm::max(secondMesh.vertPos[secondTriVert.x], - secondMesh.vertPos[secondTriVert.y]), - secondMesh.vertPos[secondTriVert.z]) + - glm::vec3(searchLength); - - // Check for AABB collision - if (minBoundsFirst.x <= maxBoundsSecond.x && - maxBoundsFirst.x >= minBoundsSecond.x && - minBoundsFirst.y <= maxBoundsSecond.y && - maxBoundsFirst.y >= minBoundsSecond.y && - minBoundsFirst.z <= maxBoundsSecond.z && - maxBoundsFirst.z >= minBoundsSecond.z) { - // AABBs overlap, calculate triangle-to-triangle distance - glm::vec3 cp; - glm::vec3 cq; - - glm::vec3 p[3] = {firstMesh.vertPos[firstTriVert.x], - firstMesh.vertPos[firstTriVert.y], - firstMesh.vertPos[firstTriVert.z]}; - glm::vec3 q[3] = {secondMesh.vertPos[secondTriVert.x], - secondMesh.vertPos[secondTriVert.y], - secondMesh.vertPos[secondTriVert.z]}; - - float distanceSquared = DistanceTriangleTriangleSquared(cp, cq, p, q); - - minDistanceSquared = std::min(minDistanceSquared, distanceSquared); - } - } - } - - return sqrt(minDistanceSquared); -} - -float Manifold::MinGapCollider(const Manifold& other, - float searchLength) const { - // Get intersection - auto intersect = *this ^ other; - auto prop = intersect.GetProperties(); - - // If intersection is non zero, return zero (overlapping) - if (prop.volume != 0) { - return 0.0f; - } + if (prop.volume != 0) return 0.0f; Vec faceBox; Vec faceMorton; @@ -979,16 +907,7 @@ float Manifold::MinGapCollider(const Manifold& other, box.max + glm::vec3(searchLength)); }); - Vec faceNew2Old(NumTri()); - auto policy = autoPolicy(faceNew2Old.size()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - stable_sort(policy, zip(faceMorton.begin(), faceNew2Old.begin()), - zip(faceMorton.end(), faceNew2Old.end()), - [](const thrust::tuple& a, - const thrust::tuple& b) { - return thrust::get<0>(a) < thrust::get<0>(b); - }); + GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); Vec faceBoxOther; Vec faceMortonOther; @@ -1002,64 +921,42 @@ float Manifold::MinGapCollider(const Manifold& other, box.max + glm::vec3(searchLength)); }); - Vec faceNew2Old2(other.NumTri()); - auto policy2 = autoPolicy(faceNew2Old2.size()); - sequence(policy, faceNew2Old2.begin(), faceNew2Old2.end()); + other.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBoxOther, + faceMortonOther); - stable_sort(policy, zip(faceMortonOther.begin(), faceNew2Old2.begin()), - zip(faceMortonOther.end(), faceNew2Old2.end()), - [](const thrust::tuple& a, - const thrust::tuple& b) { - return thrust::get<0>(a) < thrust::get<0>(b); - }); + Collider collider{faceBox, faceMorton}; - // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode - // to sort them to the end, which allows them to be removed. + SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); - Collider collider(faceBox, faceMorton); + float minDistanceSquared = searchLength * searchLength; - SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); + auto vertPos = GetMesh().vertPos; + auto halfedge = GetCsgLeafNode().GetImpl()->halfedge_; - float minDistanceSquared = searchLength; + auto vertPosOther = other.GetMesh().vertPos; + auto halfedgeOther = other.GetCsgLeafNode().GetImpl()->halfedge_; for (int i = 0; i < collisions.size(); ++i) { - const int tri = collisions.Get(i, 0); - const int triOther = collisions.Get(i, 1); + const int tri = collisions.Get(i, 1); + const int triOther = collisions.Get(i, 0); + + glm::vec3 cp; + glm::vec3 cq; glm::vec3 p[3]; glm::vec3 q[3]; for (const int j : {0, 1, 2}) { - auto vertPos = GetMesh().vertPos; - auto halfedge = GetCsgLeafNode().GetImpl()->halfedge_; - - const float x = vertPos[halfedge[3 * tri + j].startVert].x; - const float y = vertPos[halfedge[3 * tri + j].startVert].y; - const float z = vertPos[halfedge[3 * tri + j].startVert].z; - - auto vertPosOther = other.GetMesh().vertPos; - auto halfedgeOther = other.GetCsgLeafNode().GetImpl()->halfedge_; - - const float x2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].x; - const float y2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].y; - const float z2 = vertPosOther[halfedgeOther[3 * tri + j].startVert].z; - p[j] = vertPos[halfedge[3 * tri + j].startVert]; - q[j] = vertPosOther[halfedgeOther[3 * tri + j].startVert]; - - std::cout << "x: " << x << " y: " << y << " z: " << z << std::endl; - std::cout << "x2: " << x2 << " y2: " << y2 << " z2: " << z2 << std::endl; + q[j] = vertPosOther[halfedgeOther[3 * triOther + j].startVert]; } - glm::vec3 cp; - glm::vec3 cq; - float distanceSquared = DistanceTriangleTriangleSquared(cp, cq, p, q); + minDistanceSquared = std::min(minDistanceSquared, distanceSquared); } - std::cout << collisions.size() << std::endl; // 0 - return sqrt(minDistanceSquared); } + } // namespace manifold diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 457d6f044..5d3c9b414 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -418,6 +418,33 @@ void Manifold::Impl::SortFaces(Vec& faceBox, Vec& faceMorton) { GatherFaces(faceNew2Old); } +void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, + Vec& faceMorton) const { + ZoneScoped; + Vec faceNew2Old(NumTri()); + auto policy = autoPolicy(faceNew2Old.size()); + sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); + + stable_sort(policy, zip(faceMorton.begin(), faceNew2Old.begin()), + zip(faceMorton.end(), faceNew2Old.end()), + [](const thrust::tuple& a, + const thrust::tuple& b) { + return thrust::get<0>(a) < thrust::get<0>(b); + }); + + // maybe dont need this + // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode + // to sort them to the end, which allows them to be removed. + const int newNumTri = + find(policy, faceMorton.begin(), + faceMorton.end(), kNoCode) - + faceMorton.begin(); + faceMorton.resize(newNumTri); + faceNew2Old.resize(newNumTri); + + Permute(faceBox, faceNew2Old); +} + /** * Creates the halfedge_ vector for this manifold by copying a set of faces from * another manifold, given by oldHalfedge. Input faceNew2Old defines the old From 1f07dd54500532fb86b51bf7b55574adcc90e74d Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 11 Mar 2024 16:37:08 +0100 Subject: [PATCH 14/48] Use par transform --- src/manifold/src/manifold.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 3cbba6225..00881abd8 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -884,10 +884,10 @@ Manifold Manifold::Hull(const std::vector& manifolds) { } /** - * Compute the minimum distance between two manifolds. Returns a float between 0 - * and searchLength. + * Computes the minimum distance between two manifolds. Returns a float between + * 0 and searchLength. * - * @param other The other manifold to compute the minimum distance to. + * @param other The other manifold to compute the minimum gap to. * @param searchLength The maximum distance to search for a minimum gap. */ float Manifold::MinGap(const Manifold& other, float searchLength) const { @@ -901,11 +901,11 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); - std::transform(faceBox.begin(), faceBox.end(), faceBox.begin(), - [searchLength](Box box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); + transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), + faceBox.begin(), [searchLength](Box box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); @@ -915,11 +915,11 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { other.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBoxOther, faceMortonOther); - std::transform(faceBoxOther.begin(), faceBoxOther.end(), faceBoxOther.begin(), - [searchLength](Box box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); + transform(autoPolicy(faceBoxOther.size()), faceBoxOther.begin(), + faceBoxOther.end(), faceBoxOther.begin(), [searchLength](Box box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); other.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBoxOther, faceMortonOther); From 03745fa701a76dd7281fb09ac2b703ca3ff3a71c Mon Sep 17 00:00:00 2001 From: Marcell Leleszi <59964679+mleleszi@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:48:25 +0100 Subject: [PATCH 15/48] Revert settings.json, add comments --- .vscode/settings.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a7a26215c..98c51ac55 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -113,10 +113,7 @@ "format": "cpp", "numbers": "cpp", "ranges": "cpp", - "stop_token": "cpp", - "*.inc": "cpp", - "csetjmp": "cpp", - "cuchar": "cpp" + "stop_token": "cpp" }, "C_Cpp.clang_format_fallbackStyle": "google", "editor.formatOnSave": true, From 91d48eca19c2de5d1afd3d64726e9cbb262602f7 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 11 Mar 2024 18:51:49 +0100 Subject: [PATCH 16/48] Add comments --- src/manifold/include/manifold.h | 2 +- src/manifold/src/sort.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/manifold/include/manifold.h b/src/manifold/include/manifold.h index 895cc25f1..d5b26b3eb 100644 --- a/src/manifold/include/manifold.h +++ b/src/manifold/include/manifold.h @@ -293,7 +293,7 @@ class Manifold { int NumOverlaps(const Manifold& second) const; ///@} - /** @name MinGap + /** @name Utilities */ ///@{ float MinGap(const Manifold& other, float searchLength) const; diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 5d3c9b414..059e6cdb6 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -418,6 +418,9 @@ void Manifold::Impl::SortFaces(Vec& faceBox, Vec& faceMorton) { GatherFaces(faceNew2Old); } +/** + * Sorts the bounding box and Morton code arrays based on the Morton codes. + */ void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const { ZoneScoped; @@ -432,7 +435,6 @@ void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, return thrust::get<0>(a) < thrust::get<0>(b); }); - // maybe dont need this // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode // to sort them to the end, which allows them to be removed. const int newNumTri = From 1c9cdd455bc4b29e392e0e9ff92a6d10e8389abb Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 14 Mar 2024 16:35:40 +0100 Subject: [PATCH 17/48] Move tri_dist to utils --- src/manifold/include/tri_dist.h | 46 ------------------- src/manifold/src/manifold.cpp | 5 +- src/utilities/CMakeLists.txt | 2 +- .../include/tri_dist.h} | 25 +++++++++- 4 files changed, 28 insertions(+), 50 deletions(-) delete mode 100644 src/manifold/include/tri_dist.h rename src/{manifold/src/tri_dist.cpp => utilities/include/tri_dist.h} (90%) diff --git a/src/manifold/include/tri_dist.h b/src/manifold/include/tri_dist.h deleted file mode 100644 index 04052c131..000000000 --- a/src/manifold/include/tri_dist.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2024 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include - -#include "public.h" - -namespace manifold { - -/** - * Returns the distance between two line segments. - * - * @param[out] cq Closest point on line segment pa. - * @param[out] cp Closest point on line segment qb. - * @param[in] p Endpoint of first line segment. - * @param[in] q Endpoint of first line segment. - * @param[in] p Endpoint of second line segment. - * @param[in] q Endpoint of second line segment. - */ -void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, const glm::vec3& p, - const glm::vec3& a, const glm::vec3& q, const glm::vec3& b); - -/** - * Returns the minimum squared distance between two triangles. - * - * @param[out] cq Closest point on first triangle. - * @param[out] cp Closest point on second triangle. - * @param[in] p First triangle. - * @param[in] q Second triangle. - */ -float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, - const glm::vec3 p[3], - const glm::vec3 q[3]); -} // namespace manifold diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 00881abd8..0975b3941 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -902,7 +902,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), [searchLength](Box box) { + faceBox.begin(), [searchLength](const Box& box) { return Box(box.min - glm::vec3(searchLength), box.max + glm::vec3(searchLength)); }); @@ -916,7 +916,8 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { faceMortonOther); transform(autoPolicy(faceBoxOther.size()), faceBoxOther.begin(), - faceBoxOther.end(), faceBoxOther.begin(), [searchLength](Box box) { + faceBoxOther.end(), faceBoxOther.begin(), + [searchLength](const Box& box) { return Box(box.min - glm::vec3(searchLength), box.max + glm::vec3(searchLength)); }); diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt index bdd2253a3..83e7b6ca2 100644 --- a/src/utilities/CMakeLists.txt +++ b/src/utilities/CMakeLists.txt @@ -83,4 +83,4 @@ endif() target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) install(TARGETS ${PROJECT_NAME} EXPORT manifoldTargets) -install(FILES include/public.h include/vec_view.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME}) +install(FILES include/public.h include/vec_view.h include/tri_dist.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME}) diff --git a/src/manifold/src/tri_dist.cpp b/src/utilities/include/tri_dist.h similarity index 90% rename from src/manifold/src/tri_dist.cpp rename to src/utilities/include/tri_dist.h index ca39bf70b..8b018e2b1 100644 --- a/src/manifold/src/tri_dist.cpp +++ b/src/utilities/include/tri_dist.h @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "tri_dist.h" +#pragma once + +#include +#include namespace manifold { @@ -26,6 +29,17 @@ const T& clamp(const T& v, const T& lo, const T& hi) { // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/sweep/GuSweepCapsuleCapsule.cpp // With minor modifications to use glm::vec3 type. + +/** + * Returns the distance between two line segments. + * + * @param[out] cq Closest point on line segment pa. + * @param[out] cp Closest point on line segment qb. + * @param[in] p One endpoint of the first line segment. + * @param[in] q Other endpoint of the first line segment. + * @param[in] p One endpoint of the second line segment. + * @param[in] q Other endpoint of the second line segment. + */ void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points const glm::vec3& p, const glm::vec3& a, // seg 1 origin, vector @@ -86,6 +100,15 @@ void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/distance/GuDistanceTriangleTriangle.cpp // With minor modifications to use glm::vec3 type. + +/** + * Returns the minimum squared distance between two triangles. + * + * @param[out] cq Closest point on the first triangle. + * @param[out] cp Closest point on the second triangle. + * @param[in] p First triangle. + * @param[in] q Second triangle. + */ float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, const glm::vec3 p[3], const glm::vec3 q[3]) { From 42b8af71c41a4c5299e6c26d221423069e9cdac4 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 14 Mar 2024 16:50:55 +0100 Subject: [PATCH 18/48] Delete unnecessary include --- test/mingap_test.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index fb6a48213..6b7011839 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -15,10 +15,6 @@ #include "manifold.h" #include "test.h" -#ifdef MANIFOLD_EXPORT -#include "meshIO.h" -#endif - TEST(MinGap, CubeCube) { auto a = Manifold::Cube(); auto b = Manifold::Cube().Translate({2.0f, 2.0f, 0.0f}); From 2c0ebdb0273a89a5004f2492580856a1eb0120ca Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 14 Mar 2024 17:00:27 +0100 Subject: [PATCH 19/48] Create lambda for bounding box expansion --- src/manifold/src/manifold.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 0975b3941..958d9fe73 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -896,16 +896,18 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { if (prop.volume != 0) return 0.0f; + auto expandBox = [searchLength](const Box& box) -> Box { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }; + Vec faceBox; Vec faceMorton; GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), [searchLength](const Box& box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); + faceBox.begin(), expandBox); GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); @@ -916,11 +918,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { faceMortonOther); transform(autoPolicy(faceBoxOther.size()), faceBoxOther.begin(), - faceBoxOther.end(), faceBoxOther.begin(), - [searchLength](const Box& box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); + faceBoxOther.end(), faceBoxOther.begin(), expandBox); other.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBoxOther, faceMortonOther); From 2804cd466e2fbcfa587ac9dbfe8cf5b5dffd1a8d Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 14 Mar 2024 17:08:47 +0100 Subject: [PATCH 20/48] Move duplicate logic to lambda --- src/manifold/src/manifold.cpp | 37 ++++++++++++++--------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 958d9fe73..0b0d8c4be 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -896,32 +896,25 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { if (prop.volume != 0) return 0.0f; - auto expandBox = [searchLength](const Box& box) -> Box { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }; - - Vec faceBox; - Vec faceMorton; - - GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); + auto getSortedExpandedFaceBoxMorton = [searchLength]( + const Manifold& manifold) { + Vec faceBox; + Vec faceMorton; - transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), expandBox); + manifold.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); - GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); + transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), + faceBox.begin(), [searchLength](const Box& box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); - Vec faceBoxOther; - Vec faceMortonOther; - - other.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBoxOther, - faceMortonOther); - - transform(autoPolicy(faceBoxOther.size()), faceBoxOther.begin(), - faceBoxOther.end(), faceBoxOther.begin(), expandBox); + manifold.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); + return std::pair{faceBox, faceMorton}; + }; - other.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBoxOther, - faceMortonOther); + auto [faceBox, faceMorton] = getSortedExpandedFaceBoxMorton(*this); + auto [faceBoxOther, faceMortonOther] = getSortedExpandedFaceBoxMorton(other); Collider collider{faceBox, faceMorton}; From 3c8501cc23c1032df04993c61dfa8c7dc923a74d Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 20 Mar 2024 09:28:25 +0100 Subject: [PATCH 21/48] Cleanup --- src/manifold/include/manifold.h | 7 +------ src/manifold/src/manifold.cpp | 4 ++-- src/utilities/include/tri_dist.h | 18 +++++++++--------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/manifold/include/manifold.h b/src/manifold/include/manifold.h index d5b26b3eb..cbd6915ad 100644 --- a/src/manifold/include/manifold.h +++ b/src/manifold/include/manifold.h @@ -218,6 +218,7 @@ class Manifold { float Precision() const; int Genus() const; Properties GetProperties() const; + float MinGap(const Manifold& other, float searchLength) const; ///@} /** @name Mesh ID @@ -293,12 +294,6 @@ class Manifold { int NumOverlaps(const Manifold& second) const; ///@} - /** @name Utilities - */ - ///@{ - float MinGap(const Manifold& other, float searchLength) const; - ///@} - struct Impl; private: diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 0b0d8c4be..40a6d9bd0 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -922,10 +922,10 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { float minDistanceSquared = searchLength * searchLength; - auto vertPos = GetMesh().vertPos; + auto vertPos = GetCsgLeafNode().GetImpl()->vertPos_; auto halfedge = GetCsgLeafNode().GetImpl()->halfedge_; - auto vertPosOther = other.GetMesh().vertPos; + auto vertPosOther = other.GetCsgLeafNode().GetImpl()->vertPos_; auto halfedgeOther = other.GetCsgLeafNode().GetImpl()->halfedge_; for (int i = 0; i < collisions.size(); ++i) { diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 8b018e2b1..38f9547ba 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -20,7 +20,7 @@ namespace manifold { template -const T& clamp(const T& v, const T& lo, const T& hi) { +inline const T& clamp(const T& v, const T& lo, const T& hi) { assert(!(hi < lo)); return (v < lo) ? lo : (hi < v) ? hi : v; } @@ -40,11 +40,11 @@ const T& clamp(const T& v, const T& lo, const T& hi) { * @param[in] p One endpoint of the second line segment. * @param[in] q Other endpoint of the second line segment. */ -void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points - const glm::vec3& p, - const glm::vec3& a, // seg 1 origin, vector - const glm::vec3& q, - const glm::vec3& b) // seg 2 origin, vector +inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points + const glm::vec3& p, + const glm::vec3& a, // seg 1 origin, vector + const glm::vec3& q, + const glm::vec3& b) // seg 2 origin, vector { const glm::vec3 T = q - p; const double ADotA = glm::dot(a, a); @@ -109,9 +109,9 @@ void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points * @param[in] p First triangle. * @param[in] q Second triangle. */ -float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, - const glm::vec3 p[3], - const glm::vec3 q[3]) { +inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, + const glm::vec3 p[3], + const glm::vec3 q[3]) { std::array Sv; Sv[0] = p[1] - p[0]; Sv[1] = p[2] - p[1]; From 24d1ee0bf45d0abb0b6d21c51ba5312a5d62bf09 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 20 Mar 2024 09:56:35 +0100 Subject: [PATCH 22/48] Use floats instead of doubles, use glm::clamp instead of own implementation --- src/utilities/include/tri_dist.h | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 38f9547ba..c330a0887 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -19,12 +19,6 @@ namespace manifold { -template -inline const T& clamp(const T& v, const T& lo, const T& hi) { - assert(!(hi < lo)); - return (v < lo) ? lo : (hi < v) ? hi : v; -} - // From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/sweep/GuSweepCapsuleCapsule.cpp @@ -47,26 +41,26 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points const glm::vec3& b) // seg 2 origin, vector { const glm::vec3 T = q - p; - const double ADotA = glm::dot(a, a); - const double BDotB = glm::dot(b, b); - const double ADotB = glm::dot(a, b); - const double ADotT = glm::dot(a, T); - const double BDotT = glm::dot(b, T); + const float ADotA = glm::dot(a, a); + const float BDotB = glm::dot(b, b); + const float ADotB = glm::dot(a, b); + const float ADotT = glm::dot(a, T); + const float BDotT = glm::dot(b, T); // t parameterizes ray (p, a) // u parameterizes ray (q, b) // Compute t for the closest point on ray (p, a) to ray (q, b) - const double Denom = ADotA * BDotB - ADotB * ADotB; + const float Denom = ADotA * BDotB - ADotB * ADotB; - double t; // We will clamp result so t is on the segment (p, a) + float t; // We will clamp result so t is on the segment (p, a) if (Denom != 0.0f) - t = clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0, 1.0); + t = glm::clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0f, 1.0f); else t = 0.0f; // find u for point on ray (q, b) closest to point at t - double u; + float u; if (BDotB != 0.0f) { u = (t * ADotB - BDotT) / BDotB; @@ -75,20 +69,20 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points if (u < 0.0f) { u = 0.0f; if (ADotA != 0.0f) - t = clamp(ADotT / ADotA, 0.0, 1.0); + t = glm::clamp(ADotT / ADotA, 0.0f, 1.0f); else t = 0.0f; } else if (u > 1.0f) { u = 1.0f; if (ADotA != 0.0f) - t = clamp((ADotB + ADotT) / ADotA, 0.0, 1.0); + t = glm::clamp((ADotB + ADotT) / ADotA, 0.0f, 1.0f); else t = 0.0f; } } else { u = 0.0f; if (ADotA != 0.0f) - t = clamp(ADotT / ADotA, 0.0, 1.0); + t = glm::clamp(ADotT / ADotA, 0.0f, 1.0f); else t = 0.0f; } From df9367b0811a3a14243e950b7fde62583e6820e3 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 20 Mar 2024 15:59:12 +0100 Subject: [PATCH 23/48] User ternaries --- src/utilities/include/tri_dist.h | 43 ++++++++------------------------ 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index c330a0887..80ac5c262 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -54,10 +54,9 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points const float Denom = ADotA * BDotB - ADotB * ADotB; float t; // We will clamp result so t is on the segment (p, a) - if (Denom != 0.0f) - t = glm::clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0f, 1.0f); - else - t = 0.0f; + t = Denom != 0.0f + ? glm::clamp((ADotT * BDotB - BDotT * ADotB) / Denom, 0.0f, 1.0f) + : 0.0f; // find u for point on ray (q, b) closest to point at t float u; @@ -68,23 +67,15 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points // otherwise, clamp u, recompute and clamp t if (u < 0.0f) { u = 0.0f; - if (ADotA != 0.0f) - t = glm::clamp(ADotT / ADotA, 0.0f, 1.0f); - else - t = 0.0f; + t = ADotA != 0.0f ? glm::clamp(ADotT / ADotA, 0.0f, 1.0f) : 0.0f; } else if (u > 1.0f) { u = 1.0f; - if (ADotA != 0.0f) - t = glm::clamp((ADotB + ADotT) / ADotA, 0.0f, 1.0f); - else - t = 0.0f; + t = ADotA != 0.0f ? glm::clamp((ADotB + ADotT) / ADotA, 0.0f, 1.0f) + : 0.0f; } } else { u = 0.0f; - if (ADotA != 0.0f) - t = glm::clamp(ADotT / ADotA, 0.0f, 1.0f); - else - t = 0.0f; + t = ADotA != 0.0f ? glm::clamp(ADotT / ADotA, 0.0f, 1.0f) : 0.0f; } x = p + a * static_cast(t); y = q + b * static_cast(u); @@ -164,16 +155,10 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, int index = -1; if ((Tp[0] > 0.0f) && (Tp[1] > 0.0f) && (Tp[2] > 0.0f)) { - if (Tp[0] < Tp[1]) - index = 0; - else - index = 1; + index = Tp[0] < Tp[1] ? 0 : 1; if (Tp[2] < Tp[index]) index = 2; } else if ((Tp[0] < 0.0f) && (Tp[1] < 0.0f) && (Tp[2] < 0.0f)) { - if (Tp[0] > Tp[1]) - index = 0; - else - index = 1; + index = Tp[0] > Tp[1] ? 0 : 1; if (Tp[2] > Tp[index]) index = 2; } @@ -209,16 +194,10 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, int index = -1; if ((Sp[0] > 0.0f) && (Sp[1] > 0.0f) && (Sp[2] > 0.0f)) { - if (Sp[0] < Sp[1]) - index = 0; - else - index = 1; + index = Sp[0] < Sp[1] ? 0 : 1; if (Sp[2] < Sp[index]) index = 2; } else if ((Sp[0] < 0.0f) && (Sp[1] < 0.0f) && (Sp[2] < 0.0f)) { - if (Sp[0] > Sp[1]) - index = 0; - else - index = 1; + index = Sp[0] > Sp[1] ? 0 : 1; if (Sp[2] > Sp[index]) index = 2; } From ee073a1fe6088e846157f50ad265ce5b012e01ed Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 20 Mar 2024 16:18:41 +0100 Subject: [PATCH 24/48] Remove DistanceTriangleTriangleSquared out params --- src/manifold/src/manifold.cpp | 5 +---- src/utilities/include/tri_dist.h | 24 ++++++++---------------- test/tri_dist_test.cpp | 21 +++++---------------- 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index 40a6d9bd0..c98f24c30 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -932,9 +932,6 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { const int tri = collisions.Get(i, 1); const int triOther = collisions.Get(i, 0); - glm::vec3 cp; - glm::vec3 cq; - glm::vec3 p[3]; glm::vec3 q[3]; @@ -943,7 +940,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { q[j] = vertPosOther[halfedgeOther[3 * triOther + j].startVert]; } - float distanceSquared = DistanceTriangleTriangleSquared(cp, cq, p, q); + float distanceSquared = DistanceTriangleTriangleSquared(p, q); minDistanceSquared = std::min(minDistanceSquared, distanceSquared); } diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 80ac5c262..ef5658369 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -94,8 +94,7 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points * @param[in] p First triangle. * @param[in] q Second triangle. */ -inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, - const glm::vec3 p[3], +inline float DistanceTriangleTriangleSquared(const glm::vec3 p[3], const glm::vec3 q[3]) { std::array Sv; Sv[0] = p[1] - p[0]; @@ -107,20 +106,19 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, Tv[1] = q[2] - q[1]; Tv[2] = q[0] - q[2]; - glm::vec3 minP, minQ; bool shown_disjoint = false; float mindd = std::numeric_limits::max(); for (uint32_t i = 0; i < 3; i++) { for (uint32_t j = 0; j < 3; j++) { + glm::vec3 cp; + glm::vec3 cq; EdgeEdgeDist(cp, cq, p[i], Sv[i], q[j], Tv[j]); const glm::vec3 V = cq - cp; const float dd = glm::dot(V, V); if (dd <= mindd) { - minP = cp; - minQ = cq; mindd = dd; uint32_t id = i + 2; @@ -176,8 +174,8 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, V = qIndex - p[2]; Z = glm::cross(Sn, Sv[2]); if (glm::dot(V, Z) > 0.0f) { - cp = qIndex + Sn * Tp[index] / Snl; - cq = qIndex; + glm::vec3 cp = qIndex + Sn * Tp[index] / Snl; + glm::vec3 cq = qIndex; return glm::dot(cp - cq, cp - cq); } } @@ -215,8 +213,8 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, V = pIndex - q[2]; Z = glm::cross(Tn, Tv[2]); if (glm::dot(V, Z) > 0.0f) { - cp = pIndex; - cq = pIndex + Tn * Sp[index] / Tnl; + glm::vec3 cp = pIndex; + glm::vec3 cq = pIndex + Tn * Sp[index] / Tnl; return glm::dot(cp - cq, cp - cq); } } @@ -224,12 +222,6 @@ inline float DistanceTriangleTriangleSquared(glm::vec3& cp, glm::vec3& cq, } } - if (shown_disjoint) { - cp = minP; - cq = minQ; - return mindd; - } else { - return 0.0f; - } + return shown_disjoint ? mindd : 0.0f; }; } // namespace manifold diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp index e6b64534e..90e08577f 100644 --- a/test/tri_dist_test.cpp +++ b/test/tri_dist_test.cpp @@ -19,58 +19,47 @@ #include "test.h" TEST(TriangleDistance, ClosestPointsOnVertices) { - glm::vec3 cp; - glm::vec3 cq; - glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; glm::vec3 q[3] = {{2.0f, 0.0f, 0.0f}, {4.0f, 0.0f, 0.0f}, {3.0f, 1.0f, 0.0f}}; - float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + + float distance = DistanceTriangleTriangleSquared(p, q); EXPECT_FLOAT_EQ(distance, 1.0f); } TEST(TriangleDistance, ClosestPointOnEdge) { - glm::vec3 cp; - glm::vec3 cq; - glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; glm::vec3 q[3] = { {-1.0f, 2.0f, 0.0f}, {1.0f, 2.0f, 0.0f}, {0.0f, 3.0f, 0.0f}}; - float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + float distance = DistanceTriangleTriangleSquared(p, q); EXPECT_FLOAT_EQ(distance, 1.0f); } TEST(TriangleDistance, ClosestPointOnEdge2) { - glm::vec3 cp; - glm::vec3 cq; - glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; glm::vec3 q[3] = {{1.0f, 1.0f, 0.0f}, {3.0f, 1.0f, 0.0f}, {2.0f, 2.0f, 0.0f}}; - float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + float distance = DistanceTriangleTriangleSquared(p, q); EXPECT_FLOAT_EQ(distance, 0.5f); } TEST(TriangleDistance, ClosestPointOnFace) { - glm::vec3 cp; - glm::vec3 cq; - glm::vec3 p[3] = { {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; glm::vec3 q[3] = { {-1.0f, 2.0f, -0.5f}, {1.0f, 2.0f, -0.5f}, {0.0f, 2.0f, 1.5f}}; - float distance = DistanceTriangleTriangleSquared(cp, cq, p, q); + float distance = DistanceTriangleTriangleSquared(p, q); EXPECT_FLOAT_EQ(distance, 1.0f); } From 29d8ee6351ffe1b4c73501b6a6b215394b660a9f Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 08:44:29 +0100 Subject: [PATCH 25/48] Move MinGap impl to Impl --- src/manifold/src/impl.cpp | 54 +++++++++++++++++++++++++++++++++++ src/manifold/src/impl.h | 1 + src/manifold/src/manifold.cpp | 53 ++-------------------------------- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 8de196a08..af3f6753b 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -23,6 +23,7 @@ #include "mesh_fixes.h" #include "par.h" #include "svd.h" +#include "tri_dist.h" namespace { using namespace manifold; @@ -902,4 +903,57 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( else return collider_.Collisions(vertsIn); } +/* + * Computes the minimum distance between two manifolds. Returns a float between + * 0 and searchLength. + */ +float Manifold::Impl::MinGap(const Manifold::Impl& other, + float searchLength) const { + ZoneScoped; + auto getSortedExpandedFaceBoxMorton = + [searchLength](const Manifold::Impl& impl) { + Vec faceBox; + Vec faceMorton; + + impl.GetFaceBoxMorton(faceBox, faceMorton); + + transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), + faceBox.begin(), [searchLength](const Box& box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); + + impl.SortFaceBoxMorton(faceBox, faceMorton); + return std::pair{faceBox, faceMorton}; + }; + + auto [faceBox, faceMorton] = getSortedExpandedFaceBoxMorton(*this); + auto [faceBoxOther, faceMortonOther] = getSortedExpandedFaceBoxMorton(other); + + Collider collider{faceBox, faceMorton}; + + SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); + + float minDistanceSquared = searchLength * searchLength; + + for (int i = 0; i < collisions.size(); ++i) { + const int tri = collisions.Get(i, 1); + const int triOther = collisions.Get(i, 0); + + glm::vec3 p[3]; + glm::vec3 q[3]; + + for (const int j : {0, 1, 2}) { + p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; + q[j] = other.vertPos_[other.halfedge_[3 * triOther + j].startVert]; + } + + float distanceSquared = DistanceTriangleTriangleSquared(p, q); + + minDistanceSquared = std::min(minDistanceSquared, distanceSquared); + } + + return sqrt(minDistanceSquared); +}; + } // namespace manifold diff --git a/src/manifold/src/impl.h b/src/manifold/src/impl.h index 2ef7f2c03..d0a90b6c1 100644 --- a/src/manifold/src/impl.h +++ b/src/manifold/src/impl.h @@ -81,6 +81,7 @@ struct Manifold::Impl { SparseIndices EdgeCollisions(const Impl& B, bool inverted = false) const; SparseIndices VertexCollisionsZ(VecView vertsIn, bool inverted = false) const; + float MinGap(const Impl& other, float searchLength) const; bool IsEmpty() const { return NumVert() == 0; } int NumVert() const { return vertPos_.size(); } diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index c98f24c30..61f430192 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -896,56 +896,7 @@ float Manifold::MinGap(const Manifold& other, float searchLength) const { if (prop.volume != 0) return 0.0f; - auto getSortedExpandedFaceBoxMorton = [searchLength]( - const Manifold& manifold) { - Vec faceBox; - Vec faceMorton; - - manifold.GetCsgLeafNode().GetImpl()->GetFaceBoxMorton(faceBox, faceMorton); - - transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), [searchLength](const Box& box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); - - manifold.GetCsgLeafNode().GetImpl()->SortFaceBoxMorton(faceBox, faceMorton); - return std::pair{faceBox, faceMorton}; - }; - - auto [faceBox, faceMorton] = getSortedExpandedFaceBoxMorton(*this); - auto [faceBoxOther, faceMortonOther] = getSortedExpandedFaceBoxMorton(other); - - Collider collider{faceBox, faceMorton}; - - SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); - - float minDistanceSquared = searchLength * searchLength; - - auto vertPos = GetCsgLeafNode().GetImpl()->vertPos_; - auto halfedge = GetCsgLeafNode().GetImpl()->halfedge_; - - auto vertPosOther = other.GetCsgLeafNode().GetImpl()->vertPos_; - auto halfedgeOther = other.GetCsgLeafNode().GetImpl()->halfedge_; - - for (int i = 0; i < collisions.size(); ++i) { - const int tri = collisions.Get(i, 1); - const int triOther = collisions.Get(i, 0); - - glm::vec3 p[3]; - glm::vec3 q[3]; - - for (const int j : {0, 1, 2}) { - p[j] = vertPos[halfedge[3 * tri + j].startVert]; - q[j] = vertPosOther[halfedgeOther[3 * triOther + j].startVert]; - } - - float distanceSquared = DistanceTriangleTriangleSquared(p, q); - - minDistanceSquared = std::min(minDistanceSquared, distanceSquared); - } - - return sqrt(minDistanceSquared); + return GetCsgLeafNode().GetImpl()->MinGap(*other.GetCsgLeafNode().GetImpl(), + searchLength); } - } // namespace manifold From e6d70c823ffd621ab170065ac08ead83a7c6e81a Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 08:59:20 +0100 Subject: [PATCH 26/48] Use std::array instead of C-style --- src/manifold/src/impl.cpp | 4 ++-- src/manifold/src/sort.cpp | 9 -------- src/utilities/include/tri_dist.h | 4 ++-- test/tri_dist_test.cpp | 38 ++++++++++++++++++++------------ 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index af3f6753b..49527d400 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -940,8 +940,8 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, const int tri = collisions.Get(i, 1); const int triOther = collisions.Get(i, 0); - glm::vec3 p[3]; - glm::vec3 q[3]; + std::array p; + std::array q; for (const int j : {0, 1, 2}) { p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 059e6cdb6..85b5ee315 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -435,15 +435,6 @@ void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, return thrust::get<0>(a) < thrust::get<0>(b); }); - // Tris were flagged for removal with pairedHalfedge = -1 and assigned kNoCode - // to sort them to the end, which allows them to be removed. - const int newNumTri = - find(policy, faceMorton.begin(), - faceMorton.end(), kNoCode) - - faceMorton.begin(); - faceMorton.resize(newNumTri); - faceNew2Old.resize(newNumTri); - Permute(faceBox, faceNew2Old); } diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index ef5658369..6709c1a67 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -94,8 +94,8 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points * @param[in] p First triangle. * @param[in] q Second triangle. */ -inline float DistanceTriangleTriangleSquared(const glm::vec3 p[3], - const glm::vec3 q[3]) { +inline float DistanceTriangleTriangleSquared( + const std::array& p, const std::array& q) { std::array Sv; Sv[0] = p[1] - p[0]; Sv[1] = p[2] - p[1]; diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp index 90e08577f..476b9900b 100644 --- a/test/tri_dist_test.cpp +++ b/test/tri_dist_test.cpp @@ -19,10 +19,13 @@ #include "test.h" TEST(TriangleDistance, ClosestPointsOnVertices) { - glm::vec3 p[3] = { - {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = {{2.0f, 0.0f, 0.0f}, {4.0f, 0.0f, 0.0f}, {3.0f, 1.0f, 0.0f}}; + std::array q = {glm::vec3{2.0f, 0.0f, 0.0f}, + glm::vec3{4.0f, 0.0f, 0.0f}, + glm::vec3{3.0f, 1.0f, 0.0f}}; float distance = DistanceTriangleTriangleSquared(p, q); @@ -30,11 +33,13 @@ TEST(TriangleDistance, ClosestPointsOnVertices) { } TEST(TriangleDistance, ClosestPointOnEdge) { - glm::vec3 p[3] = { - {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = { - {-1.0f, 2.0f, 0.0f}, {1.0f, 2.0f, 0.0f}, {0.0f, 3.0f, 0.0f}}; + std::array q = {glm::vec3{-1.0f, 2.0f, 0.0f}, + glm::vec3{1.0f, 2.0f, 0.0f}, + glm::vec3{0.0f, 3.0f, 0.0f}}; float distance = DistanceTriangleTriangleSquared(p, q); @@ -42,10 +47,13 @@ TEST(TriangleDistance, ClosestPointOnEdge) { } TEST(TriangleDistance, ClosestPointOnEdge2) { - glm::vec3 p[3] = { - {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = {{1.0f, 1.0f, 0.0f}, {3.0f, 1.0f, 0.0f}, {2.0f, 2.0f, 0.0f}}; + std::array q = {glm::vec3{1.0f, 1.0f, 0.0f}, + glm::vec3{3.0f, 1.0f, 0.0f}, + glm::vec3{2.0f, 2.0f, 0.0f}}; float distance = DistanceTriangleTriangleSquared(p, q); @@ -53,11 +61,13 @@ TEST(TriangleDistance, ClosestPointOnEdge2) { } TEST(TriangleDistance, ClosestPointOnFace) { - glm::vec3 p[3] = { - {-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}; + std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; - glm::vec3 q[3] = { - {-1.0f, 2.0f, -0.5f}, {1.0f, 2.0f, -0.5f}, {0.0f, 2.0f, 1.5f}}; + std::array q = {glm::vec3{-1.0f, 2.0f, -0.5f}, + glm::vec3{1.0f, 2.0f, -0.5f}, + glm::vec3{0.0f, 2.0f, 1.5f}}; float distance = DistanceTriangleTriangleSquared(p, q); From 5455f05b86f66ab85e216656663f8498aa8fd22a Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 09:59:16 +0100 Subject: [PATCH 27/48] Modify MinGap test cases for clarity, add overlapping tri_dist test --- test/mingap_test.cpp | 16 +++++++++------- test/tri_dist_test.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 6b7011839..4bdb51df5 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -48,7 +48,7 @@ TEST(MinGap, CubeSphereOverlapping) { float distance = a.MinGap(b, 10); - EXPECT_FLOAT_EQ(distance, 0); + EXPECT_FLOAT_EQ(distance, 0.0f); } TEST(MinGap, SphereSphere) { @@ -57,7 +57,7 @@ TEST(MinGap, SphereSphere) { float distance = a.MinGap(b, 10); - EXPECT_FLOAT_EQ(distance, 3); + EXPECT_FLOAT_EQ(distance, 3.0f); } TEST(MinGap, SphereSphere2) { @@ -80,18 +80,20 @@ TEST(MinGap, SphereSphereOutOfBounds) { TEST(MinGap, ClosestPointOnEdge) { auto a = Manifold::Cube(); - auto b = Manifold::Sphere(1.0f).Translate({3.0f, 0.0f, 0.5f}); + auto b = Manifold::Cube().Translate({2.0f, 1.0f, 0.5f}); float distance = a.MinGap(b, 10); - EXPECT_FLOAT_EQ(distance, 1); + EXPECT_FLOAT_EQ(distance, 1.0f); } TEST(MinGap, ClosestPointOnTriangleFace) { - auto a = Manifold::Cube().Translate({0.0f, -0.25f, 0.0f}); - auto b = Manifold::Sphere(1.0f).Translate({3.0f, 0.0f, 0.5f}); + auto a = Manifold::Cube(); + auto b = Manifold::Cube() + .Scale({10.0f, 10.0f, 10.0f}) + .Translate({2.0f, -5.0f, -1.0f}); float distance = a.MinGap(b, 10); - EXPECT_FLOAT_EQ(distance, 1); + EXPECT_FLOAT_EQ(distance, 1.0f); } diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp index 476b9900b..950bea9ee 100644 --- a/test/tri_dist_test.cpp +++ b/test/tri_dist_test.cpp @@ -73,3 +73,17 @@ TEST(TriangleDistance, ClosestPointOnFace) { EXPECT_FLOAT_EQ(distance, 1.0f); } + +TEST(TriangleDistance, Overlapping) { + std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.0f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; + + std::array q = {glm::vec3{-1.0f, 0.0f, 0.0f}, + glm::vec3{1.0f, 0.5f, 0.0f}, + glm::vec3{0.0f, 1.0f, 0.0f}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 0.0f); +} From 1719c8ca04972c41b1e5fd3097a9105fac2cbfe0 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 11:12:32 +0100 Subject: [PATCH 28/48] Add c, wasm, python bindings --- bindings/c/include/manifoldc.h | 2 ++ bindings/c/manifoldc.cpp | 5 +++++ bindings/python/manifold3d.cpp | 8 ++++++++ bindings/wasm/bindings.cpp | 1 + bindings/wasm/manifold-encapsulated-types.d.ts | 7 +++++++ 5 files changed, 23 insertions(+) diff --git a/bindings/c/include/manifoldc.h b/bindings/c/include/manifoldc.h index b7c01ca0c..7120c3adb 100644 --- a/bindings/c/include/manifoldc.h +++ b/bindings/c/include/manifoldc.h @@ -188,6 +188,8 @@ ManifoldManifold *manifold_set_properties( void (*fun)(float *new_prop, ManifoldVec3 position, const float *old_prop)); ManifoldManifold *manifold_calculate_curvature(void *mem, ManifoldManifold *m, int gaussian_idx, int mean_idx); +float manifold_min_gap(ManifoldManifold *m, ManifoldManifold *other, + float searchLength); // CrossSection Shapes/Constructors diff --git a/bindings/c/manifoldc.cpp b/bindings/c/manifoldc.cpp index 9b48ed0a6..093aea5c1 100644 --- a/bindings/c/manifoldc.cpp +++ b/bindings/c/manifoldc.cpp @@ -543,6 +543,11 @@ ManifoldManifold *manifold_calculate_curvature(void *mem, ManifoldManifold *m, return to_c(new (mem) Manifold(man)); } +float manifold_min_gap(ManifoldManifold *m, ManifoldManifold *other, + float searchLength) { + return from_c(m)->MinGap(*from_c(other), searchLength); +} + // Static Quality Globals void manifold_set_min_circular_angle(float degrees) { diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index 0d744f501..d4ac7b44d 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -315,6 +315,14 @@ NB_MODULE(manifold3d, m) { .def("calculate_curvature", &Manifold::CalculateCurvature, nb::arg("gaussian_idx"), nb::arg("mean_idx"), manifold__calculate_curvature__gaussian_idx__mean_idx) + .def( + "min_gap", + [](const Manifold &self, const Manifold &other, float searchLength) { + return self.MinGap(other, searchLength); + }, + nb::arg("other"), nb::arg("search_length"), + "Returns the minimum distance between two manifolds." + "Returns a float between 0 and searchLength.") .def("refine", &Manifold::Refine, nb::arg("n"), manifold__refine__n) .def("refine_to_length", &Manifold::RefineToLength, nb::arg("length"), manifold__refine_to_length__length) diff --git a/bindings/wasm/bindings.cpp b/bindings/wasm/bindings.cpp index f017a510a..1dc7c626e 100644 --- a/bindings/wasm/bindings.cpp +++ b/bindings/wasm/bindings.cpp @@ -164,6 +164,7 @@ EMSCRIPTEN_BINDINGS(whatever) { .function("precision", &Manifold::Precision) .function("genus", &Manifold::Genus) .function("getProperties", &Manifold::GetProperties) + .function("minGap", &Manifold::MinGap) .function("calculateCurvature", &Manifold::CalculateCurvature) .function("originalID", &Manifold::OriginalID) .function("asOriginal", &Manifold::AsOriginal); diff --git a/bindings/wasm/manifold-encapsulated-types.d.ts b/bindings/wasm/manifold-encapsulated-types.d.ts index 6dfec5be3..0a8b0920f 100644 --- a/bindings/wasm/manifold-encapsulated-types.d.ts +++ b/bindings/wasm/manifold-encapsulated-types.d.ts @@ -809,6 +809,13 @@ export class Manifold { */ getProperties(): Properties; + + /* + * Returns the minimum distance between two manifolds. Returns a float between + * 0 and searchLength. + */ + minGap(other: Manifold, searchLength: number): number; + // Export /** From f5e8cc3d96ee9c1a699586b3ce1ea77f6e2d36cc Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 11:36:43 +0100 Subject: [PATCH 29/48] Fix formatting --- bindings/c/manifoldc.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bindings/c/manifoldc.cpp b/bindings/c/manifoldc.cpp index 3e69447af..521557069 100644 --- a/bindings/c/manifoldc.cpp +++ b/bindings/c/manifoldc.cpp @@ -554,13 +554,12 @@ float manifold_min_gap(ManifoldManifold *m, ManifoldManifold *other, float searchLength) { return from_c(m)->MinGap(*from_c(other), searchLength); } - + ManifoldManifold *manifold_calculate_normals(void *mem, ManifoldManifold *m, int normal_idx, int min_sharp_angle) { auto man = from_c(m)->CalculateNormals(normal_idx, min_sharp_angle); return to_c(new (mem) Manifold(man)); - } // Static Quality Globals From 1b93a6c8040591fb06d7c53dbd388dcaa31973d3 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sun, 24 Mar 2024 11:52:25 +0100 Subject: [PATCH 30/48] Clean up comments --- bindings/python/manifold3d.cpp | 2 +- bindings/wasm/manifold-encapsulated-types.d.ts | 2 +- src/manifold/src/impl.cpp | 2 +- src/manifold/src/manifold.cpp | 2 +- src/manifold/src/sort.cpp | 1 + src/utilities/include/tri_dist.h | 10 ++++------ 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index 2c26e10b8..f75010de7 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -321,7 +321,7 @@ NB_MODULE(manifold3d, m) { return self.MinGap(other, searchLength); }, nb::arg("other"), nb::arg("search_length"), - "Returns the minimum distance between two manifolds." + "Returns the minimum gap between two manifolds." "Returns a float between 0 and searchLength.") .def("calculate_normals", &Manifold::CalculateNormals, nb::arg("normal_idx"), nb::arg("min_sharp_angle") = 60, diff --git a/bindings/wasm/manifold-encapsulated-types.d.ts b/bindings/wasm/manifold-encapsulated-types.d.ts index a86c95cd5..d51afcae9 100644 --- a/bindings/wasm/manifold-encapsulated-types.d.ts +++ b/bindings/wasm/manifold-encapsulated-types.d.ts @@ -847,7 +847,7 @@ export class Manifold { /* - * Returns the minimum distance between two manifolds. Returns a float between + * Returns the minimum gap between two manifolds. Returns a float between * 0 and searchLength. */ minGap(other: Manifold, searchLength: number): number; diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 49527d400..6026bcc12 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -904,7 +904,7 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( return collider_.Collisions(vertsIn); } /* - * Computes the minimum distance between two manifolds. Returns a float between + * Returns the minimum gap between two manifolds. Returns a float between * 0 and searchLength. */ float Manifold::Impl::MinGap(const Manifold::Impl& other, diff --git a/src/manifold/src/manifold.cpp b/src/manifold/src/manifold.cpp index f8972dd7e..810405d46 100644 --- a/src/manifold/src/manifold.cpp +++ b/src/manifold/src/manifold.cpp @@ -929,7 +929,7 @@ Manifold Manifold::Hull(const std::vector& manifolds) { } /** - * Computes the minimum distance between two manifolds. Returns a float between + * Returns the minimum gap between two manifolds. Returns a float between * 0 and searchLength. * * @param other The other manifold to compute the minimum gap to. diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 85b5ee315..4ba51f735 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -420,6 +420,7 @@ void Manifold::Impl::SortFaces(Vec& faceBox, Vec& faceMorton) { /** * Sorts the bounding box and Morton code arrays based on the Morton codes. + * Leaves the original manifold untouched. */ void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const { diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 6709c1a67..8028f7822 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -22,7 +22,7 @@ namespace manifold { // From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/sweep/GuSweepCapsuleCapsule.cpp -// With minor modifications to use glm::vec3 type. +// With minor modifications /** * Returns the distance between two line segments. @@ -84,15 +84,13 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points // From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/LICENSE.md // https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/distance/GuDistanceTriangleTriangle.cpp -// With minor modifications to use glm::vec3 type. +// With minor modifications /** * Returns the minimum squared distance between two triangles. * - * @param[out] cq Closest point on the first triangle. - * @param[out] cp Closest point on the second triangle. - * @param[in] p First triangle. - * @param[in] q Second triangle. + * @param p First triangle. + * @param q Second triangle. */ inline float DistanceTriangleTriangleSquared( const std::array& p, const std::array& q) { From 84878cb69df84452d32d42f61b2667818f2fd655 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 25 Mar 2024 16:18:49 +0100 Subject: [PATCH 31/48] Test whether faceboxes need to be sorted --- src/manifold/src/impl.cpp | 2 +- test/mingap_test.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 6026bcc12..47ac9d0c0 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -923,7 +923,7 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, box.max + glm::vec3(searchLength)); }); - impl.SortFaceBoxMorton(faceBox, faceMorton); + // impl.SortFaceBoxMorton(faceBox, faceMorton); return std::pair{faceBox, faceMorton}; }; diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 4bdb51df5..ca55c61c2 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -97,3 +97,15 @@ TEST(MinGap, ClosestPointOnTriangleFace) { EXPECT_FLOAT_EQ(distance, 1.0f); } + +TEST(MinGap, AfterTransformations) { + auto a = Manifold::Sphere(1.0f, 100); + auto b = Manifold::Sphere(1.0f, 100) + .Scale({3.0f, 1.0f, 1.0f}) + .Rotate(0, 90, 45) + .Translate({3.0f, 0.0f, 0.0f}); + + float distance = a.MinGap(b, 10); + + ASSERT_NEAR(distance, 1.0f, 0.001f); +} From 71e2c57dcbb61e0b8bca34d19b4bb677a80497fe Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 27 Mar 2024 17:22:59 +0100 Subject: [PATCH 32/48] Add min_gap example to all_apis.py --- bindings/python/examples/all_apis.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/python/examples/all_apis.py b/bindings/python/examples/all_apis.py index 53e52fab0..9ff417919 100644 --- a/bindings/python/examples/all_apis.py +++ b/bindings/python/examples/all_apis.py @@ -111,6 +111,9 @@ def all_manifold(): m = m.trim_by_plane((0, 0, 1), 0) m = m.warp(lambda p: (p[0] + 1, p[1] / 2, p[2] * 2)) m = m.warp_batch(lambda ps: ps * [1, 0.5, 2] + [1, 0, 0]) + m = Manifold.cube() + m2 = Manifold.cube().translate([2, 0, 0]) + d = m.min_gap(m2, 2) def run(): From 50b551ce7c8fe1b64b7799da4558fa45e53eac6b Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 27 Mar 2024 17:26:54 +0100 Subject: [PATCH 33/48] Fix formatting --- bindings/python/examples/all_apis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/examples/all_apis.py b/bindings/python/examples/all_apis.py index 9ff417919..c2e231fb5 100644 --- a/bindings/python/examples/all_apis.py +++ b/bindings/python/examples/all_apis.py @@ -111,7 +111,7 @@ def all_manifold(): m = m.trim_by_plane((0, 0, 1), 0) m = m.warp(lambda p: (p[0] + 1, p[1] / 2, p[2] * 2)) m = m.warp_batch(lambda ps: ps * [1, 0.5, 2] + [1, 0, 0]) - m = Manifold.cube() + m = Manifold.cube() m2 = Manifold.cube().translate([2, 0, 0]) d = m.min_gap(m2, 2) From 38ce232da5152860188ec395cfeec0a884b56147 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 27 Mar 2024 17:34:03 +0100 Subject: [PATCH 34/48] Clean up python binding --- bindings/python/manifold3d.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bindings/python/manifold3d.cpp b/bindings/python/manifold3d.cpp index f75010de7..c9f3a5efd 100644 --- a/bindings/python/manifold3d.cpp +++ b/bindings/python/manifold3d.cpp @@ -315,14 +315,10 @@ NB_MODULE(manifold3d, m) { .def("calculate_curvature", &Manifold::CalculateCurvature, nb::arg("gaussian_idx"), nb::arg("mean_idx"), manifold__calculate_curvature__gaussian_idx__mean_idx) - .def( - "min_gap", - [](const Manifold &self, const Manifold &other, float searchLength) { - return self.MinGap(other, searchLength); - }, - nb::arg("other"), nb::arg("search_length"), - "Returns the minimum gap between two manifolds." - "Returns a float between 0 and searchLength.") + .def("min_gap", &Manifold::MinGap, nb::arg("other"), + nb::arg("search_length"), + "Returns the minimum gap between two manifolds." + "Returns a float between 0 and searchLength.") .def("calculate_normals", &Manifold::CalculateNormals, nb::arg("normal_idx"), nb::arg("min_sharp_angle") = 60, manifold__calculate_normals__normal_idx__min_sharp_angle) From 19d356e935b5cd3ef3bd3240c1c4c9c901cce6f4 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Wed, 27 Mar 2024 17:50:29 +0100 Subject: [PATCH 35/48] Fix edge to edge test case --- src/manifold/src/impl.cpp | 2 +- test/mingap_test.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 47ac9d0c0..6026bcc12 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -923,7 +923,7 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, box.max + glm::vec3(searchLength)); }); - // impl.SortFaceBoxMorton(faceBox, faceMorton); + impl.SortFaceBoxMorton(faceBox, faceMorton); return std::pair{faceBox, faceMorton}; }; diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index ca55c61c2..fbe7ccf6f 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -79,12 +79,13 @@ TEST(MinGap, SphereSphereOutOfBounds) { } TEST(MinGap, ClosestPointOnEdge) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube().Translate({2.0f, 1.0f, 0.5f}); + auto a = Manifold::Cube().Rotate(0.0f, 0.0f, 45.0f); + auto b = + Manifold::Cube().Rotate(0.0f, 45.0f, 0.0f).Translate({1.0f, 0.0f, 0.5f}); float distance = a.MinGap(b, 10); - EXPECT_FLOAT_EQ(distance, 1.0f); + EXPECT_FLOAT_EQ(distance, 1.0f - sqrt(2) / 2); } TEST(MinGap, ClosestPointOnTriangleFace) { From 5979ea3701977da2a29664aee26572414339b9bf Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 09:04:42 +0100 Subject: [PATCH 36/48] Test BVH culling --- src/manifold/src/impl.cpp | 28 +++++++++++++--------------- test/mingap_test.cpp | 39 +++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 6026bcc12..f9294a4b2 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -910,25 +910,23 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( float Manifold::Impl::MinGap(const Manifold::Impl& other, float searchLength) const { ZoneScoped; - auto getSortedExpandedFaceBoxMorton = - [searchLength](const Manifold::Impl& impl) { - Vec faceBox; - Vec faceMorton; + Vec faceBox; + Vec faceMorton; - impl.GetFaceBoxMorton(faceBox, faceMorton); + this->GetFaceBoxMorton(faceBox, faceMorton); + this->SortFaceBoxMorton(faceBox, faceMorton); - transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), [searchLength](const Box& box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); + transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), + faceBox.begin(), [searchLength](const Box& box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); - impl.SortFaceBoxMorton(faceBox, faceMorton); - return std::pair{faceBox, faceMorton}; - }; + Vec faceBoxOther; + Vec faceMortonOther; - auto [faceBox, faceMorton] = getSortedExpandedFaceBoxMorton(*this); - auto [faceBoxOther, faceMortonOther] = getSortedExpandedFaceBoxMorton(other); + other.GetFaceBoxMorton(faceBoxOther, faceMortonOther); + other.SortFaceBoxMorton(faceBoxOther, faceMortonOther); Collider collider{faceBox, faceMorton}; diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index fbe7ccf6f..9b507d5b9 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -19,7 +19,7 @@ TEST(MinGap, CubeCube) { auto a = Manifold::Cube(); auto b = Manifold::Cube().Translate({2.0f, 2.0f, 0.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 1.5f); EXPECT_FLOAT_EQ(distance, sqrt(2)); } @@ -28,7 +28,7 @@ TEST(MinGap, CubeCube2) { auto a = Manifold::Cube(); auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 3.0f); EXPECT_FLOAT_EQ(distance, sqrt(2) * 2); } @@ -37,16 +37,16 @@ TEST(MinGap, CubeCubeOutOfBounds) { auto a = Manifold::Cube(); auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); - float distance = a.MinGap(b, 0.1f); + float distance = a.MinGap(b, 2.5f); - EXPECT_FLOAT_EQ(distance, 0.1f); + EXPECT_FLOAT_EQ(distance, 2.5f); } TEST(MinGap, CubeSphereOverlapping) { auto a = Manifold::Cube(); auto b = Manifold::Sphere(1.0f); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 0.1f); EXPECT_FLOAT_EQ(distance, 0.0f); } @@ -55,7 +55,7 @@ TEST(MinGap, SphereSphere) { auto a = Manifold::Sphere(1.0f); auto b = Manifold::Sphere(1.0f).Translate({5.0f, 0.0f, 0.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 3.1f); EXPECT_FLOAT_EQ(distance, 3.0f); } @@ -64,7 +64,7 @@ TEST(MinGap, SphereSphere2) { auto a = Manifold::Sphere(1.0f); auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 0.85f); EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); } @@ -73,9 +73,9 @@ TEST(MinGap, SphereSphereOutOfBounds) { auto a = Manifold::Sphere(1.0f); auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); - float distance = a.MinGap(b, 0.1f); + float distance = a.MinGap(b, 0.8f); - EXPECT_FLOAT_EQ(distance, 0.1f); + EXPECT_FLOAT_EQ(distance, 0.8f); } TEST(MinGap, ClosestPointOnEdge) { @@ -83,7 +83,7 @@ TEST(MinGap, ClosestPointOnEdge) { auto b = Manifold::Cube().Rotate(0.0f, 45.0f, 0.0f).Translate({1.0f, 0.0f, 0.5f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 0.3f); EXPECT_FLOAT_EQ(distance, 1.0f - sqrt(2) / 2); } @@ -94,7 +94,7 @@ TEST(MinGap, ClosestPointOnTriangleFace) { .Scale({10.0f, 10.0f, 10.0f}) .Translate({2.0f, -5.0f, -1.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 1.1f); EXPECT_FLOAT_EQ(distance, 1.0f); } @@ -106,7 +106,22 @@ TEST(MinGap, AfterTransformations) { .Rotate(0, 90, 45) .Translate({3.0f, 0.0f, 0.0f}); - float distance = a.MinGap(b, 10); + float distance = a.MinGap(b, 1.1f); + + ASSERT_NEAR(distance, 1.0f, 0.001f); +} + +TEST(MinGap, AfterTransformationsDummyBooleanOp) { + auto a = Manifold::Sphere(1.0f, 100); + auto b = Manifold::Sphere(1.0f, 100) + .Scale({3.0f, 1.0f, 1.0f}) + .Rotate(0, 90, 45) + .Translate({3.0f, 0.0f, 0.0f}); + + a = a + a; + b = b + b; + + float distance = a.MinGap(b, 1.1f); ASSERT_NEAR(distance, 1.0f, 0.001f); } From 0f47505ff808dafeba10437353d70eb4f3692d67 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 20:22:26 +0100 Subject: [PATCH 37/48] Remove sorting of other manifold's boxes --- src/manifold/src/impl.cpp | 1 - test/mingap_test.cpp | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index f9294a4b2..b3c6d6786 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -926,7 +926,6 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, Vec faceMortonOther; other.GetFaceBoxMorton(faceBoxOther, faceMortonOther); - other.SortFaceBoxMorton(faceBoxOther, faceMortonOther); Collider collider{faceBox, faceMorton}; diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 9b507d5b9..99407dd39 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -111,17 +111,14 @@ TEST(MinGap, AfterTransformations) { ASSERT_NEAR(distance, 1.0f, 0.001f); } -TEST(MinGap, AfterTransformationsDummyBooleanOp) { +TEST(MinGap, AfterTransformationsOutOfRange) { auto a = Manifold::Sphere(1.0f, 100); auto b = Manifold::Sphere(1.0f, 100) .Scale({3.0f, 1.0f, 1.0f}) .Rotate(0, 90, 45) .Translate({3.0f, 0.0f, 0.0f}); - a = a + a; - b = b + b; + float distance = a.MinGap(b, 0.95f); - float distance = a.MinGap(b, 1.1f); - - ASSERT_NEAR(distance, 1.0f, 0.001f); + ASSERT_NEAR(distance, 0.95f, 0.001f); } From 5e3732cef9e46707a7fbcd7522951a39aa3ce5d8 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 20:44:40 +0100 Subject: [PATCH 38/48] Use collider_ member, remove sorting --- src/manifold/src/impl.cpp | 21 +++++++-------------- src/manifold/src/impl.h | 1 - src/manifold/src/sort.cpp | 21 --------------------- test/mingap_test.cpp | 8 ++++---- 4 files changed, 11 insertions(+), 40 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index b3c6d6786..ec9499937 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -910,26 +910,19 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( float Manifold::Impl::MinGap(const Manifold::Impl& other, float searchLength) const { ZoneScoped; - Vec faceBox; - Vec faceMorton; - - this->GetFaceBoxMorton(faceBox, faceMorton); - this->SortFaceBoxMorton(faceBox, faceMorton); - - transform(autoPolicy(faceBox.size()), faceBox.begin(), faceBox.end(), - faceBox.begin(), [searchLength](const Box& box) { - return Box(box.min - glm::vec3(searchLength), - box.max + glm::vec3(searchLength)); - }); - Vec faceBoxOther; Vec faceMortonOther; other.GetFaceBoxMorton(faceBoxOther, faceMortonOther); - Collider collider{faceBox, faceMorton}; + transform(autoPolicy(faceBoxOther.size()), faceBoxOther.begin(), + faceBoxOther.end(), faceBoxOther.begin(), + [searchLength](const Box& box) { + return Box(box.min - glm::vec3(searchLength), + box.max + glm::vec3(searchLength)); + }); - SparseIndices collisions = collider.Collisions(faceBoxOther.cview()); + SparseIndices collisions = collider_.Collisions(faceBoxOther.cview()); float minDistanceSquared = searchLength * searchLength; diff --git a/src/manifold/src/impl.h b/src/manifold/src/impl.h index 7307241ba..7cc97556a 100644 --- a/src/manifold/src/impl.h +++ b/src/manifold/src/impl.h @@ -112,7 +112,6 @@ struct Manifold::Impl { void CompactProps(); void GetFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const; void SortFaces(Vec& faceBox, Vec& faceMorton); - void SortFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const; void GatherFaces(const Vec& faceNew2Old); void GatherFaces(const Impl& old, const Vec& faceNew2Old); diff --git a/src/manifold/src/sort.cpp b/src/manifold/src/sort.cpp index 4ba51f735..457d6f044 100644 --- a/src/manifold/src/sort.cpp +++ b/src/manifold/src/sort.cpp @@ -418,27 +418,6 @@ void Manifold::Impl::SortFaces(Vec& faceBox, Vec& faceMorton) { GatherFaces(faceNew2Old); } -/** - * Sorts the bounding box and Morton code arrays based on the Morton codes. - * Leaves the original manifold untouched. - */ -void Manifold::Impl::SortFaceBoxMorton(Vec& faceBox, - Vec& faceMorton) const { - ZoneScoped; - Vec faceNew2Old(NumTri()); - auto policy = autoPolicy(faceNew2Old.size()); - sequence(policy, faceNew2Old.begin(), faceNew2Old.end()); - - stable_sort(policy, zip(faceMorton.begin(), faceNew2Old.begin()), - zip(faceMorton.end(), faceNew2Old.end()), - [](const thrust::tuple& a, - const thrust::tuple& b) { - return thrust::get<0>(a) < thrust::get<0>(b); - }); - - Permute(faceBox, faceNew2Old); -} - /** * Creates the halfedge_ vector for this manifold by copying a set of faces from * another manifold, given by oldHalfedge. Input faceNew2Old defines the old diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp index 99407dd39..b118fc31b 100644 --- a/test/mingap_test.cpp +++ b/test/mingap_test.cpp @@ -100,8 +100,8 @@ TEST(MinGap, ClosestPointOnTriangleFace) { } TEST(MinGap, AfterTransformations) { - auto a = Manifold::Sphere(1.0f, 100); - auto b = Manifold::Sphere(1.0f, 100) + auto a = Manifold::Sphere(1.0f, 256); + auto b = Manifold::Sphere(1.0f, 256) .Scale({3.0f, 1.0f, 1.0f}) .Rotate(0, 90, 45) .Translate({3.0f, 0.0f, 0.0f}); @@ -112,8 +112,8 @@ TEST(MinGap, AfterTransformations) { } TEST(MinGap, AfterTransformationsOutOfRange) { - auto a = Manifold::Sphere(1.0f, 100); - auto b = Manifold::Sphere(1.0f, 100) + auto a = Manifold::Sphere(1.0f, 256); + auto b = Manifold::Sphere(1.0f, 256) .Scale({3.0f, 1.0f, 1.0f}) .Rotate(0, 90, 45) .Translate({3.0f, 0.0f, 0.0f}); From 25643de935b8da75489f9178919aece6bded8ca1 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 21:03:07 +0100 Subject: [PATCH 39/48] Move tests to manifold_test.cpp --- test/CMakeLists.txt | 2 +- test/manifold_test.cpp | 163 +++++++++++++++++++++++++++++++++++++++++ test/mingap_test.cpp | 124 ------------------------------- test/tri_dist_test.cpp | 89 ---------------------- 4 files changed, 164 insertions(+), 214 deletions(-) delete mode 100644 test/mingap_test.cpp delete mode 100644 test/tri_dist_test.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 53514c9ea..b9a45b1f6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,7 @@ project(manifold_test) set(CMAKE_CXX_STANDARD 17) enable_testing() -set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp mingap_test.cpp tri_dist_test.cpp) +set(SOURCE_FILES polygon_test.cpp cross_section_test.cpp manifold_test.cpp boolean_test.cpp sdf_test.cpp samples_test.cpp test_main.cpp) if(MANIFOLD_CBIND AND NOT EMSCRIPTEN) list(APPEND SOURCE_FILES manifoldc_test.cpp) diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index f67bee9f3..a158ec9e0 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -18,6 +18,7 @@ #include "cross_section.h" #include "test.h" +#include "tri_dist.h" #ifdef MANIFOLD_EXPORT #include "meshIO.h" @@ -833,3 +834,165 @@ TEST(Manifold, EmptyHull) { {0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0}}; EXPECT_TRUE(Manifold::Hull(coplanar).IsEmpty()); } + +TEST(Manifold, MinGapCubeCube) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({2, 2, 0}); + + float distance = a.MinGap(b, 1.5f); + + EXPECT_FLOAT_EQ(distance, sqrt(2)); +} + +TEST(Manifold, MinGapCubeCube2) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({3, 3, 0}); + + float distance = a.MinGap(b, 3); + + EXPECT_FLOAT_EQ(distance, sqrt(2) * 2); +} + +TEST(Manifold, MinGapCubeCubeOutOfBounds) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Translate({3, 3, 0}); + + float distance = a.MinGap(b, 2.5f); + + EXPECT_FLOAT_EQ(distance, 2.5f); +} + +TEST(Manifold, MinGapCubeSphereOverlapping) { + auto a = Manifold::Cube(); + auto b = Manifold::Sphere(1); + + float distance = a.MinGap(b, 0.1f); + + EXPECT_FLOAT_EQ(distance, 0); +} + +TEST(Manifold, MinGapSphereSphere) { + auto a = Manifold::Sphere(1); + auto b = Manifold::Sphere(1).Translate({2, 2, 0}); + + float distance = a.MinGap(b, 0.85f); + + EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); +} + +TEST(Manifold, MinGapSphereSphere2) { + auto a = Manifold::Sphere(1); + auto b = Manifold::Sphere(1).Translate({2, 2, 0}); + + float distance = a.MinGap(b, 0.85f); + + EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); +} + +TEST(Manifold, MinGapSphereSphereOutOfBounds) { + auto a = Manifold::Sphere(1); + auto b = Manifold::Sphere(1).Translate({2, 2, 0}); + + float distance = a.MinGap(b, 0.8f); + + EXPECT_FLOAT_EQ(distance, 0.8f); +} + +TEST(Manifold, MinGapClosestPointOnEdge) { + auto a = Manifold::Cube().Rotate(0, 0, 45); + auto b = Manifold::Cube().Rotate(0, 45, 0).Translate({1, 0, 0.5f}); + + float distance = a.MinGap(b, 0.3f); + + EXPECT_FLOAT_EQ(distance, 1 - sqrt(2) / 2); +} + +TEST(Manifold, MinGapClosestPointOnTriangleFace) { + auto a = Manifold::Cube(); + auto b = Manifold::Cube().Scale({10, 10, 10}).Translate({2, -5, -1}); + + float distance = a.MinGap(b, 1.1f); + + EXPECT_FLOAT_EQ(distance, 1); +} + +TEST(Manifold, MingapComplex) { + auto a = Manifold::Sphere(1, 256); + auto b = + Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + {3, 0, 0}); + + float distance = a.MinGap(b, 1.1f); + + ASSERT_NEAR(distance, 1, 0.001f); +} + +TEST(Manifold, MinGapComplexOutOfRange) { + auto a = Manifold::Sphere(1, 256); + auto b = + Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + {3, 0, 0}); + + float distance = a.MinGap(b, 0.95f); + + ASSERT_NEAR(distance, 0.95f, 0.001f); +} +TEST(Manifold, TriangleDistanceClosestPointsOnVertices) { + std::array p = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0, 0}, + glm::vec3{0, 1, 0}}; + + std::array q = {glm::vec3{2, 0, 0}, glm::vec3{4, 0, 0}, + glm::vec3{3, 1, 0}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 1); +} + +TEST(Manifold, TriangleDistanceClosestPointOnEdge) { + std::array p = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0, 0}, + glm::vec3{0, 1, 0}}; + + std::array q = {glm::vec3{-1, 2, 0}, glm::vec3{1, 2, 0}, + glm::vec3{0, 3, 0}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 1); +} + +TEST(Manifold, TriangleDistanceClosestPointOnEdge2) { + std::array p = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0, 0}, + glm::vec3{0, 1, 0}}; + + std::array q = {glm::vec3{1, 1, 0}, glm::vec3{3, 1, 0}, + glm::vec3{2, 2, 0}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 0.5f); +} + +TEST(Manifold, TriangleDistanceClosestPointOnFace) { + std::array p = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0, 0}, + glm::vec3{0, 1, 0}}; + + std::array q = {glm::vec3{-1, 2, -0.5f}, glm::vec3{1, 2, -0.5f}, + glm::vec3{0, 2, 1.5f}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 1); +} + +TEST(Manifold, TriangleDistanceOverlapping) { + std::array p = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0, 0}, + glm::vec3{0, 1, 0}}; + + std::array q = {glm::vec3{-1, 0, 0}, glm::vec3{1, 0.5f, 0}, + glm::vec3{0, 1, 0}}; + + float distance = DistanceTriangleTriangleSquared(p, q); + + EXPECT_FLOAT_EQ(distance, 0); +} diff --git a/test/mingap_test.cpp b/test/mingap_test.cpp deleted file mode 100644 index b118fc31b..000000000 --- a/test/mingap_test.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2024 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "manifold.h" -#include "test.h" - -TEST(MinGap, CubeCube) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube().Translate({2.0f, 2.0f, 0.0f}); - - float distance = a.MinGap(b, 1.5f); - - EXPECT_FLOAT_EQ(distance, sqrt(2)); -} - -TEST(MinGap, CubeCube2) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); - - float distance = a.MinGap(b, 3.0f); - - EXPECT_FLOAT_EQ(distance, sqrt(2) * 2); -} - -TEST(MinGap, CubeCubeOutOfBounds) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube().Translate({3.0f, 3.0f, 0.0f}); - - float distance = a.MinGap(b, 2.5f); - - EXPECT_FLOAT_EQ(distance, 2.5f); -} - -TEST(MinGap, CubeSphereOverlapping) { - auto a = Manifold::Cube(); - auto b = Manifold::Sphere(1.0f); - - float distance = a.MinGap(b, 0.1f); - - EXPECT_FLOAT_EQ(distance, 0.0f); -} - -TEST(MinGap, SphereSphere) { - auto a = Manifold::Sphere(1.0f); - auto b = Manifold::Sphere(1.0f).Translate({5.0f, 0.0f, 0.0f}); - - float distance = a.MinGap(b, 3.1f); - - EXPECT_FLOAT_EQ(distance, 3.0f); -} - -TEST(MinGap, SphereSphere2) { - auto a = Manifold::Sphere(1.0f); - auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); - - float distance = a.MinGap(b, 0.85f); - - EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); -} - -TEST(MinGap, SphereSphereOutOfBounds) { - auto a = Manifold::Sphere(1.0f); - auto b = Manifold::Sphere(1.0f).Translate({2.0f, 2.0f, 0.0f}); - - float distance = a.MinGap(b, 0.8f); - - EXPECT_FLOAT_EQ(distance, 0.8f); -} - -TEST(MinGap, ClosestPointOnEdge) { - auto a = Manifold::Cube().Rotate(0.0f, 0.0f, 45.0f); - auto b = - Manifold::Cube().Rotate(0.0f, 45.0f, 0.0f).Translate({1.0f, 0.0f, 0.5f}); - - float distance = a.MinGap(b, 0.3f); - - EXPECT_FLOAT_EQ(distance, 1.0f - sqrt(2) / 2); -} - -TEST(MinGap, ClosestPointOnTriangleFace) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube() - .Scale({10.0f, 10.0f, 10.0f}) - .Translate({2.0f, -5.0f, -1.0f}); - - float distance = a.MinGap(b, 1.1f); - - EXPECT_FLOAT_EQ(distance, 1.0f); -} - -TEST(MinGap, AfterTransformations) { - auto a = Manifold::Sphere(1.0f, 256); - auto b = Manifold::Sphere(1.0f, 256) - .Scale({3.0f, 1.0f, 1.0f}) - .Rotate(0, 90, 45) - .Translate({3.0f, 0.0f, 0.0f}); - - float distance = a.MinGap(b, 1.1f); - - ASSERT_NEAR(distance, 1.0f, 0.001f); -} - -TEST(MinGap, AfterTransformationsOutOfRange) { - auto a = Manifold::Sphere(1.0f, 256); - auto b = Manifold::Sphere(1.0f, 256) - .Scale({3.0f, 1.0f, 1.0f}) - .Rotate(0, 90, 45) - .Translate({3.0f, 0.0f, 0.0f}); - - float distance = a.MinGap(b, 0.95f); - - ASSERT_NEAR(distance, 0.95f, 0.001f); -} diff --git a/test/tri_dist_test.cpp b/test/tri_dist_test.cpp deleted file mode 100644 index 950bea9ee..000000000 --- a/test/tri_dist_test.cpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2024 The Manifold Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tri_dist.h" - -#include "manifold.h" -#include "public.h" -#include "test.h" - -TEST(TriangleDistance, ClosestPointsOnVertices) { - std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.0f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - std::array q = {glm::vec3{2.0f, 0.0f, 0.0f}, - glm::vec3{4.0f, 0.0f, 0.0f}, - glm::vec3{3.0f, 1.0f, 0.0f}}; - - float distance = DistanceTriangleTriangleSquared(p, q); - - EXPECT_FLOAT_EQ(distance, 1.0f); -} - -TEST(TriangleDistance, ClosestPointOnEdge) { - std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.0f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - std::array q = {glm::vec3{-1.0f, 2.0f, 0.0f}, - glm::vec3{1.0f, 2.0f, 0.0f}, - glm::vec3{0.0f, 3.0f, 0.0f}}; - - float distance = DistanceTriangleTriangleSquared(p, q); - - EXPECT_FLOAT_EQ(distance, 1.0f); -} - -TEST(TriangleDistance, ClosestPointOnEdge2) { - std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.0f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - std::array q = {glm::vec3{1.0f, 1.0f, 0.0f}, - glm::vec3{3.0f, 1.0f, 0.0f}, - glm::vec3{2.0f, 2.0f, 0.0f}}; - - float distance = DistanceTriangleTriangleSquared(p, q); - - EXPECT_FLOAT_EQ(distance, 0.5f); -} - -TEST(TriangleDistance, ClosestPointOnFace) { - std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.0f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - std::array q = {glm::vec3{-1.0f, 2.0f, -0.5f}, - glm::vec3{1.0f, 2.0f, -0.5f}, - glm::vec3{0.0f, 2.0f, 1.5f}}; - - float distance = DistanceTriangleTriangleSquared(p, q); - - EXPECT_FLOAT_EQ(distance, 1.0f); -} - -TEST(TriangleDistance, Overlapping) { - std::array p = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.0f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - std::array q = {glm::vec3{-1.0f, 0.0f, 0.0f}, - glm::vec3{1.0f, 0.5f, 0.0f}, - glm::vec3{0.0f, 1.0f, 0.0f}}; - - float distance = DistanceTriangleTriangleSquared(p, q); - - EXPECT_FLOAT_EQ(distance, 0.0f); -} From 93a1726bf739957e473611a709718a58e16436d6 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 21:07:08 +0100 Subject: [PATCH 40/48] Remove whitespace --- src/manifold/src/impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/manifold/src/impl.h b/src/manifold/src/impl.h index 7cc97556a..6f026b730 100644 --- a/src/manifold/src/impl.h +++ b/src/manifold/src/impl.h @@ -112,7 +112,6 @@ struct Manifold::Impl { void CompactProps(); void GetFaceBoxMorton(Vec& faceBox, Vec& faceMorton) const; void SortFaces(Vec& faceBox, Vec& faceMorton); - void GatherFaces(const Vec& faceNew2Old); void GatherFaces(const Impl& old, const Vec& faceNew2Old); From 7979fe979bf006a311ea83e4567ff880f2b08459 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Thu, 28 Mar 2024 21:11:25 +0100 Subject: [PATCH 41/48] Rename some tests for clarity --- test/manifold_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index a158ec9e0..7cd93ff5c 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -916,8 +916,8 @@ TEST(Manifold, MinGapClosestPointOnTriangleFace) { EXPECT_FLOAT_EQ(distance, 1); } -TEST(Manifold, MingapComplex) { - auto a = Manifold::Sphere(1, 256); +TEST(Manifold, MingapAfterTransformations) { + auto a = Manifold::Sphere(1, 256).Rotate(30, 30, 30); auto b = Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); @@ -927,8 +927,8 @@ TEST(Manifold, MingapComplex) { ASSERT_NEAR(distance, 1, 0.001f); } -TEST(Manifold, MinGapComplexOutOfRange) { - auto a = Manifold::Sphere(1, 256); +TEST(Manifold, MinGapAfterTransformationsOutOfBounds) { + auto a = Manifold::Sphere(1, 256).Rotate(30, 30, 30); auto b = Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); From 8ac46f5e64c8c1b241bb90d206d436fe13c1a531 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Fri, 29 Mar 2024 18:00:11 +0100 Subject: [PATCH 42/48] Remove redundant test, modify test for edge to edge test for clarity --- test/manifold_test.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index 7cd93ff5c..d1d71622d 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -853,15 +853,6 @@ TEST(Manifold, MinGapCubeCube2) { EXPECT_FLOAT_EQ(distance, sqrt(2) * 2); } -TEST(Manifold, MinGapCubeCubeOutOfBounds) { - auto a = Manifold::Cube(); - auto b = Manifold::Cube().Translate({3, 3, 0}); - - float distance = a.MinGap(b, 2.5f); - - EXPECT_FLOAT_EQ(distance, 2.5f); -} - TEST(Manifold, MinGapCubeSphereOverlapping) { auto a = Manifold::Cube(); auto b = Manifold::Sphere(1); @@ -880,15 +871,6 @@ TEST(Manifold, MinGapSphereSphere) { EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); } -TEST(Manifold, MinGapSphereSphere2) { - auto a = Manifold::Sphere(1); - auto b = Manifold::Sphere(1).Translate({2, 2, 0}); - - float distance = a.MinGap(b, 0.85f); - - EXPECT_FLOAT_EQ(distance, 2 * sqrt(2) - 2); -} - TEST(Manifold, MinGapSphereSphereOutOfBounds) { auto a = Manifold::Sphere(1); auto b = Manifold::Sphere(1).Translate({2, 2, 0}); @@ -899,12 +881,13 @@ TEST(Manifold, MinGapSphereSphereOutOfBounds) { } TEST(Manifold, MinGapClosestPointOnEdge) { - auto a = Manifold::Cube().Rotate(0, 0, 45); - auto b = Manifold::Cube().Rotate(0, 45, 0).Translate({1, 0, 0.5f}); + auto a = Manifold::Cube({1, 1, 1}, true).Rotate(0, 0, 45); + auto b = + Manifold::Cube({1, 1, 1}, true).Rotate(0, 45, 0).Translate({2, 0, 0}); - float distance = a.MinGap(b, 0.3f); + float distance = a.MinGap(b, 0.7f); - EXPECT_FLOAT_EQ(distance, 1 - sqrt(2) / 2); + EXPECT_FLOAT_EQ(distance, 2 - sqrt(2)); } TEST(Manifold, MinGapClosestPointOnTriangleFace) { From a237f7491971835749abbebe00a78c9b7deb5d99 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Fri, 29 Mar 2024 18:03:03 +0100 Subject: [PATCH 43/48] Fix comments --- src/utilities/include/tri_dist.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 8028f7822..987ede501 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -27,12 +27,12 @@ namespace manifold { /** * Returns the distance between two line segments. * - * @param[out] cq Closest point on line segment pa. - * @param[out] cp Closest point on line segment qb. + * @param[out] x Closest point on line segment pa. + * @param[out] y Closest point on line segment qb. * @param[in] p One endpoint of the first line segment. - * @param[in] q Other endpoint of the first line segment. + * @param[in] a Other endpoint of the first line segment. * @param[in] p One endpoint of the second line segment. - * @param[in] q Other endpoint of the second line segment. + * @param[in] b Other endpoint of the second line segment. */ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points const glm::vec3& p, From 8713ca2d34d814eb647f1c7e495964f588218156 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 30 Mar 2024 09:18:12 +0100 Subject: [PATCH 44/48] Parallelize narrow phase --- src/manifold/src/impl.cpp | 48 ++++++++++++++++++++++++--------------- test/manifold_test.cpp | 8 +++---- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index ec9499937..9d41e505d 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -903,6 +903,30 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( else return collider_.Collisions(vertsIn); } + +struct GetDistanceTriangleTriangleSquared { + const SparseIndices& collisions; + const VecView vertPos_; + const VecView vertPosOther_; + const VecView halfedge_; + const VecView halfedgeOther_; + + float operator()(int i) { + const int tri = collisions.Get(i, 1); + const int triOther = collisions.Get(i, 0); + + std::array p; + std::array q; + + for (const int j : {0, 1, 2}) { + p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; + q[j] = vertPosOther_[halfedgeOther_[3 * triOther + j].startVert]; + } + + return DistanceTriangleTriangleSquared(p, q); + } +}; + /* * Returns the minimum gap between two manifolds. Returns a float between * 0 and searchLength. @@ -924,24 +948,12 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, SparseIndices collisions = collider_.Collisions(faceBoxOther.cview()); - float minDistanceSquared = searchLength * searchLength; - - for (int i = 0; i < collisions.size(); ++i) { - const int tri = collisions.Get(i, 1); - const int triOther = collisions.Get(i, 0); - - std::array p; - std::array q; - - for (const int j : {0, 1, 2}) { - p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; - q[j] = other.vertPos_[other.halfedge_[3 * triOther + j].startVert]; - } - - float distanceSquared = DistanceTriangleTriangleSquared(p, q); - - minDistanceSquared = std::min(minDistanceSquared, distanceSquared); - } + float minDistanceSquared = transform_reduce( + autoPolicy(collisions.size()), thrust::counting_iterator(0), + thrust::counting_iterator(collisions.size()), + GetDistanceTriangleTriangleSquared{collisions, vertPos_, other.vertPos_, + halfedge_, other.halfedge_}, + searchLength * searchLength, thrust::minimum()); return sqrt(minDistanceSquared); }; diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index d1d71622d..e17b1a718 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -900,9 +900,9 @@ TEST(Manifold, MinGapClosestPointOnTriangleFace) { } TEST(Manifold, MingapAfterTransformations) { - auto a = Manifold::Sphere(1, 256).Rotate(30, 30, 30); + auto a = Manifold::Sphere(1, 1024).Rotate(30, 30, 30); auto b = - Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + Manifold::Sphere(1, 1024).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); float distance = a.MinGap(b, 1.1f); @@ -911,9 +911,9 @@ TEST(Manifold, MingapAfterTransformations) { } TEST(Manifold, MinGapAfterTransformationsOutOfBounds) { - auto a = Manifold::Sphere(1, 256).Rotate(30, 30, 30); + auto a = Manifold::Sphere(1, 1024).Rotate(30, 30, 30); auto b = - Manifold::Sphere(1, 256).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + Manifold::Sphere(1, 1024).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); float distance = a.MinGap(b, 0.95f); From 5659396fa3eadd1778ed09031eb89eae122b0f5d Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 30 Mar 2024 09:29:30 +0100 Subject: [PATCH 45/48] Reduce sphere res in test case to not cause out of memory error --- test/manifold_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index e17b1a718..6829db5fb 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -900,9 +900,9 @@ TEST(Manifold, MinGapClosestPointOnTriangleFace) { } TEST(Manifold, MingapAfterTransformations) { - auto a = Manifold::Sphere(1, 1024).Rotate(30, 30, 30); + auto a = Manifold::Sphere(1, 512).Rotate(30, 30, 30); auto b = - Manifold::Sphere(1, 1024).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + Manifold::Sphere(1, 512).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); float distance = a.MinGap(b, 1.1f); @@ -911,9 +911,9 @@ TEST(Manifold, MingapAfterTransformations) { } TEST(Manifold, MinGapAfterTransformationsOutOfBounds) { - auto a = Manifold::Sphere(1, 1024).Rotate(30, 30, 30); + auto a = Manifold::Sphere(1, 512).Rotate(30, 30, 30); auto b = - Manifold::Sphere(1, 1024).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( + Manifold::Sphere(1, 512).Scale({3, 1, 1}).Rotate(0, 90, 45).Translate( {3, 0, 0}); float distance = a.MinGap(b, 0.95f); From ca020cf83f0e5bcfe9ed06e44e40b4236093e024 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 30 Mar 2024 16:47:39 +0100 Subject: [PATCH 46/48] Add complex test case --- test/manifold_test.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/manifold_test.cpp b/test/manifold_test.cpp index 6829db5fb..5160c6283 100644 --- a/test/manifold_test.cpp +++ b/test/manifold_test.cpp @@ -17,6 +17,7 @@ #include #include "cross_section.h" +#include "samples.h" #include "test.h" #include "tri_dist.h" @@ -910,6 +911,15 @@ TEST(Manifold, MingapAfterTransformations) { ASSERT_NEAR(distance, 1, 0.001f); } +TEST(Manifold, MingapStretchyBracelet) { + auto a = StretchyBracelet(); + auto b = StretchyBracelet().Translate({0, 0, 20}); + + float distance = a.MinGap(b, 10); + + ASSERT_NEAR(distance, 5, 0.001f); +} + TEST(Manifold, MinGapAfterTransformationsOutOfBounds) { auto a = Manifold::Sphere(1, 512).Rotate(30, 30, 30); auto b = From 8ed4373158b4431541ad382a8d59fddda2519f55 Mon Sep 17 00:00:00 2001 From: mleleszi Date: Sat, 30 Mar 2024 17:05:17 +0100 Subject: [PATCH 47/48] Remove unnecessary cast --- src/utilities/include/tri_dist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/include/tri_dist.h b/src/utilities/include/tri_dist.h index 987ede501..f768f7f90 100644 --- a/src/utilities/include/tri_dist.h +++ b/src/utilities/include/tri_dist.h @@ -77,8 +77,8 @@ inline void EdgeEdgeDist(glm::vec3& x, glm::vec3& y, // closest points u = 0.0f; t = ADotA != 0.0f ? glm::clamp(ADotT / ADotA, 0.0f, 1.0f) : 0.0f; } - x = p + a * static_cast(t); - y = q + b * static_cast(u); + x = p + a * t; + y = q + b * u; } // From NVIDIA-Omniverse PhysX - BSD 3-Clause "New" or "Revised" License From 3786209ae6e0ca4816654eb075956fb0da06cb4e Mon Sep 17 00:00:00 2001 From: mleleszi Date: Mon, 1 Apr 2024 21:30:37 +0200 Subject: [PATCH 48/48] Refactor functor is lambda --- src/manifold/src/impl.cpp | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/manifold/src/impl.cpp b/src/manifold/src/impl.cpp index 9d41e505d..014d2945b 100644 --- a/src/manifold/src/impl.cpp +++ b/src/manifold/src/impl.cpp @@ -904,29 +904,6 @@ SparseIndices Manifold::Impl::VertexCollisionsZ( return collider_.Collisions(vertsIn); } -struct GetDistanceTriangleTriangleSquared { - const SparseIndices& collisions; - const VecView vertPos_; - const VecView vertPosOther_; - const VecView halfedge_; - const VecView halfedgeOther_; - - float operator()(int i) { - const int tri = collisions.Get(i, 1); - const int triOther = collisions.Get(i, 0); - - std::array p; - std::array q; - - for (const int j : {0, 1, 2}) { - p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; - q[j] = vertPosOther_[halfedgeOther_[3 * triOther + j].startVert]; - } - - return DistanceTriangleTriangleSquared(p, q); - } -}; - /* * Returns the minimum gap between two manifolds. Returns a float between * 0 and searchLength. @@ -951,8 +928,20 @@ float Manifold::Impl::MinGap(const Manifold::Impl& other, float minDistanceSquared = transform_reduce( autoPolicy(collisions.size()), thrust::counting_iterator(0), thrust::counting_iterator(collisions.size()), - GetDistanceTriangleTriangleSquared{collisions, vertPos_, other.vertPos_, - halfedge_, other.halfedge_}, + [&collisions, this, &other](int i) { + const int tri = collisions.Get(i, 1); + const int triOther = collisions.Get(i, 0); + + std::array p; + std::array q; + + for (const int j : {0, 1, 2}) { + p[j] = vertPos_[halfedge_[3 * tri + j].startVert]; + q[j] = other.vertPos_[other.halfedge_[3 * triOther + j].startVert]; + } + + return DistanceTriangleTriangleSquared(p, q); + }, searchLength * searchLength, thrust::minimum()); return sqrt(minDistanceSquared);