mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-05 06:41:10 +00:00
* Add Missing Includes Across src/libslic3r Every libslic3r source and header now directly includes the headers declaring what it uses, rather than relying on the precompiled header or transitive includes. Generated with clang-tidy misc-include-cleaner, with libslic3r headers spelled libslic3r/... so they resolve outside the library's private include paths. MultiMaterialSegmentation.hpp, Support/SupportParameters.hpp and Format/STEP.hpp are made self-contained by hand. * Make the libslic3r Headers Compile on Their Own Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Left out: I18N.hpp, which errors on purpose when included from GUI code, and VoxelizeCSGMesh.hpp and SLA/bicubic.h, which nothing includes and which no longer compile at all. * Add the Includes Missing From the Hand-Fixed libslic3r Headers clang-tidy would not edit these headers while they failed to compile on their own, so the first pass skipped them. With the headers now self-contained, a second pass adds the rest. * Keep Windows Setup Ahead of the Added libslic3r Includes Print.cpp and Thread.cpp open with a _WIN32 block that has to come first; without the precompiled header, Print.cpp otherwise reaches windows.h through OCCT with NONLS defined and boost/regex fails. OpenVDBUtils.cpp and SLA/SupportTreeBuilder.cpp had includes inside #ifndef NOMINMAX, which libslic3r defines on Windows, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory. * Re-Add libslic3r Includes After the Clipper2 2.0.1 Migration Rebasing onto main took main's version of the files the Clipper2 migration rewrote, so their added includes are restored here, along with includes for main's new code. Clipper2's individual headers are now ignored by clang-tidy: they only build the Z variant through clipper2_z.hpp, which defines USINGZ first, so including clipper.core.h and the like directly broke ClipperZUtils.cpp.
782 lines
30 KiB
C++
782 lines
30 KiB
C++
#include "../libslic3r.h"
|
|
#include "../Model.hpp"
|
|
#include "../TriangleMesh.hpp"
|
|
#include "libslic3r/Exception.hpp"
|
|
#include "libslic3r/Utils.hpp"
|
|
#include "libslic3r/Point.hpp"
|
|
#include "libslic3r/Thread.hpp"
|
|
|
|
#include "STEP.hpp"
|
|
|
|
#include <boost/filesystem/path.hpp>
|
|
#include <ios>
|
|
#include <ostream>
|
|
#include <cstddef>
|
|
#include <Standard_Handle.hxx>
|
|
#include <Standard_TypeDef.hxx>
|
|
#include <TopAbs_ShapeEnum.hxx>
|
|
#include <atomic>
|
|
#include <IFSelect_ReturnStatus.hxx>
|
|
#include <boost/chrono/duration.hpp>
|
|
#include <cstring>
|
|
#include <Poly_Triangulation.hxx>
|
|
#include <cstdint>
|
|
#include <gp_Trsf.hxx>
|
|
#include <gp_Pnt.hxx>
|
|
#include <TopAbs_Orientation.hxx>
|
|
#include <Poly_Triangle.hxx>
|
|
#include <string>
|
|
#include <boost/nowide/cstdio.hpp>
|
|
#include <boost/nowide/iostream.hpp>
|
|
#include <boost/nowide/fstream.hpp>
|
|
|
|
#include <tbb/blocked_range.h>
|
|
#include <tbb/parallel_for.h>
|
|
#include <vector>
|
|
#include <utility>
|
|
|
|
#ifdef _WIN32
|
|
#define DIR_SEPARATOR '\\'
|
|
#else
|
|
#define DIR_SEPARATOR '/'
|
|
#endif
|
|
|
|
#include "STEPCAFControl_Reader.hxx"
|
|
#include "BRepMesh_IncrementalMesh.hxx"
|
|
#include "Interface_Static.hxx"
|
|
#include "XCAFDoc_DocumentTool.hxx"
|
|
#include "XCAFDoc_ShapeTool.hxx"
|
|
#include "XCAFApp_Application.hxx"
|
|
#include "TDF_LabelSequence.hxx"
|
|
#include "TopoDS_Solid.hxx"
|
|
#include "TopoDS_Compound.hxx"
|
|
#include "TopoDS_Builder.hxx"
|
|
#include "TopoDS.hxx"
|
|
#include "TDataStd_Name.hxx"
|
|
#include "BRepBuilderAPI_Transform.hxx"
|
|
#include "TopExp_Explorer.hxx"
|
|
#include "TopExp_Explorer.hxx"
|
|
#include "BRep_Tool.hxx"
|
|
#include "BRepTools.hxx"
|
|
#include <IMeshTools_Parameters.hxx>
|
|
|
|
|
|
namespace Slic3r {
|
|
|
|
bool StepPreProcessor::preprocess(const char* path, std::string &output_path)
|
|
{
|
|
boost::nowide::ifstream infile(path);
|
|
if (!infile.good()) {
|
|
throw Slic3r::RuntimeError(std::string("Load step file failed.\nCannot open file for reading.\n"));
|
|
return false;
|
|
}
|
|
|
|
boost::filesystem::path temp_path(temporary_dir());
|
|
std::string temp_step_path = temp_path.string() + "/temp.step";
|
|
boost::nowide::remove(temp_step_path.c_str());
|
|
boost::nowide::ofstream temp_file(temp_step_path, std::ios::app);
|
|
std::string temp_line;
|
|
while (std::getline(infile, temp_line)) {
|
|
if (m_encode_type == EncodedType::UTF8) {
|
|
//BBS: continue to judge whether is other type
|
|
if (isUtf8(temp_line)) {
|
|
//BBS: do nothing, but must be checked before checking whether is GBK
|
|
}
|
|
//BBS: not utf8, then maybe GBK
|
|
else if (isGBK(temp_line)) {
|
|
m_encode_type = EncodedType::GBK;
|
|
}
|
|
//BBS: not UTF8 and not GBK, then maybe some kind of special encoded type which we can't handle
|
|
// Load the step as UTF and user will see garbage characters in slicer but we have no solution at the moment
|
|
else {
|
|
m_encode_type = EncodedType::OTHER;
|
|
}
|
|
}
|
|
if (m_encode_type == EncodedType::GBK)
|
|
//BBS: transform to UTF8 format if is GBK
|
|
//todo: use gbkToUtf8 function to replace
|
|
temp_file << decode_path(temp_line.c_str()) << std::endl;
|
|
else
|
|
temp_file << temp_line.c_str() << std::endl;
|
|
}
|
|
temp_file.close();
|
|
infile.close();
|
|
if (m_encode_type == EncodedType::GBK) {
|
|
output_path = temp_step_path;
|
|
} else {
|
|
boost::nowide::remove(temp_step_path.c_str());
|
|
output_path = std::string(path);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool StepPreProcessor::isUtf8File(const char* path)
|
|
{
|
|
boost::nowide::ifstream infile(path);
|
|
if (!infile.good()) {
|
|
throw Slic3r::RuntimeError(std::string("Load step file failed.\nCannot open file for reading.\n"));
|
|
return false;
|
|
}
|
|
|
|
std::string temp_line;
|
|
while (std::getline(infile, temp_line)) {
|
|
if (!isUtf8(temp_line)) {
|
|
infile.close();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
infile.close();
|
|
return true;
|
|
}
|
|
|
|
bool StepPreProcessor::isUtf8(const std::string str)
|
|
{
|
|
size_t num = 0;
|
|
size_t i = 0;
|
|
while (i < str.length()) {
|
|
const unsigned char lead = static_cast<unsigned char>(str[i]);
|
|
if ((lead & 0x80) == 0x00) {
|
|
i++;
|
|
// preNum() counts the leading 1 bits, and a multi-byte sequence is 2 to 4
|
|
// bytes long, so anything outside that range is not a lead byte.
|
|
} else if ((num = preNum(lead)) >= 2 && num <= 4) {
|
|
if (i + num > str.length())
|
|
return false;
|
|
i++;
|
|
for (size_t j = 0; j < num - 1; j++) {
|
|
if ((static_cast<unsigned char>(str[i]) & 0xc0) != 0x80)
|
|
return false;
|
|
i++;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool StepPreProcessor::isGBK(const std::string str) {
|
|
size_t i = 0;
|
|
while (i < str.length()) {
|
|
// char is signed here, so every byte compares <= 0x7f unless widened first.
|
|
const unsigned char lead = static_cast<unsigned char>(str[i]);
|
|
if (lead <= 0x7f) {
|
|
i++;
|
|
continue;
|
|
} else {
|
|
if (i + 1 >= str.length())
|
|
return false;
|
|
const unsigned char trail = static_cast<unsigned char>(str[i + 1]);
|
|
if (lead >= 0x81 &&
|
|
lead <= 0xfe &&
|
|
trail >= 0x40 &&
|
|
trail <= 0xfe &&
|
|
trail != 0xf7) {
|
|
i += 2;
|
|
continue;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int StepPreProcessor::preNum(const unsigned char byte) {
|
|
unsigned char mask = 0x80;
|
|
int num = 0;
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((byte & mask) == mask) {
|
|
mask = mask >> 1;
|
|
num++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
static void getNamedSolids(const TopLoc_Location& location,
|
|
const std::string& prefix,
|
|
unsigned int& id,
|
|
const Handle(XCAFDoc_ShapeTool) shapeTool,
|
|
const TDF_Label label,
|
|
std::vector<NamedSolid>& namedSolids,
|
|
bool isSplitCompound = false) {
|
|
TDF_Label referredLabel{label};
|
|
if (shapeTool->IsReference(label))
|
|
shapeTool->GetReferredShape(label, referredLabel);
|
|
|
|
std::string name;
|
|
Handle(TDataStd_Name) shapeName;
|
|
if (referredLabel.FindAttribute(TDataStd_Name::GetID(), shapeName) ||
|
|
label.FindAttribute(TDataStd_Name::GetID(), shapeName))
|
|
name = TCollection_AsciiString(shapeName->Get()).ToCString();
|
|
|
|
if (name == "" || !StepPreProcessor::isUtf8(name))
|
|
name = std::to_string(id++);
|
|
std::string fullName{name};
|
|
|
|
TopLoc_Location localLocation = location * shapeTool->GetLocation(label);
|
|
TDF_LabelSequence components;
|
|
if (shapeTool->GetComponents(referredLabel, components)) {
|
|
for (Standard_Integer compIndex = 1; compIndex <= components.Length(); ++compIndex) {
|
|
getNamedSolids(localLocation, fullName, id, shapeTool, components.Value(compIndex), namedSolids, isSplitCompound);
|
|
}
|
|
} else {
|
|
TopoDS_Shape shape;
|
|
TopExp_Explorer explorer;
|
|
shapeTool->GetShape(referredLabel, shape);
|
|
TopAbs_ShapeEnum shape_type = shape.ShapeType();
|
|
BRepBuilderAPI_Transform transform(shape, localLocation, Standard_True);
|
|
int i = 0;
|
|
switch (shape_type) {
|
|
case TopAbs_COMPOUND:
|
|
if (!isSplitCompound) {
|
|
namedSolids.emplace_back(TopoDS::Compound(transform.Shape()), fullName);
|
|
break;
|
|
}
|
|
case TopAbs_COMPSOLID:
|
|
if (!isSplitCompound) {
|
|
namedSolids.emplace_back(TopoDS::CompSolid(transform.Shape()), fullName);
|
|
} else {
|
|
for (explorer.Init(transform.Shape(), TopAbs_SOLID); explorer.More(); explorer.Next()) {
|
|
i++;
|
|
const TopoDS_Shape& currentShape = explorer.Current();
|
|
namedSolids.emplace_back(TopoDS::Solid(currentShape), fullName + "-SOLID-" + std::to_string(i));
|
|
}
|
|
}
|
|
break;
|
|
case TopAbs_SOLID:
|
|
namedSolids.emplace_back(TopoDS::Solid(transform.Shape()), fullName);
|
|
break;
|
|
case TopAbs_SHELL:
|
|
namedSolids.emplace_back(TopoDS::Shell(transform.Shape()), fullName);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//bool load_step(const char *path, Model *model, bool& is_cancel,
|
|
// double linear_deflection/*=0.003*/,
|
|
// double angle_deflection/*= 0.5*/,
|
|
// bool isSplitCompound,
|
|
// 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_deflection, false, angle_deflection, 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;
|
|
int progress = 0;
|
|
bool load_result = false;
|
|
auto task = new boost::thread(Slic3r::create_thread([&]() -> void {
|
|
|
|
STEPCAFControl_Reader reader;
|
|
reader.SetNameMode(true);
|
|
IFSelect_ReturnStatus stat = reader.ReadFile(m_path.c_str());
|
|
if (cb_cancel) return;
|
|
progress = 3;
|
|
if (stat != IFSelect_RetDone || !reader.Transfer(m_doc, incdicator->Start())) {
|
|
load_result = false;
|
|
task_result = true;
|
|
return;
|
|
}
|
|
if (cb_cancel) return;
|
|
progress = 6;
|
|
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) {
|
|
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_deflection/*=0.003*/,
|
|
double angle_deflection/*= 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 };
|
|
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
|
|
|
|
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
|
|
progress = static_cast<double>(iLabel) / (topShapeLength-1);
|
|
if (cb_cancel) {
|
|
return;
|
|
}
|
|
getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, 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_deflection, false, angle_deflection, 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(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();
|
|
}
|
|
meshed_solid_num.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
});
|
|
|
|
|
|
for (size_t i = 0; i < stl.size(); i++) {
|
|
progress_2 = static_cast<float>(i) / stl.size();
|
|
if (cb_cancel)
|
|
return;
|
|
|
|
//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 = m_path.c_str();
|
|
new_volume->source.object_idx = (int)model->objects.size() - 1;
|
|
new_volume->source.volume_idx = (int)new_object->volumes.size() - 1;
|
|
}
|
|
}
|
|
task_result = true;
|
|
}));
|
|
|
|
while (!task_result) {
|
|
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
|
|
if (new_object->volumes.size() == 0) {
|
|
model->delete_object(new_object);
|
|
return Step_Status::MESH_ERROR;
|
|
}
|
|
return Step_Status::MESH_SUCCESS;
|
|
}
|
|
|
|
void Step::clean_mesh_data()
|
|
{
|
|
for (const auto& name_solid : m_name_solids) {
|
|
BRepTools::Clean(name_solid.solid);
|
|
}
|
|
}
|
|
|
|
unsigned int Step::get_triangle_num(double linear_deflection, double angle_deflection)
|
|
{
|
|
unsigned int tri_num = 0;
|
|
try {
|
|
Handle(StepProgressIncdicator) progress = new StepProgressIncdicator(m_stop_mesh);
|
|
clean_mesh_data();
|
|
IMeshTools_Parameters param;
|
|
param.Deflection = linear_deflection;
|
|
param.Angle = angle_deflection;
|
|
param.InParallel = true;
|
|
for (int i = 0; i < m_name_solids.size(); ++i) {
|
|
BRepMesh_IncrementalMesh mesh(m_name_solids[i].solid, param, progress->Start());
|
|
for (TopExp_Explorer anExpSF(m_name_solids[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()) {
|
|
tri_num += aTriangulation->NbTriangles();
|
|
}
|
|
}
|
|
if (m_stop_mesh.load()) {
|
|
return 0;
|
|
}
|
|
}
|
|
} catch(const Exception &) {
|
|
return 0;
|
|
}
|
|
|
|
return tri_num;
|
|
}
|
|
|
|
unsigned int Step::get_triangle_num_tbb(double linear_deflection, double angle_deflection)
|
|
{
|
|
unsigned int tri_num = 0;
|
|
clean_mesh_data();
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, m_name_solids.size()),
|
|
[&](const tbb::blocked_range<size_t>& range) {
|
|
for (size_t i = range.begin(); i < range.end(); i++) {
|
|
unsigned int solids_tri_num = 0;
|
|
BRepMesh_IncrementalMesh mesh(m_name_solids[i].solid, linear_deflection, false, angle_deflection, true);
|
|
for (TopExp_Explorer anExpSF(m_name_solids[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()) {
|
|
solids_tri_num += aTriangulation->NbTriangles();
|
|
}
|
|
}
|
|
m_name_solids[i].tri_face_cout = solids_tri_num;
|
|
}
|
|
|
|
});
|
|
for (int i = 0; i < m_name_solids.size(); ++i) {
|
|
tri_num += m_name_solids[i].tri_face_cout;
|
|
}
|
|
return tri_num;
|
|
}
|
|
|
|
}; // namespace Slic3r
|