-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preventing crash with self intersection #501
Conversation
I think the relative path should be |
It will fail with the README build instruction for example( |
To make the test pass, you can add manifold::PolygonParams().processOverlaps = true; before your test case, and set it back to false afterwards. |
Thanks! |
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #501 +/- ##
==========================================
+ Coverage 90.34% 90.36% +0.01%
==========================================
Files 35 35
Lines 4414 4431 +17
==========================================
+ Hits 3988 4004 +16
- Misses 426 427 +1
☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
src/manifold/src/edge_op.cpp
Outdated
@@ -222,9 +222,10 @@ void Manifold::Impl::SimplifyTopology() { | |||
precision_}; | |||
for_each_n(policy, countAt(0), nbEdges, | |||
[=] __host__ __device__(int i) { bflagsPtr[i] = se(i); }); | |||
std::vector<uint32_t> visited(halfedge_.size(), -1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting a uint to -1 feels a little awkward...
src/manifold/src/edge_op.cpp
Outdated
VecDH<TriRef>& triRef = meshRelation_.triRef; | ||
|
||
if (edge < 0) return; | ||
const int pair = halfedge_[edge].pairedHalfedge; | ||
if (pair < 0) return; | ||
if (visited[edge] == pair) return; | ||
visited[edge] = pair; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be safer to mark these as booleans and set both the [edge]
and [pair]
to visited?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will likely output more degenerate tris, but I’ll try.
Otherwise maybe tagging visited[pair] = edge
.
Ultimately, slight changes in the logic gives different result for the ‘Sponge4’ test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not super worried about the variations in Sponge4 - really I need to come back to it and figure out why it has so many in the first place - I had managed to get rid of most of them at one time.
Curious what you find here - I need to look into this logic more deeply at some point. It's been awhile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a way to get the same number of degenerate Tris as master, while avoiding recursion.
Instead of booleans I use tag that I reset when there is a CollapseEdge
.
Alternative version: (maybe a bit more robust, to avoid skipping valid cases)
Using a stack and hash pair of edges instead of checking both edges separately
diff --git a/src/manifold/src/edge_op.cpp b/src/manifold/src/edge_op.cpp
index 26fd983..e1c2e73 100644
--- a/src/manifold/src/edge_op.cpp
+++ b/src/manifold/src/edge_op.cpp
@@ -222,12 +222,11 @@ void Manifold::Impl::SimplifyTopology() {
precision_};
for_each_n(policy, countAt(0), nbEdges,
[=] __host__ __device__(int i) { bflagsPtr[i] = se(i); });
- std::vector<int> visited(halfedge_.size(), -1);
- int tag = 0;
+ std::vector<glm::ivec2> visited(halfedge_.size(), glm::ivec2(-1));
for (int i = 0; i < nbEdges; ++i) {
if (bflags[i]) {
- tag++;
- RecursiveEdgeSwap(i, visited, tag);
+ visited.resize(0);
+ RecursiveEdgeSwap(i, visited);
numFlagged++;
}
}
@@ -487,7 +486,7 @@ void Manifold::Impl::CollapseEdge(const int edge) {
}
void Manifold::Impl::RecursiveEdgeSwap(const int edge,
- std::vector<int>& visited, int& tag) {
+ std::vector<glm::ivec2>& visited) {
VecDH<TriRef>& triRef = meshRelation_.triRef;
if (edge < 0) return;
@@ -495,7 +494,9 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge,
if (pair < 0) return;
// avoid infinite recursion
- if (visited[edge] == tag && visited[pair] == tag) return;
+ for (int i = 0; i < visited.size(); ++i) {
+ if (visited[i] == glm::ivec2(edge, pair)) return;
+ }
const glm::ivec3 tri0edge = TriOf(edge);
const glm::ivec3 tri1edge = TriOf(pair);
@@ -575,15 +576,14 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge,
SwapEdge();
const glm::vec2 e23 = v[3] - v[2];
if (glm::dot(e23, e23) < precision_ * precision_) {
- tag++;
+ visited.resize(0);
CollapseEdge(tri0edge[2]);
} else {
- visited[edge] = tag;
- visited[pair] = tag;
- RecursiveEdgeSwap(tri0edge[0], visited, tag);
- RecursiveEdgeSwap(tri0edge[1], visited, tag);
- RecursiveEdgeSwap(tri1edge[0], visited, tag);
- RecursiveEdgeSwap(tri1edge[1], visited, tag);
+ visited.emplace_back(glm::ivec2(edge, pair));
+ RecursiveEdgeSwap(tri0edge[0], visited);
+ RecursiveEdgeSwap(tri0edge[1], visited);
+ RecursiveEdgeSwap(tri1edge[0], visited);
+ RecursiveEdgeSwap(tri1edge[1], visited);
}
return;
} else if (CCW(v[0], v[3], v[2], precision_) <= 0 ||
@@ -592,10 +592,9 @@ void Manifold::Impl::RecursiveEdgeSwap(const int edge,
}
// Normal path
SwapEdge();
- visited[edge] = tag;
- visited[pair] = tag;
- RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge, visited, tag);
- RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge, visited, tag);
+ visited.emplace_back(glm::ivec2(edge, pair));
+ RecursiveEdgeSwap(halfedge_[tri0edge[1]].pairedHalfedge, visited);
+ RecursiveEdgeSwap(halfedge_[tri1edge[0]].pairedHalfedge, visited);
}
void Manifold::Impl::SplitPinchedVerts() {
diff --git a/src/manifold/src/impl.h b/src/manifold/src/impl.h
index dc4f57b..cb890df 100644
--- a/src/manifold/src/impl.h
+++ b/src/manifold/src/impl.h
@@ -121,7 +121,7 @@ struct Manifold::Impl {
void SimplifyTopology();
void DedupeEdge(int edge);
void CollapseEdge(int edge);
- void RecursiveEdgeSwap(int edge, std::vector<int>& visited, int& tag);
+ void RecursiveEdgeSwap(int edge, std::vector<glm::ivec2>& visited);
void RemoveIfFolded(int edge);
void PairUp(int edge0, int edge1);
void UpdateVert(int vert, int startEdge, int endEdge);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I tend to prefer to simpler version you have now, though I don't quite grok the difference. If you want, it's probably best to put this as a follow-on PR and add a test that shows the difference.
test/samples_test.cpp
Outdated
manifold::PolygonParams().processOverlaps = true; | ||
std::string file = __FILE__; | ||
std::string dir = file.substr(0, file.rfind('/')); | ||
Manifold m1 = ImportMesh(dir + "/../samples/models/self_intersectA.glb"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a chance these are simple enough they can be generated by e.g. an Extrude and Warp? Still, there is value in being able to add test models - this may be nice as a helper function. I think I'd prefer to put them in a dedicated models directory in test
rather than samples
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably not, it’s a bit sensitive and I couldn’t replicate when I tried with other self intersected tubes,
Maybe if you managed to output the exact same sweep but probably lot of trial & error, and I’m lazy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, no prob - but let's at least change the directory.
da8bbc4
to
7c3730b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice solution, thanks!
* Prevent infinite recursion * Add test for self intersection
Issue: #495
The code snippet in the issue makes
Samples.Sponge4
fails:If I change the logic a bit the test passes and it doesn't crash on my example, but
ImportMesh
to test the crash scenario but not sure relative path is the way to go for the test