mirror of
https://github.com/Nexoniarz/Fry3DX.git
synced 2026-11-03 04:24:26 +00:00
Combining: points the cutting leaves a hair apart are one, and needles along edges go — the example gear (and others like it) came out with an edge of three faces and a face with no size, so not ready to print; a test for it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e18c7f6bce
commit
5d3121b335
2 changed files with 55 additions and 1 deletions
|
|
@ -143,7 +143,14 @@ Mesh meshOf(const std::vector<Poly>& polys) {
|
|||
if (f.empty() || f.back() != i) f.push_back(i);
|
||||
}
|
||||
while (f.size() > 1 && f.front() == f.back()) f.pop_back();
|
||||
if (f.size() >= 3) m.faces.push_back(f);
|
||||
if (f.size() < 3) continue;
|
||||
// A sliver squashed flat by the sharing of points (all its corners on one line): it
|
||||
// would be a third face on an edge. Left out; its middle points are set into the
|
||||
// neighbours' edges below, so it stays closed all round.
|
||||
glm::vec3 area(0.0f);
|
||||
for (size_t i = 0; i < f.size(); ++i) area += glm::cross(m.verts[size_t(f[i])], m.verts[size_t(f[(i + 1) % f.size()])]);
|
||||
if (glm::length(area) < 2e-11f) continue; // (twice the area: about a square of 3 µm)
|
||||
m.faces.push_back(f);
|
||||
}
|
||||
// T-junctions: a point in the middle of an edge it isn't a corner of.
|
||||
std::vector<int> order(m.verts.size());
|
||||
|
|
@ -175,6 +182,30 @@ Mesh meshOf(const std::vector<Poly>& polys) {
|
|||
return m;
|
||||
}
|
||||
|
||||
// Faces that run out to a point and straight back (… a b a …): a needle along an edge, which
|
||||
// would put a third face on it. The needle goes; the face is the same without it.
|
||||
void removeSpikes(Mesh& m) {
|
||||
for (auto& f : m.faces)
|
||||
for (bool again = true; again && f.size() >= 3;) {
|
||||
again = false;
|
||||
for (size_t i = 0; i < f.size() && f.size() >= 3; ++i) {
|
||||
const size_t n = f.size(), next = (i + 1) % n, after = (i + 2) % n;
|
||||
if (f[i] == f[next]) { // (a point twice in a row)
|
||||
f.erase(f.begin() + long(next));
|
||||
again = true;
|
||||
break;
|
||||
}
|
||||
if (f[i] == f[after]) { // a b a: b, and one a, go
|
||||
const size_t lo = std::min(next, after), hi = std::max(next, after);
|
||||
f.erase(f.begin() + long(hi)), f.erase(f.begin() + long(lo));
|
||||
again = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::erase_if(m.faces, [](const std::vector<int>& f) { return f.size() < 3; });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool combine(Mesh& a, const Mesh& b, Combine op) {
|
||||
|
|
@ -200,7 +231,12 @@ bool combine(Mesh& a, const Mesh& b, Combine op) {
|
|||
std::vector<Poly> out;
|
||||
A.all(out);
|
||||
a = meshOf(out);
|
||||
// Points the cutting left a hair apart (closer than 0.03 mm: nothing a printer or a model
|
||||
// could show) are one; else they fold tiny faces back over their neighbours.
|
||||
mergeByDistance(a, 3e-5f);
|
||||
removeSpikes(a);
|
||||
mergeFlatFaces(a);
|
||||
removeSpikes(a);
|
||||
return !a.faces.empty();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -426,6 +426,24 @@ int main() {
|
|||
const std::string text((std::istreambuf_iterator<char>(j)), {});
|
||||
CHECK(text.find("\"translation\":[2,3,1]") != std::string::npos, "in glTF's axes (Y up): the position is [2,3,1]");
|
||||
|
||||
{ // A gear with a screw hole (scripts/gear.lua): cutting leaves points a hair apart and
|
||||
// needles along edges; what comes out must still print (closed, nothing without size).
|
||||
for (int teeth : {10, 16})
|
||||
for (int sides : {24, 32}) {
|
||||
std::vector<glm::vec3> o;
|
||||
const float radius = teeth == 16 ? 0.03f : 0.018f;
|
||||
for (int i = 0; i < teeth * 4; ++i) {
|
||||
const float a = float(i) / float(teeth * 4) * 6.2831853f, r = i % 4 < 2 ? radius + 0.004f : radius;
|
||||
o.push_back({std::cos(a) * r, std::sin(a) * r, 0});
|
||||
}
|
||||
Mesh g = extrudeOutline(o, {0, 0, 1}, 0.008f);
|
||||
transform(g, glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0.004f)));
|
||||
combine(g, makeCylinder(sides, 0.0027f, 0.03f), Combine::Subtract);
|
||||
const PrintCheck c = checkForPrint(g);
|
||||
CHECK(c.closed() && c.tinyFaces == 0 && closed(g), "a %d-tooth gear minus a %d-sided hole prints (open %d, crowded %d, flipped %d, tiny %d)", teeth, sides,
|
||||
c.openEdges, c.crowdedEdges, c.flippedEdges, c.tinyFaces);
|
||||
}
|
||||
}
|
||||
{ // Sculpting: a cube made finer keeps its shape; brushes move only what's under them.
|
||||
Mesh m = makeCube(1.0f);
|
||||
const int times = finerForSculpting(m, 2000);
|
||||
|
|
|
|||
Loading…
Reference in a new issue