ENH:loading the step in boost thread

github: #6079
Change-Id: I0a289fc9730e7d091a71137cf11a711dfee5392f
(cherry picked from commit b454e7d8bb91b62b3be6121c567f7aee291eff50)
This commit is contained in:
Mack 2025-03-25 11:28:07 +08:00 committed by lane.wei
parent cf63988a45
commit b7ffba39e4
3 changed files with 466 additions and 216 deletions

View File

@ -1,6 +1,7 @@
#include "../libslic3r.h" #include "../libslic3r.h"
#include "../Model.hpp" #include "../Model.hpp"
#include "../TriangleMesh.hpp" #include "../TriangleMesh.hpp"
#include "libslic3r/Thread.hpp"
#include "STEP.hpp" #include "STEP.hpp"
@ -225,59 +226,315 @@ static void getNamedSolids(const TopLoc_Location& location,
} }
} }
bool load_step(const char *path, Model *model, bool& is_cancel, //bool load_step(const char *path, Model *model, bool& is_cancel,
double linear_defletion/*=0.003*/, // double linear_defletion/*=0.003*/,
double angle_defletion/*= 0.5*/, // double angle_defletion/*= 0.5*/,
bool isSplitCompound, // bool isSplitCompound,
ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn, long& mesh_face_num) // ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn, long& mesh_face_num)
//{
// bool cb_cancel = false;
// if (stepFn) {
// stepFn(LOAD_STEP_STAGE_READ_FILE, 0, 1, cb_cancel);
// is_cancel = cb_cancel;
// if (cb_cancel) {
// return false;
// }
// }
//
// if (!StepPreProcessor::isUtf8File(path) && isUtf8Fn)
// isUtf8Fn(false);
// std::string file_after_preprocess = std::string(path);
//
// std::vector<NamedSolid> namedSolids;
// Handle(TDocStd_Document) document;
// Handle(XCAFApp_Application) application = XCAFApp_Application::GetApplication();
// application->NewDocument(file_after_preprocess.c_str(), document);
// STEPCAFControl_Reader reader;
// reader.SetNameMode(true);
// //BBS: Todo, read file is slow which cause the progress_bar no update and gui no response
// IFSelect_ReturnStatus stat = reader.ReadFile(file_after_preprocess.c_str());
// if (stat != IFSelect_RetDone || !reader.Transfer(document)) {
// application->Close(document);
// throw std::logic_error{ std::string{"Could not read '"} + path + "'" };
// return false;
// }
// Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(document->Main());
// TDF_LabelSequence topLevelShapes;
// shapeTool->GetFreeShapes(topLevelShapes);
//
// unsigned int id{1};
// Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
// auto stage_unit2 = topShapeLength / LOAD_STEP_STAGE_UNIT_NUM + 1;
//
// for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
// if (stepFn) {
// if ((iLabel % stage_unit2) == 0) {
// stepFn(LOAD_STEP_STAGE_GET_SOLID, iLabel, topShapeLength, cb_cancel);
// is_cancel = cb_cancel;
// }
// if (cb_cancel) {
// shapeTool.reset(nullptr);
// application->Close(document);
// return false;
// }
// }
// getNamedSolids(TopLoc_Location{}, "", id, shapeTool, topLevelShapes.Value(iLabel), namedSolids, isSplitCompound);
// }
//
// std::vector<stl_file> stl;
// stl.resize(namedSolids.size());
// tbb::parallel_for(tbb::blocked_range<size_t>(0, namedSolids.size()), [&](const tbb::blocked_range<size_t> &range) {
// for (size_t i = range.begin(); i < range.end(); i++) {
// BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, linear_defletion, false, angle_defletion, true);
// // BBS: calculate total number of the nodes and triangles
// int aNbNodes = 0;
// int aNbTriangles = 0;
// for (TopExp_Explorer anExpSF(namedSolids[i].solid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
// TopLoc_Location aLoc;
// Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(TopoDS::Face(anExpSF.Current()), aLoc);
// if (!aTriangulation.IsNull()) {
// aNbNodes += aTriangulation->NbNodes();
// aNbTriangles += aTriangulation->NbTriangles();
// }
// }
//
// if (aNbTriangles == 0 || aNbNodes == 0)
// // BBS: No triangulation on the shape.
// continue;
//
// stl[i].stats.type = inmemory;
// stl[i].stats.number_of_facets = (uint32_t) aNbTriangles;
// stl[i].stats.original_num_facets = stl[i].stats.number_of_facets;
// stl_allocate(&stl[i]);
//
// std::vector<Vec3f> points;
// points.reserve(aNbNodes);
// // BBS: count faces missing triangulation
// Standard_Integer aNbFacesNoTri = 0;
// // BBS: fill temporary triangulation
// Standard_Integer aNodeOffset = 0;
// Standard_Integer aTriangleOffet = 0;
// for (TopExp_Explorer anExpSF(namedSolids[i].solid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
// const TopoDS_Shape &aFace = anExpSF.Current();
// TopLoc_Location aLoc;
// Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(TopoDS::Face(aFace), aLoc);
// if (aTriangulation.IsNull()) {
// ++aNbFacesNoTri;
// continue;
// }
// // BBS: copy nodes
// gp_Trsf aTrsf = aLoc.Transformation();
// for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
// gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
// aPnt.Transform(aTrsf);
// points.emplace_back(std::move(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z())));
// }
// // BBS: copy triangles
// const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
// Standard_Integer anId[3] = {};
// for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
// Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
//
// aTri.Get(anId[0], anId[1], anId[2]);
// if (anOrientation == TopAbs_REVERSED)
// std::swap(anId[1], anId[2]);
// // BBS: save triangles facets
// stl_facet facet;
// facet.vertex[0] = points[anId[0] + aNodeOffset - 1].cast<float>();
// facet.vertex[1] = points[anId[1] + aNodeOffset - 1].cast<float>();
// facet.vertex[2] = points[anId[2] + aNodeOffset - 1].cast<float>();
// facet.extra[0] = 0;
// facet.extra[1] = 0;
// stl_normal normal;
// stl_calculate_normal(normal, &facet);
// stl_normalize_vector(normal);
// facet.normal = normal;
// stl[i].facet_start[aTriangleOffet + aTriIter - 1] = facet;
// }
//
// aNodeOffset += aTriangulation->NbNodes();
// aTriangleOffet += aTriangulation->NbTriangles();
// }
// }
// });
//
// if (mesh_face_num != -1) {
// for (size_t i = 0; i < stl.size(); i++) {
// // Test for overflow
// mesh_face_num += stl[i].stats.number_of_facets;
// }
// return true;
// }
//
// ModelObject *new_object = model->add_object();
// const char * last_slash = strrchr(path, DIR_SEPARATOR);
// new_object->name.assign((last_slash == nullptr) ? path : last_slash + 1);
// new_object->input_file = path;
//
// auto stage_unit3 = stl.size() / LOAD_STEP_STAGE_UNIT_NUM + 1;
// for (size_t i = 0; i < stl.size(); i++) {
// if (stepFn) {
// if ((i % stage_unit3) == 0) {
// stepFn(LOAD_STEP_STAGE_GET_MESH, i, stl.size(), cb_cancel);
// is_cancel = cb_cancel;
// }
// if (cb_cancel) {
// model->delete_object(new_object);
// shapeTool.reset(nullptr);
// application->Close(document);
// return false;
// }
// }
//
// //BBS: maybe mesh is empty from step file. Don't add
// if (stl[i].stats.number_of_facets > 0) {
// TriangleMesh triangle_mesh;
// triangle_mesh.from_stl(stl[i]);
// ModelVolume* new_volume = new_object->add_volume(std::move(triangle_mesh));
// new_volume->name = namedSolids[i].name;
// new_volume->source.input_file = path;
// new_volume->source.object_idx = (int)model->objects.size() - 1;
// new_volume->source.volume_idx = (int)new_object->volumes.size() - 1;
// }
// }
//
// shapeTool.reset(nullptr);
// application->Close(document);
//
// //BBS: no valid shape from the step, delete the new object as well
// if (new_object->volumes.size() == 0) {
// model->delete_object(new_object);
// return false;
// }
//
// return true;
//}
Step::Step(fs::path path, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn):
m_stepFn(stepFn),
m_utf8Fn(isUtf8Fn)
{ {
m_path = path.string();
m_app->NewDocument(TCollection_ExtendedString("BinXCAF"), m_doc);
}
Step::Step(std::string path, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn) :
m_path(path),
m_stepFn(stepFn),
m_utf8Fn(isUtf8Fn)
{
m_app->NewDocument(TCollection_ExtendedString("BinXCAF"), m_doc);
}
Step::~Step()
{
m_app->Close(m_doc);
}
void Step::update_process(int load_stage, int current, int total, bool& cancel)
{
if (m_stepFn) {
m_stepFn(load_stage, current, total, cancel);
}
}
Step::Step_Status Step::load()
{
if (!StepPreProcessor::isUtf8File(m_path.c_str()) && m_utf8Fn) {
m_utf8Fn(false);
return Step_Status::LOAD_ERROR;
}
std::atomic<bool> stop_load_flag = false;
Handle(StepProgressIncdicator) incdicator = new StepProgressIncdicator(stop_load_flag);
bool task_result = false;
bool cb_cancel = false; bool cb_cancel = false;
if (stepFn) { int progress = 0;
stepFn(LOAD_STEP_STAGE_READ_FILE, 0, 1, cb_cancel); bool load_result = false;
is_cancel = cb_cancel; auto task = new boost::thread(Slic3r::create_thread([&]() -> void {
if (cb_cancel) {
return false;
}
}
if (!StepPreProcessor::isUtf8File(path) && isUtf8Fn)
isUtf8Fn(false);
std::string file_after_preprocess = std::string(path);
std::vector<NamedSolid> namedSolids;
Handle(TDocStd_Document) document;
Handle(XCAFApp_Application) application = XCAFApp_Application::GetApplication();
application->NewDocument(file_after_preprocess.c_str(), document);
STEPCAFControl_Reader reader; STEPCAFControl_Reader reader;
reader.SetNameMode(true); reader.SetNameMode(true);
//BBS: Todo, read file is slow which cause the progress_bar no update and gui no response IFSelect_ReturnStatus stat = reader.ReadFile(m_path.c_str());
IFSelect_ReturnStatus stat = reader.ReadFile(file_after_preprocess.c_str()); if (cb_cancel) return;
if (stat != IFSelect_RetDone || !reader.Transfer(document)) { progress = 3;
application->Close(document); if (stat != IFSelect_RetDone || !reader.Transfer(m_doc, incdicator->Start())) {
throw std::logic_error{ std::string{"Could not read '"} + path + "'" }; load_result = false;
return false; task_result = true;
return;
} }
Handle(XCAFDoc_ShapeTool) shapeTool = XCAFDoc_DocumentTool::ShapeTool(document->Main()); if (cb_cancel) return;
progress = 6;
m_shape_tool = XCAFDoc_DocumentTool::ShapeTool(m_doc->Main());
TDF_LabelSequence topLevelShapes; TDF_LabelSequence topLevelShapes;
shapeTool->GetFreeShapes(topLevelShapes); m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
if (cb_cancel) return;
getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, topLevelShapes.Value(iLabel), m_name_solids);
}
progress = 10;
load_result = true;
task_result = true;
}));
while (!task_result) {
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
update_process(LOAD_STEP_STAGE_READ_FILE, progress, 10, cb_cancel);
if (cb_cancel) {
stop_load_flag.store(true);
if (task) {
if (task->joinable()) {
task->join();
delete task;
}
}
return Step_Status::CANCEL;
}
}
if (task){
if (task->joinable()) {
task->join();
delete task;
}
}
if (load_result) {
return Step_Status::LOAD_SUCCESS;
}else {
return Step_Status::LOAD_ERROR;
}
}
Step::Step_Status Step::mesh(Model* model,
bool& is_cancel,
bool isSplitCompound,
double linear_defletion/*=0.003*/,
double angle_defletion/*= 0.5*/)
{
bool task_result = false;
bool cb_cancel = false;
float progress = .0;
std::atomic<int> meshed_solid_num = 0;
std::vector<NamedSolid> namedSolids;
float progress_2 = .0;
ModelObject* new_object = model->add_object();
const char* last_slash = strrchr(m_path.c_str(), DIR_SEPARATOR);
new_object->name.assign((last_slash == nullptr) ? m_path.c_str() : last_slash + 1);
new_object->input_file = m_path.c_str();
auto task = new boost::thread(Slic3r::create_thread([&]() -> void {
TDF_LabelSequence topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 }; unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1; Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
auto stage_unit2 = topShapeLength / LOAD_STEP_STAGE_UNIT_NUM + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) { for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
if (stepFn) { progress = static_cast<double>(iLabel) / (topShapeLength-1);
if ((iLabel % stage_unit2) == 0) {
stepFn(LOAD_STEP_STAGE_GET_SOLID, iLabel, topShapeLength, cb_cancel);
is_cancel = cb_cancel;
}
if (cb_cancel) { if (cb_cancel) {
shapeTool.reset(nullptr); return;
application->Close(document);
return false;
} }
} getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, topLevelShapes.Value(iLabel), namedSolids, isSplitCompound);
getNamedSolids(TopLoc_Location{}, "", id, shapeTool, topLevelShapes.Value(iLabel), namedSolids, isSplitCompound);
} }
std::vector<stl_file> stl; std::vector<stl_file> stl;
@ -354,36 +611,15 @@ bool load_step(const char *path, Model *model, bool& is_cancel,
aNodeOffset += aTriangulation->NbNodes(); aNodeOffset += aTriangulation->NbNodes();
aTriangleOffet += aTriangulation->NbTriangles(); aTriangleOffet += aTriangulation->NbTriangles();
} }
meshed_solid_num.fetch_add(1, std::memory_order_relaxed);
} }
}); });
if (mesh_face_num != -1) {
for (size_t i = 0; i < stl.size(); i++) {
// Test for overflow
mesh_face_num += stl[i].stats.number_of_facets;
}
return true;
}
ModelObject *new_object = model->add_object();
const char * last_slash = strrchr(path, DIR_SEPARATOR);
new_object->name.assign((last_slash == nullptr) ? path : last_slash + 1);
new_object->input_file = path;
auto stage_unit3 = stl.size() / LOAD_STEP_STAGE_UNIT_NUM + 1;
for (size_t i = 0; i < stl.size(); i++) { for (size_t i = 0; i < stl.size(); i++) {
if (stepFn) { progress_2 = static_cast<float>(i) / stl.size();
if ((i % stage_unit3) == 0) { if (cb_cancel)
stepFn(LOAD_STEP_STAGE_GET_MESH, i, stl.size(), cb_cancel); return;
is_cancel = cb_cancel;
}
if (cb_cancel) {
model->delete_object(new_object);
shapeTool.reset(nullptr);
application->Close(document);
return false;
}
}
//BBS: maybe mesh is empty from step file. Don't add //BBS: maybe mesh is empty from step file. Don't add
if (stl[i].stats.number_of_facets > 0) { if (stl[i].stats.number_of_facets > 0) {
@ -391,64 +627,56 @@ bool load_step(const char *path, Model *model, bool& is_cancel,
triangle_mesh.from_stl(stl[i]); triangle_mesh.from_stl(stl[i]);
ModelVolume* new_volume = new_object->add_volume(std::move(triangle_mesh)); ModelVolume* new_volume = new_object->add_volume(std::move(triangle_mesh));
new_volume->name = namedSolids[i].name; new_volume->name = namedSolids[i].name;
new_volume->source.input_file = path; new_volume->source.input_file = m_path.c_str();
new_volume->source.object_idx = (int)model->objects.size() - 1; new_volume->source.object_idx = (int)model->objects.size() - 1;
new_volume->source.volume_idx = (int)new_object->volumes.size() - 1; new_volume->source.volume_idx = (int)new_object->volumes.size() - 1;
} }
} }
task_result = true;
}));
shapeTool.reset(nullptr); while (!task_result) {
application->Close(document); boost::this_thread::sleep_for(boost::chrono::milliseconds(300));
if (progress_2 > 0) {
// third progress
update_process(LOAD_STEP_STAGE_GET_MESH, static_cast<int>(progress_2 * 100), 100, cb_cancel);
}else {
if (meshed_solid_num.load()) {
// second progress
int meshed_solid = meshed_solid_num.load();
update_process(LOAD_STEP_STAGE_GET_SOLID, static_cast<int>((float)meshed_solid / namedSolids.size() * 10) + 10, 20, cb_cancel);
} else {
if (progress > 0) {
// first progress
update_process(LOAD_STEP_STAGE_GET_SOLID, static_cast<int>(progress * 10), 20, cb_cancel);
}
}
}
if (cb_cancel) {
if (task) {
if (task->joinable()) {
task->join();
delete task;
}
}
return Step_Status::CANCEL;
}
}
if (task) {
if (task->joinable()) {
task->join();
delete task;
}
}
//BBS: no valid shape from the step, delete the new object as well //BBS: no valid shape from the step, delete the new object as well
if (new_object->volumes.size() == 0) { if (new_object->volumes.size() == 0) {
model->delete_object(new_object); model->delete_object(new_object);
return false; return Step_Status::MESH_ERROR;
} }
return Step_Status::MESH_SUCCESS;
return true;
}
Step::Step(fs::path path, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn):
m_stepFn(stepFn),
m_utf8Fn(isUtf8Fn)
{
m_path = path.string();
m_app->NewDocument(TCollection_ExtendedString("BinXCAF"), m_doc);
}
Step::Step(std::string path, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn) :
m_path(path),
m_stepFn(stepFn),
m_utf8Fn(isUtf8Fn)
{
m_app->NewDocument(TCollection_ExtendedString("BinXCAF"), m_doc);
}
bool Step::load()
{
if (!StepPreProcessor::isUtf8File(m_path.c_str()) && m_utf8Fn) {
m_utf8Fn(false);
return false;
}
STEPCAFControl_Reader reader;
reader.SetNameMode(true);
IFSelect_ReturnStatus stat = reader.ReadFile(m_path.c_str());
if (stat != IFSelect_RetDone || !reader.Transfer(m_doc)) {
m_app->Close(m_doc);
return false;
}
m_shape_tool = XCAFDoc_DocumentTool::ShapeTool(m_doc->Main());
TDF_LabelSequence topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, topLevelShapes.Value(iLabel), m_name_solids);
}
return true;
} }
void Step::clean_mesh_data() void Step::clean_mesh_data()

