Warn if exporting a non-watertight mesh.

If a generated mesh is non-watertight, and this is not noticed for
some reason (e.g. the markers are dismissed), and the mesh is
exported for further processing, it could cause problems down
the line.
pull/109/head
Evil-Spirit 2016-11-14 22:16:50 +07:00 committed by whitequark
parent 3b241392d4
commit fdd08cbead
3 changed files with 37 additions and 29 deletions

View File

@ -812,7 +812,7 @@ void SolveSpaceUI::ExportMeshTo(const std::string &filename) {
Error("Couldn't write to '%s'", filename.c_str()); Error("Couldn't write to '%s'", filename.c_str());
return; return;
} }
ShowNakedEdges(/*reportOnlyWhenNotOkay=*/true);
if(FilenameHasExtension(filename, ".stl")) { if(FilenameHasExtension(filename, ".stl")) {
ExportMeshAsStlTo(f, m); ExportMeshAsStlTo(f, m);
} else if(FilenameHasExtension(filename, ".obj")) { } else if(FilenameHasExtension(filename, ".obj")) {

View File

@ -596,34 +596,7 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
break; break;
case Command::NAKED_EDGES: { case Command::NAKED_EDGES: {
SS.nakedEdges.Clear(); ShowNakedEdges(/*reportOnlyWhenNotOkay=*/false);
Group *g = SK.GetGroup(SS.GW.activeGroup);
SMesh *m = &(g->displayMesh);
SKdNode *root = SKdNode::From(m);
bool inters, leaks;
root->MakeCertainEdgesInto(&(SS.nakedEdges),
EdgeKind::NAKED_OR_SELF_INTER, /*coplanarIsInter=*/true, &inters, &leaks);
InvalidateGraphics();
const char *intersMsg = inters ?
"The mesh is self-intersecting (NOT okay, invalid)." :
"The mesh is not self-intersecting (okay, valid).";
const char *leaksMsg = leaks ?
"The mesh has naked edges (NOT okay, invalid)." :
"The mesh is watertight (okay, valid).";
std::string cntMsg = ssprintf("\n\nThe model contains %d triangles, from "
"%d surfaces.", g->displayMesh.l.n, g->runningShell.surface.n);
if(SS.nakedEdges.l.n == 0) {
Message("%s\n\n%s\n\nZero problematic edges, good.%s",
intersMsg, leaksMsg, cntMsg.c_str());
} else {
Error("%s\n\n%s\n\n%d problematic edges, bad.%s",
intersMsg, leaksMsg, SS.nakedEdges.l.n, cntMsg.c_str());
}
break; break;
} }
@ -811,6 +784,40 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
} }
} }
void SolveSpaceUI::ShowNakedEdges(bool reportOnlyWhenNotOkay) {
SS.nakedEdges.Clear();
Group *g = SK.GetGroup(SS.GW.activeGroup);
SMesh *m = &(g->displayMesh);
SKdNode *root = SKdNode::From(m);
bool inters, leaks;
root->MakeCertainEdgesInto(&(SS.nakedEdges),
EdgeKind::NAKED_OR_SELF_INTER, /*coplanarIsInter=*/true, &inters, &leaks);
if(reportOnlyWhenNotOkay && !inters && !leaks && SS.nakedEdges.l.n == 0) {
return;
}
InvalidateGraphics();
const char *intersMsg = inters ?
"The mesh is self-intersecting (NOT okay, invalid)." :
"The mesh is not self-intersecting (okay, valid).";
const char *leaksMsg = leaks ?
"The mesh has naked edges (NOT okay, invalid)." :
"The mesh is watertight (okay, valid).";
std::string cntMsg = ssprintf("\n\nThe model contains %d triangles, from "
"%d surfaces.", g->displayMesh.l.n, g->runningShell.surface.n);
if(SS.nakedEdges.l.n == 0) {
Message("%s\n\n%s\n\nZero problematic edges, good.%s",
intersMsg, leaksMsg, cntMsg.c_str());
} else {
Error("%s\n\n%s\n\n%d problematic edges, bad.%s",
intersMsg, leaksMsg, SS.nakedEdges.l.n, cntMsg.c_str());
}
}
void SolveSpaceUI::MenuHelp(Command id) { void SolveSpaceUI::MenuHelp(Command id) {
switch(id) { switch(id) {
case Command::WEBSITE: case Command::WEBSITE:

View File

@ -881,6 +881,7 @@ public:
bool PruneGroups(hGroup hg); bool PruneGroups(hGroup hg);
bool PruneRequests(hGroup hg); bool PruneRequests(hGroup hg);
bool PruneConstraints(hGroup hg); bool PruneConstraints(hGroup hg);
static void ShowNakedEdges(bool reportOnlyWhenNotOkay);
enum class Generate : uint32_t { enum class Generate : uint32_t {
DIRTY, DIRTY,