fix: 3MF multi-object parsing — flush per object
This commit is contained in:
+31
-55
@@ -328,14 +328,33 @@ static std::vector<ThreeMFMesh> parse_model_xml(const std::string& xml) {
|
||||
std::istringstream iss(xml);
|
||||
std::string line;
|
||||
|
||||
// Parse all <object> blocks in the XML
|
||||
// Per-object state
|
||||
std::vector<std::array<double, 3>> verts;
|
||||
std::vector<std::array<int, 3>> tris;
|
||||
bool in_vertices = false, in_triangles = false;
|
||||
std::string object_name;
|
||||
|
||||
auto add_current_object = [&]() {
|
||||
if (verts.empty()) return;
|
||||
std::vector<mesh::Point3D> pts;
|
||||
pts.reserve(verts.size());
|
||||
for (const auto& v : verts) pts.emplace_back(v[0], v[1], v[2]);
|
||||
std::vector<std::array<int, 3>> faces;
|
||||
for (const auto& t : tris) {
|
||||
if (t[0]>=0 && (size_t)t[0]<verts.size()
|
||||
&& t[1]>=0 && (size_t)t[1]<verts.size()
|
||||
&& t[2]>=0 && (size_t)t[2]<verts.size())
|
||||
faces.push_back(t);
|
||||
}
|
||||
ThreeMFMesh m;
|
||||
m.mesh.build_from_triangles(pts, faces);
|
||||
m.name = object_name;
|
||||
results.push_back(std::move(m));
|
||||
verts.clear();
|
||||
tris.clear();
|
||||
};
|
||||
|
||||
while (std::getline(iss, line)) {
|
||||
// Trim whitespace
|
||||
size_t start = 0;
|
||||
while (start < line.size() && (line[start] == ' ' || line[start] == '\t' || line[start] == '\r'))
|
||||
++start;
|
||||
@@ -344,79 +363,36 @@ static std::vector<ThreeMFMesh> parse_model_xml(const std::string& xml) {
|
||||
if (!line.empty() && line.back() == '\r') line.pop_back();
|
||||
}
|
||||
|
||||
// New object: flush previous
|
||||
if (line.find("<object ") != std::string::npos) {
|
||||
add_current_object();
|
||||
object_name = xml_get_attr(line, "name");
|
||||
}
|
||||
|
||||
if (line.find("<vertices>") != std::string::npos) {
|
||||
in_vertices = true;
|
||||
continue;
|
||||
}
|
||||
if (line.find("</vertices>") != std::string::npos) {
|
||||
in_vertices = false;
|
||||
continue;
|
||||
}
|
||||
if (line.find("<triangles>") != std::string::npos) {
|
||||
in_triangles = true;
|
||||
continue;
|
||||
}
|
||||
if (line.find("</triangles>") != std::string::npos) {
|
||||
in_triangles = false;
|
||||
continue;
|
||||
}
|
||||
if (line.find("<vertices>") != std::string::npos) { in_vertices = true; continue; }
|
||||
if (line.find("</vertices>") != std::string::npos) { in_vertices = false; continue; }
|
||||
if (line.find("<triangles>") != std::string::npos) { in_triangles = true; continue; }
|
||||
if (line.find("</triangles>") != std::string::npos) { in_triangles = false; continue; }
|
||||
|
||||
if (in_vertices && line.find("<vertex ") != std::string::npos) {
|
||||
auto xs = xml_get_attr(line, "x");
|
||||
auto ys = xml_get_attr(line, "y");
|
||||
auto zs = xml_get_attr(line, "z");
|
||||
if (!xs.empty() && !ys.empty() && !zs.empty()) {
|
||||
if (!xs.empty() && !ys.empty() && !zs.empty())
|
||||
verts.push_back({std::stod(xs), std::stod(ys), std::stod(zs)});
|
||||
}
|
||||
}
|
||||
|
||||
if (in_triangles && line.find("<triangle ") != std::string::npos) {
|
||||
auto v1s = xml_get_attr(line, "v1");
|
||||
auto v2s = xml_get_attr(line, "v2");
|
||||
auto v3s = xml_get_attr(line, "v3");
|
||||
if (!v1s.empty() && !v2s.empty() && !v3s.empty()) {
|
||||
if (!v1s.empty() && !v2s.empty() && !v3s.empty())
|
||||
tris.push_back({std::stoi(v1s), std::stoi(v2s), std::stoi(v3s)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build mesh
|
||||
std::vector<mesh::Point3D> pts;
|
||||
pts.reserve(verts.size());
|
||||
for (const auto& v : verts) {
|
||||
pts.emplace_back(v[0], v[1], v[2]);
|
||||
}
|
||||
|
||||
std::vector<std::array<int, 3>> faces;
|
||||
faces.reserve(tris.size());
|
||||
for (const auto& t : tris) {
|
||||
// Validate indices
|
||||
if (t[0] >= 0 && static_cast<size_t>(t[0]) < verts.size() &&
|
||||
t[1] >= 0 && static_cast<size_t>(t[1]) < verts.size() &&
|
||||
t[2] >= 0 && static_cast<size_t>(t[2]) < verts.size()) {
|
||||
faces.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
ThreeMFMesh m;
|
||||
m.mesh.build_from_triangles(pts, faces);
|
||||
m.name = object_name;
|
||||
results.push_back(m);
|
||||
|
||||
// Reset for next object
|
||||
verts.clear();
|
||||
tris.clear();
|
||||
object_name.clear();
|
||||
pts.clear();
|
||||
faces.clear();
|
||||
|
||||
// Re-parse for next objects? No, the function ends here.
|
||||
// Actually this only works for the first object.
|
||||
// For multi-object, need to detect <object> boundaries
|
||||
// Flush final object
|
||||
add_current_object();
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user