View File

@ -88,14 +88,28 @@ private:
class Step class Step
{ {
public: public:
enum class Step_Status {
LOAD_SUCCESS,
LOAD_ERROR,
CANCEL,
MESH_SUCCESS,
MESH_ERROR
};
Step(fs::path path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr); Step(fs::path path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
Step(std::string path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr); Step(std::string path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
bool load(); ~Step();
Step_Status load();
unsigned int get_triangle_num(double linear_defletion, double angle_defletion); unsigned int get_triangle_num(double linear_defletion, double angle_defletion);
unsigned int get_triangle_num_tbb(double linear_defletion, double angle_defletion); unsigned int get_triangle_num_tbb(double linear_defletion, double angle_defletion);
void clean_mesh_data(); void clean_mesh_data();
Step_Status mesh(Model* model,
bool& is_cancel,
bool isSplitCompound,
double linear_defletion = 0.003,
double angle_defletion = 0.5);
std::atomic<bool> m_stop_mesh; std::atomic<bool> m_stop_mesh;
void update_process(int load_stage, int current, int total, bool& cancel);
private: private:
std::string m_path; std::string m_path;
ImportStepProgressFn m_stepFn; ImportStepProgressFn m_stepFn;

View File

@ -197,26 +197,34 @@ Model Model::read_from_step(const std::string&
Model model; Model model;
bool result = false; bool result = false;
bool is_cb_cancel = false; bool is_cb_cancel = false;
std::string message; Step::Step_Status status;
Step step_file(input_file); Step step_file(input_file, stepFn);
step_file.load(); status = step_file.load();
if(status != Step::Step_Status::LOAD_SUCCESS) {
goto _finished;
}
if (step_mesh_fn) { if (step_mesh_fn) {
if (step_mesh_fn(step_file, linear_defletion, angle_defletion, is_split_compound) == -1) { if (step_mesh_fn(step_file, linear_defletion, angle_defletion, is_split_compound) == -1) {
Model empty_model; status = Step::Step_Status::CANCEL;
return empty_model; goto _finished;
} }
} }
result = load_step(input_file.c_str(), &model, is_cb_cancel, linear_defletion, angle_defletion, is_split_compound, stepFn, stepIsUtf8Fn);
if (is_cb_cancel) {
Model empty_model;
return empty_model;
}
if (!result) { status = step_file.mesh(&model, is_cb_cancel, is_split_compound, linear_defletion, angle_defletion);
if (message.empty())
_finished:
switch (status){
case Step::Step_Status::CANCEL: {
Model empty_model;
return empty_model;
}
case Step::Step_Status::LOAD_ERROR:
throw Slic3r::RuntimeError(_L("Loading of a model file failed.")); throw Slic3r::RuntimeError(_L("Loading of a model file failed."));
else case Step::Step_Status::MESH_ERROR:
throw Slic3r::RuntimeError(message); throw Slic3r::RuntimeError(_L("Meshing of a model file failed or no valid shape."));
default:
break;
} }
if (model.objects.empty()) if (model.objects.empty())