Skip to content

Commit

Permalink
Fix Merge manifoldness issues (#481)
Browse files Browse the repository at this point in the history
* test passes

* fixed merge properly

* fixed relation

* fixed pinched verts

* added WASM debug instructions
  • Loading branch information
elalish authored Jul 7, 2023
1 parent 4b65ff3 commit 96c57c0
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 14 deletions.
6 changes: 6 additions & 0 deletions bindings/wasm/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ See `package.json` for other useful scripts.

Note that the `emcmake` command automatically copies your WASM build into `built/`, (here, not just under the `buildWASM` directory) which is then packaged by Vite into `dist/assets/`.

To debug the WASM build directly in Chrome dev tools, simply build in debug mode:
```
emcmake cmake -DCMAKE_BUILD_TYPE=Debug .. && emmake make
```
and install the [DWARF](goo.gle/wasm-debugging-extension) Chrome extension.

When testing [ManifoldCAD.org](https://manifoldcad.org/) (either locally or the
deployed version) note that it uses a service worker for faster loading. This
means you need to open the page twice to see updates (the first time loads the
Expand Down
35 changes: 30 additions & 5 deletions src/manifold/src/edge_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,13 @@ void Manifold::Impl::PairUp(int edge0, int edge1) {
// (edgeEdge.endVert must == startEdge.endVert), updating each edge to point
// to vert instead.
void Manifold::Impl::UpdateVert(int vert, int startEdge, int endEdge) {
while (startEdge != endEdge) {
halfedge_[startEdge].endVert = vert;
startEdge = NextHalfedge(startEdge);
halfedge_[startEdge].startVert = vert;
startEdge = halfedge_[startEdge].pairedHalfedge;
int current = startEdge;
while (current != endEdge) {
halfedge_[current].endVert = vert;
current = NextHalfedge(current);
halfedge_[current].startVert = vert;
current = halfedge_[current].pairedHalfedge;
ASSERT(current != startEdge, logicErr, "infinite loop in decimator!");
}
}

Expand Down Expand Up @@ -561,4 +563,27 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge) {
RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge);
RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge);
}

void Manifold::Impl::SplitPinchedVerts() {
std::vector<bool> vertProcessed(NumVert(), false);
std::vector<bool> halfedgeProcessed(halfedge_.size(), false);
for (int i = 0; i < halfedge_.size(); ++i) {
if (halfedgeProcessed[i]) continue;
int vert = halfedge_[i].startVert;
if (vertProcessed[vert]) {
vertPos_.push_back(vertPos_[vert]);
vert = NumVert() - 1;
} else {
vertProcessed[vert] = true;
}
int current = i;
do {
halfedgeProcessed[current] = true;
halfedge_[current].startVert = vert;
current = halfedge_[current].pairedHalfedge;
halfedge_[current].endVert = vert;
current = NextHalfedge(current);
} while (current != i);
}
}
} // namespace manifold
28 changes: 24 additions & 4 deletions src/manifold/src/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
namespace {
using namespace manifold;

constexpr uint64_t kRemove = std::numeric_limits<uint64_t>::max();

__host__ __device__ void AtomicAddVec3(glm::vec3& target,
const glm::vec3& add) {
for (int i : {0, 1, 2}) {
Expand Down Expand Up @@ -488,10 +490,25 @@ Manifold::Impl::Impl(const MeshGL& meshGL,
Manifold::Impl::Impl(const Mesh& mesh, const MeshRelationD& relation,
const std::vector<float>& propertyTolerance,
bool hasFaceIDs)
: vertPos_(mesh.vertPos),
halfedgeTangent_(mesh.halfedgeTangent),
meshRelation_(relation) {
VecDH<glm::ivec3> triVerts = mesh.triVerts;
: vertPos_(mesh.vertPos), halfedgeTangent_(mesh.halfedgeTangent) {
meshRelation_ = {relation.originalID, relation.numProp, relation.properties,
relation.meshIDtransform};

VecDH<glm::ivec3> triVerts;
for (int i = 0; i < mesh.triVerts.size(); ++i) {
const glm::ivec3 tri = mesh.triVerts[i];
// Remove topological degenerates
if (tri[0] != tri[1] && tri[1] != tri[2] && tri[2] != tri[0]) {
triVerts.push_back(tri);
if (relation.triRef.size() > 0) {
meshRelation_.triRef.push_back(relation.triRef[i]);
}
if (relation.triProperties.size() > 0) {
meshRelation_.triProperties.push_back(relation.triProperties[i]);
}
}
}

if (!IsIndexInBounds(triVerts)) {
MarkFailure(Error::VertexOutOfBounds);
return;
Expand All @@ -510,6 +527,9 @@ Manifold::Impl::Impl(const Mesh& mesh, const MeshRelationD& relation,
MarkFailure(Error::NotManifold);
return;
}

SplitPinchedVerts();

CalculateNormals();

InitializeOriginal();
Expand Down
5 changes: 3 additions & 2 deletions src/manifold/src/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ struct Manifold::Impl {
/// The originalID of this Manifold if it is an original; -1 otherwise.
int originalID = -1;
int numProp = 0;
VecDH<TriRef> triRef;
VecDH<glm::ivec3> triProperties;
VecDH<float> properties;
std::map<int, Relation> meshIDtransform;
VecDH<TriRef> triRef;
VecDH<glm::ivec3> triProperties;
};

Box bBox_;
Expand Down Expand Up @@ -127,6 +127,7 @@ struct Manifold::Impl {
void UpdateVert(int vert, int startEdge, int endEdge);
void FormLoop(int current, int end);
void CollapseTri(const glm::ivec3& triEdge);
void SplitPinchedVerts();

// smoothing.cu
void CreateTangents(const std::vector<Smoothness>&);
Expand Down
5 changes: 2 additions & 3 deletions src/manifold/src/properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,8 @@ struct CheckHalfedges {

__host__ __device__ bool operator()(int edge) {
const Halfedge halfedge = halfedges[edge];
if (halfedge.startVert == -1 && halfedge.endVert == -1 &&
halfedge.pairedHalfedge == -1)
return true;
if (halfedge.startVert == -1 && halfedge.endVert == -1) return true;
if (halfedge.pairedHalfedge == -1) return false;

const Halfedge paired = halfedges[halfedge.pairedHalfedge];
bool good = true;
Expand Down
50 changes: 50 additions & 0 deletions test/manifold_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -662,3 +662,53 @@ TEST(Manifold, MultiCompose) {
part.Mirror({1, 0, 0}).Translate({10, 10, 0})});
EXPECT_FLOAT_EQ(finalAssembly.GetProperties().volume, 4000);
}

TEST(Manifold, MergeDegenerates) {
MeshGL cube = Manifold::Cube(glm::vec3(1), true).GetMeshGL();
MeshGL squash;
squash.vertProperties = cube.vertProperties;
squash.triVerts = cube.triVerts;
// Move one vert to the position of its neighbor and remove one triangle
// linking them to break the manifold.
squash.vertProperties[squash.vertProperties.size() - 1] *= -1;
squash.triVerts.resize(squash.triVerts.size() - 3);
// Rotate the degenerate triangle to the middle to catch more problems.
std::rotate(squash.triVerts.begin(), squash.triVerts.begin() + 3 * 5,
squash.triVerts.end());
// Merge should remove the now duplicate vertex.
EXPECT_TRUE(squash.Merge());
// Manifold should remove the triangle with two references to the same vert.
Manifold squashed = Manifold(squash);
EXPECT_FALSE(squashed.IsEmpty());
EXPECT_EQ(squashed.Status(), Manifold::Error::NoError);
}

TEST(Manifold, PinchedVert) {
Mesh shape;
shape.vertPos = {{0, 0, 0}, //
{1, 1, 0}, //
{1, -1, 0}, //
{-0.00001, 0, 0}, //
{-1, -1, -0}, //
{-1, 1, 0}, //
{0, 0, 2}, //
{0, 0, -2}};
shape.triVerts = {{0, 2, 6}, //
{2, 1, 6}, //
{1, 0, 6}, //
{4, 3, 6}, //
{3, 5, 6}, //
{5, 4, 6}, //
{2, 0, 4}, //
{0, 3, 4}, //
{3, 0, 1}, //
{3, 1, 5}, //
{7, 2, 4}, //
{7, 4, 5}, //
{7, 5, 1}, //
{7, 1, 2}};
Manifold touch(shape);
EXPECT_FALSE(touch.IsEmpty());
EXPECT_EQ(touch.Status(), Manifold::Error::NoError);
EXPECT_EQ(touch.Genus(), 0);
}

0 comments on commit 96c57c0

Please sign in to comment.