update libslic3r

This commit is contained in:
QIDI TECH
2024-11-28 15:12:18 +08:00
parent 459e7822db
commit a26696f35e
115 changed files with 15117 additions and 4090 deletions

View File

@@ -8,6 +8,7 @@
#include <string>
#include <boost/log/trivial.hpp>
#include <boost/locale.hpp>
#ifdef _WIN32
#define DIR_SEPARATOR '\\'
@@ -33,6 +34,11 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
message = _L("load_obj: failed to parse");
return false;
}
obj_info.ml_region = data.ml_region;
obj_info.ml_name = data.ml_name;
obj_info.ml_id = data.ml_id;
bool exist_mtl = false;
if (data.mtllibs.size() > 0) { // read mtl
for (auto mtl_name : data.mtllibs) {
@@ -40,16 +46,20 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
continue;
}
exist_mtl = true;
bool mtl_name_is_path = false;
boost::filesystem::path mtl_abs_path(mtl_name);
bool mtl_name_is_path = false;
std::wstring wide_mtl_name = boost::locale::conv::to_utf<wchar_t>(mtl_name, "UTF-8");
if (boost::istarts_with(wide_mtl_name,"./")){
boost::replace_first(wide_mtl_name, "./", "");
}
boost::filesystem::path mtl_abs_path(wide_mtl_name);
if (boost::filesystem::exists(mtl_abs_path)) {
mtl_name_is_path = true;
}
boost::filesystem::path mtl_path;
if (!mtl_name_is_path) {
boost::filesystem::path full_path(path);
std::string dir = full_path.parent_path().string();
auto mtl_file = dir + "/" + mtl_name;
auto dir = full_path.parent_path().wstring();
auto mtl_file = dir + L"/" + wide_mtl_name;
boost::filesystem::path temp_mtl_path(mtl_file);
mtl_path = temp_mtl_path;
}

View File

@@ -1,13 +1,15 @@
#ifndef slic3r_Format_OBJ_hpp_
#define slic3r_Format_OBJ_hpp_
#include "libslic3r/Color.hpp"
#include "objparser.hpp"
#include <unordered_map>
namespace Slic3r {
class TriangleMesh;
class Model;
class ModelObject;
typedef std::function<void(std::vector<RGBA> &input_colors, bool is_single_color, std::vector<unsigned char> &filament_ids, unsigned char &first_extruder_id)> ObjImportColorFn;
typedef std::function<void(std::vector<RGBA> &input_colors, bool is_single_color, std::vector<unsigned char> &filament_ids, unsigned char &first_extruder_id,
std::string& ml_region, std::string& ml_name, std::string& ml_id)> ObjImportColorFn;
// Load an OBJ file into a provided model.
struct ObjInfo {
std::vector<RGBA> vertex_colors;
@@ -19,6 +21,9 @@ struct ObjInfo {
std::unordered_map<int, std::string> uv_map_pngs;
bool has_uv_png{false};
std::string ml_region;
std::string ml_name;
std::string ml_id;
};
extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_colors, std::string &message);
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr);

View File

@@ -33,9 +33,8 @@
#include "TopExp_Explorer.hxx"
#include "TopExp_Explorer.hxx"
#include "BRep_Tool.hxx"
const double STEP_TRANS_CHORD_ERROR = 0.003;
const double STEP_TRANS_ANGLE_RES = 0.5;
#include "BRepTools.hxx"
#include <IMeshTools_Parameters.hxx>
namespace Slic3r {
@@ -166,13 +165,6 @@ int StepPreProcessor::preNum(const unsigned char byte) {
return num;
}
struct NamedSolid {
NamedSolid(const TopoDS_Shape& s,
const std::string& n) : solid{s}, name{n} {}
const TopoDS_Shape solid;
const std::string name;
};
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) {
@@ -185,7 +177,7 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p
if (referredLabel.FindAttribute(TDataStd_Name::GetID(), shapeName))
name = TCollection_AsciiString(shapeName->Get()).ToCString();
if (name == "")
if (name == "" || !StepPreProcessor::isUtf8(name))
name = std::to_string(id++);
std::string fullName{name};
@@ -197,15 +189,19 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p
}
} 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:
namedSolids.emplace_back(TopoDS::Compound(transform.Shape()), fullName);
break;
case TopAbs_COMPSOLID:
namedSolids.emplace_back(TopoDS::CompSolid(transform.Shape()), fullName);
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);
@@ -216,7 +212,10 @@ static void getNamedSolids(const TopLoc_Location& location, const std::string& p
}
}
bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn)
bool load_step(const char *path, Model *model, bool& is_cancel,
double linear_defletion/*=0.003*/,
double angle_defletion/*= 0.5*/,
ImportStepProgressFn stepFn, StepIsUtf8Fn isUtf8Fn, long& mesh_face_num)
{
bool cb_cancel = false;
if (stepFn) {
@@ -271,7 +270,7 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
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, STEP_TRANS_CHORD_ERROR, false, STEP_TRANS_ANGLE_RES, true);
BRepMesh_IncrementalMesh mesh(namedSolids[i].solid, linear_defletion, false, angle_defletion, true);
// QDS: calculate total number of the nodes and triangles
int aNbNodes = 0;
int aNbTriangles = 0;
@@ -317,7 +316,7 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
}
// QDS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
Standard_Integer anId[3];
Standard_Integer anId[3] = {};
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
@@ -344,6 +343,14 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
}
});
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);
@@ -388,4 +395,104 @@ bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgre
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()
{
for (const auto& name_solid : m_name_solids) {
BRepTools::Clean(name_solid.solid);
}
}
unsigned int Step::get_triangle_num(double linear_defletion, double angle_defletion)
{
unsigned int tri_num = 0;
Handle(StepProgressIncdicator) progress = new StepProgressIncdicator(m_stop_mesh);
clean_mesh_data();
IMeshTools_Parameters param;
param.Deflection = linear_defletion;
param.Angle = angle_defletion;
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;
}
}
return tri_num;
}
unsigned int Step::get_triangle_num_tbb(double linear_defletion, double angle_defletion)
{
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_defletion, false, angle_defletion, 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

View File

@@ -1,8 +1,19 @@
#ifndef slic3r_Format_STEP_hpp_
#define slic3r_Format_STEP_hpp_
#include "XCAFDoc_DocumentTool.hxx"
#include "XCAFApp_Application.hxx"
#include "XCAFDoc_ShapeTool.hxx"
#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include <Message_ProgressIndicator.hxx>
#include <atomic>
namespace fs = boost::filesystem;
namespace Slic3r {
class Model;
class TriangleMesh;
class ModelObject;
@@ -16,8 +27,24 @@ const int LOAD_STEP_STAGE_UNIT_NUM = 5;
typedef std::function<void(int load_stage, int current, int total, bool& cancel)> ImportStepProgressFn;
typedef std::function<void(bool isUtf8)> StepIsUtf8Fn;
struct NamedSolid
{
NamedSolid(const TopoDS_Shape& s,
const std::string& n) : solid{ s }, name{ n } {
}
const TopoDS_Shape solid;
const std::string name;
int tri_face_cout = 0;
};
//QDS: Load an step file into a provided model.
extern bool load_step(const char *path, Model *model, bool& is_cancel, ImportStepProgressFn proFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
extern bool load_step(const char *path, Model *model,
bool& is_cancel,
double linear_defletion = 0.003,
double angle_defletion = 0.5,
ImportStepProgressFn proFn = nullptr,
StepIsUtf8Fn isUtf8Fn = nullptr,
long& mesh_face_num = *(new long(-1)));
//QDS: Used to detect what kind of encoded type is used in name field of step
// If is encoded in UTF8, the file don't need to be handled, then return the original path directly.
@@ -36,14 +63,50 @@ class StepPreProcessor {
public:
bool preprocess(const char* path, std::string &output_path);
static bool isUtf8File(const char* path);
private:
static bool isUtf8(const std::string str);
private:
static bool isGBK(const std::string str);
static int preNum(const unsigned char byte);
//QDS: default is UTF8 for most step file.
EncodedType m_encode_type = EncodedType::UTF8;
};
class StepProgressIncdicator : public Message_ProgressIndicator
{
public:
StepProgressIncdicator(std::atomic<bool>& stop_flag) : should_stop(stop_flag){}
Standard_Boolean UserBreak() override { return should_stop.load(); }
void Show(const Message_ProgressScope&, const Standard_Boolean) override {
std::cout << "Progress: " << GetPosition() << "%" << std::endl;
}
private:
std::atomic<bool>& should_stop;
};
class Step
{
public:
Step(fs::path path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
Step(std::string path, ImportStepProgressFn stepFn = nullptr, StepIsUtf8Fn isUtf8Fn = nullptr);
bool load();
unsigned int get_triangle_num(double linear_defletion, double angle_defletion);
unsigned int get_triangle_num_tbb(double linear_defletion, double angle_defletion);
void clean_mesh_data();
std::atomic<bool> m_stop_mesh;
private:
std::string m_path;
ImportStepProgressFn m_stepFn;
StepIsUtf8Fn m_utf8Fn;
Handle(XCAFApp_Application) m_app = XCAFApp_Application::GetApplication();
Handle(TDocStd_Document) m_doc;
Handle(XCAFDoc_ShapeTool) m_shape_tool;
std::vector<NamedSolid> m_name_solids;
};
}; // namespace Slic3r
#endif /* slic3r_Format_STEP_hpp_ */

View File

@@ -577,6 +577,8 @@ bool objparse(const char *path, ObjData &data)
char buf[65536 * 2];
size_t len = 0;
size_t lenPrev = 0;
size_t lineCount = 0;
while ((len = ::fread(buf + lenPrev, 1, 65536, pFile)) != 0) {
len += lenPrev;
size_t lastLine = 0;
@@ -589,6 +591,13 @@ bool objparse(const char *path, ObjData &data)
//FIXME check the return value and exit on error?
// Will it break parsing of some obj files?
obj_parseline(c, data);
/*for ml*/
if (lineCount == 0) { data.ml_region = parsemlinfo(c, "region:");}
if (lineCount == 1) { data.ml_name = parsemlinfo(c, "ml_name:"); }
if (lineCount == 2) { data.ml_id = parsemlinfo(c, "ml_file_id:");}
++lineCount;
lastLine = i + 1;
}
lenPrev = len - lastLine;
@@ -607,6 +616,27 @@ bool objparse(const char *path, ObjData &data)
return true;
}
std::string parsemlinfo(const char* input, const char* condition) {
const char* regionPtr = std::strstr(input, condition);
std::string regionContent = "";
if (regionPtr != nullptr) {
regionPtr += std::strlen(condition);
while (*regionPtr == ' ' || *regionPtr == '\t') {
++regionPtr;
}
const char* endPtr = std::strchr(regionPtr, '\n');
size_t length = (endPtr != nullptr) ? (endPtr - regionPtr) : std::strlen(regionPtr);
regionContent = std::string(regionPtr, length);
}
return regionContent;
}
bool mtlparse(const char *path, MtlData &data)
{
Slic3r::CNumericLocalesSetter locales_setter;
@@ -664,6 +694,14 @@ bool objparse(std::istream &stream, ObjData &data)
while (*c == ' ' || *c == '\t')
++ c;
obj_parseline(c, data);
/*for ml*/
if (lastLine < 3) {
data.ml_region = parsemlinfo(c, "region");
data.ml_name = parsemlinfo(c, "ml_name");
data.ml_id = parsemlinfo(c, "ml_file_id");
}
lastLine = i + 1;
}
lenPrev = len - lastLine;

View File

@@ -115,6 +115,10 @@ struct ObjData {
// List of faces, delimited by an ObjVertex with all members set to -1.
std::vector<ObjVertex> vertices;
std::string ml_region;
std::string ml_name;
std::string ml_id;
};
struct MtlData
@@ -127,6 +131,8 @@ extern bool objparse(const char *path, ObjData &data);
extern bool mtlparse(const char *path, MtlData &data);
extern bool objparse(std::istream &stream, ObjData &data);
extern std::string parsemlinfo(const char* input, const char* condition);
extern bool objbinsave(const char *path, const ObjData &data);
extern bool objbinload(const char *path, ObjData &data);

View File

@@ -18,6 +18,8 @@
#include <stdexcept>
#include <iomanip>
#include <boost/assign.hpp>
#include <boost/bimap.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/predicate.hpp>
@@ -46,6 +48,11 @@ namespace pt = boost::property_tree;
#include <Eigen/Dense>
#include "miniz_extension.hpp"
#include "nlohmann/json.hpp"
#include "EmbossShape.hpp"
#include "ExPolygonSerialize.hpp"
#include "NSVGUtils.hpp"
#include <fast_float/fast_float.h>
// Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
@@ -130,6 +137,9 @@ const std::string QDT_APPLICATION_TAG = "Application";
const std::string QDT_MAKERLAB_TAG = "MakerLab";
const std::string QDT_MAKERLAB_VERSION_TAG = "MakerLabVersion";
const std::string QDT_MAKERLAB_NAME = "MakerLab";
const std::string QDT_MAKERLAB_REGION = "MakerLabRegion";
const std::string QDT_MAKERLAB_ID = "MakerLabFileId";
const std::string QDT_PROFILE_TITLE_TAG = "ProfileTitle";
const std::string QDT_PROFILE_COVER_TAG = "ProfileCover";
@@ -163,6 +173,7 @@ const std::string QDS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.co
const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config";
const std::string QDS_LAYER_HEIGHTS_PROFILE_FILE = "Metadata/layer_heights_profile.txt";
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/layer_config_ranges.xml";
const std::string BRIM_EAR_POINTS_FILE = "Metadata/brim_ear_points.txt";
/*const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";*/
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/custom_gcode_per_layer.xml";
@@ -332,6 +343,40 @@ static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed";
static constexpr const char* MESH_STAT_FACETS_RESERVED = "facets_reversed";
static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges";
// Store / load of TextConfiguration
static constexpr const char *TEXT_DATA_ATTR = "text";
// TextConfiguration::EmbossStyle
static constexpr const char *STYLE_NAME_ATTR = "style_name";
static constexpr const char *FONT_DESCRIPTOR_ATTR = "font_descriptor";
static constexpr const char *FONT_DESCRIPTOR_TYPE_ATTR = "font_descriptor_type";
// TextConfiguration::FontProperty
static constexpr const char *CHAR_GAP_ATTR = "char_gap";
static constexpr const char *LINE_GAP_ATTR = "line_gap";
static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
static constexpr const char *BOLDNESS_ATTR = "boldness";
static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *PER_GLYPH_ATTR = "per_glyph";
static constexpr const char *HORIZONTAL_ALIGN_ATTR = "horizontal";
static constexpr const char *VERTICAL_ALIGN_ATTR = "vertical";
static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
static constexpr const char *FONT_FAMILY_ATTR = "family";
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
static constexpr const char *FONT_STYLE_ATTR = "style";
static constexpr const char *FONT_WEIGHT_ATTR = "weight";
// Store / load of EmbossShape
static constexpr const char *SHAPE_TAG = "slic3rpe:shape";
static constexpr const char *SHAPE_SCALE_ATTR = "scale";
static constexpr const char *UNHEALED_ATTR = "unhealed";
static constexpr const char *SVG_FILE_PATH_ATTR = "filepath";
static constexpr const char *SVG_FILE_PATH_IN_3MF_ATTR = "filepath3mf";
// EmbossProjection
static constexpr const char *DEPTH_ATTR = "depth";
static constexpr const char *USE_SURFACE_ATTR = "use_surface";
// static constexpr const char *FIX_TRANSFORMATION_ATTR = "transform";
const unsigned int QDS_VALID_OBJECT_TYPES_COUNT = 2;
const char* QDS_VALID_OBJECT_TYPES[] =
@@ -719,7 +764,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
RepairedMeshErrors mesh_stats;
ModelVolumeType part_type;
TextInfo text_info;
std::optional<EmbossShape> shape_configuration;
VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id, ModelVolumeType type = ModelVolumeType::MODEL_PART)
: first_triangle_id(first_triangle_id)
, last_triangle_id(last_triangle_id)
@@ -770,8 +815,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
//typedef std::map<Id, Geometry> IdToGeometryMap;
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
typedef std::map<int, BrimPoints> IdToBrimPointsMap;
/*typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;*/
using PathToEmbossShapeFileMap = std::map<std::string, std::shared_ptr<std::string>>;
struct ObjectImporter
{
@@ -836,7 +883,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool extract_object_model()
{
mz_zip_archive archive;
mz_zip_archive_file_stat stat;
//mz_zip_archive_file_stat stat;
mz_zip_zero_struct(&archive);
if (!open_zip_reader(&archive, zip_path)) {
@@ -964,8 +1011,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
IdToCutObjectInfoMap m_cut_object_infos;
IdToLayerHeightsProfileMap m_layer_heights_profiles;
IdToLayerConfigRangesMap m_layer_config_ranges;
IdToBrimPointsMap m_brim_ear_points;
/*IdToSlaSupportPointsMap m_sla_support_points;
IdToSlaDrainHolesMap m_sla_drain_holes;*/
PathToEmbossShapeFileMap m_path_to_emboss_shape_files;
std::string m_curr_metadata_name;
std::string m_curr_characters;
std::string m_name;
@@ -1019,6 +1068,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
// add backup & restore logic
bool _load_model_from_file(std::string filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Import3mfProgressFn proFn = nullptr,
QDTProject* project = nullptr, int plate_id = 0);
bool _is_svg_shape_file(const std::string &filename) const;
bool _extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)>, bool restore = false);
bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
@@ -1028,6 +1078,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_brim_ear_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
@@ -1039,6 +1090,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
void _extract_auxiliary_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
void _extract_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat);
// handlers to parse the .model file
void _handle_start_model_xml_element(const char* name, const char** attributes);
@@ -1094,6 +1146,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _handle_start_metadata(const char** attributes, unsigned int num_attributes);
bool _handle_end_metadata();
bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes);
bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
void _apply_transform(ModelInstance& instance, const Transform3d& transform);
@@ -1225,6 +1279,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
m_objects_metadata.clear();
m_layer_heights_profiles.clear();
m_layer_config_ranges.clear();
m_brim_ear_points.clear();
//m_sla_support_points.clear();
m_curr_metadata_name.clear();
m_curr_characters.clear();
@@ -1720,6 +1775,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
// extract slic3r layer config ranges file
_extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
}
else if (boost::algorithm::iequals(name, BRIM_EAR_POINTS_FILE)) {
// extract slic3r config file
_extract_brim_ear_points_from_archive(archive, stat);
}
//QDS: disable SLA related files currently
/*else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE)) {
// extract sla support points file
@@ -1769,6 +1828,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
add_error("Archive does not contain a valid model config");
return false;
}
} else if (_is_svg_shape_file(name)) {
_extract_embossed_svg_shape_file(name, archive, stat);
}
else if (!dont_load_config && boost::algorithm::iequals(name, SLICE_INFO_CONFIG_FILE)) {
m_parsing_slice_info = true;
@@ -1900,6 +1961,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (obj_layer_config_ranges != m_layer_config_ranges.end())
model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second);
IdToBrimPointsMap::iterator obj_brim_points = m_brim_ear_points.find(object.second + 1);
if (obj_brim_points != m_brim_ear_points.end())
model_object->brim_points = std::move(obj_brim_points->second);
// m_sla_support_points are indexed by a 1 based model object index.
/*IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
@@ -2167,6 +2232,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _QDS_3MF_Importer::_is_svg_shape_file(const std::string &name) const {
return boost::starts_with(name, MODEL_FOLDER) && boost::ends_with(name, ".svg");
}
bool _QDS_3MF_Importer::_extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)> extract, bool restore)
{
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
@@ -2710,6 +2779,78 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
}
}
void _QDS_3MF_Importer::_extract_brim_ear_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
if (stat.m_uncomp_size > 0) {
std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) {
add_error("Error while reading brim ear points data to buffer");
return;
}
if (buffer.back() == '\n')
buffer.pop_back();
std::vector<std::string> objects;
boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
// Info on format versioning - see qds_3mf.hpp
int version = 0;
std::string key("brim_points_format_version=");
if (!objects.empty() && objects[0].find(key) != std::string::npos) {
objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
version = std::stoi(objects[0]);
objects.erase(objects.begin()); // pop the header
}
for (const std::string& object : objects) {
std::vector<std::string> object_data;
boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
if (object_data.size() != 2) {
add_error("Error while reading object data");
continue;
}
std::vector<std::string> object_data_id;
boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
if (object_data_id.size() != 2) {
add_error("Error while reading object id");
continue;
}
int object_id = std::atoi(object_data_id[1].c_str());
if (object_id == 0) {
add_error("Found invalid object id");
continue;
}
IdToBrimPointsMap::iterator object_item = m_brim_ear_points.find(object_id);
if (object_item != m_brim_ear_points.end()) {
add_error("Found duplicated brim ear points");
continue;
}
std::vector<std::string> object_data_points;
boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
std::vector<BrimPoint> brim_ear_points;
if (version == 0) {
for (unsigned int i=0; i<object_data_points.size(); i+=4)
brim_ear_points.emplace_back(float(std::atof(object_data_points[i+0].c_str())),
float(std::atof(object_data_points[i+1].c_str())),
float(std::atof(object_data_points[i+2].c_str())),
float(std::atof(object_data_points[i+3].c_str())));
}
if (!brim_ear_points.empty())
m_brim_ear_points.insert({ object_id, brim_ear_points });
}
}
}
/*
void _QDS_3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
@@ -2878,6 +3019,30 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
}*/
void _QDS_3MF_Importer::_extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
{
assert(m_path_to_emboss_shape_files.find(filename) == m_path_to_emboss_shape_files.end());
auto file = std::make_unique<std::string>(stat.m_uncomp_size, '\0');
mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void *) file->data(), stat.m_uncomp_size, 0);
if (res == 0) {
add_error("Error while reading svg shape for emboss");
return;
}
// store for case svg is loaded before volume
m_path_to_emboss_shape_files[filename] = std::move(file);
// find embossed volume, for case svg is loaded after volume
for (const ModelObject *object : m_model->objects)
for (ModelVolume *volume : object->volumes) {
std::optional<EmbossShape> &es = volume->emboss_shape;
if (!es.has_value()) continue;
std::optional<EmbossShape::SvgFile> &svg = es->svg_file;
if (!svg.has_value()) continue;
if (filename.compare(svg->path_in_3mf) == 0) svg->file_data = m_path_to_emboss_shape_files[filename];
}
}
void _QDS_3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
{
//QDS: add plate tree related logic
@@ -3088,7 +3253,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
res = _handle_start_assemble_item(attributes, num_attributes);
else if (::strcmp(TEXT_INFO_TAG, name) == 0)
res = _handle_start_text_info_item(attributes, num_attributes);
else if (::strcmp(SHAPE_TAG, name) == 0)
res = _handle_start_shape_configuration(attributes, num_attributes);
if (!res)
_stop_xml_parser();
}
@@ -3641,6 +3807,40 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
// Definition of read/write method for EmbossShape
static void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive);
static std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes);
bool _QDS_3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes)
{
IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
if (object == m_objects_metadata.end()) {
add_error("Can not assign volume mesh to a valid object");
return false;
}
auto &volumes = object->second.volumes;
if (volumes.empty()) {
add_error("Can not assign mesh to a valid volume");
return false;
}
ObjectMetadata::VolumeMetadata &volume = volumes.back();
volume.shape_configuration = read_emboss_shape(attributes, num_attributes);
if (!volume.shape_configuration.has_value()) return false;
// Fill svg file content into shape_configuration
std::optional<EmbossShape::SvgFile> &svg = volume.shape_configuration->svg_file;
if (!svg.has_value()) return true; // do not contain svg file
const std::string &path = svg->path_in_3mf;
if (path.empty()) return true; // do not contain svg file
auto it = m_path_to_emboss_shape_files.find(path);
if (it == m_path_to_emboss_shape_files.end()) return true; // svg file is not loaded yet
svg->file_data = it->second;
return true;
}
bool _QDS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
{
static const unsigned int MAX_RECURSIONS = 10;
@@ -4205,7 +4405,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
ObjectMetadata::VolumeMetadata &volume = object->second.volumes[m_curr_config.volume_id];
TextInfo text_info;
text_info.m_text = xml_unescape(qds_get_attribute_value_string(attributes, num_attributes, TEXT_ATTR));
text_info.m_font_name = qds_get_attribute_value_string(attributes, num_attributes, FONT_NAME_ATTR);
@@ -4293,9 +4492,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
} else if (boost::starts_with(type, "http://schemas.openxmlformats.org/") && boost::ends_with(type, "thumbnail")) {
if (boost::algorithm::ends_with(path, ".png"))
m_thumbnail_path = path;
} else if (boost::starts_with(type, "http://schemas.qidilab.com/") && boost::ends_with(type, "cover-thumbnail-middle")) {
} else if (boost::starts_with(type, "http://schemas.qiditech.com/") && boost::ends_with(type, "cover-thumbnail-middle")) {
m_thumbnail_middle = path;
} else if (boost::starts_with(type, "http://schemas.qidilab.com/") && boost::ends_with(type, "cover-thumbnail-small")) {
} else if (boost::starts_with(type, "http://schemas.qiditech.com/") && boost::ends_with(type, "cover-thumbnail-small")) {
m_thumbnail_small = path;
}
return true;
@@ -4510,7 +4709,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
}
volume->set_type(volume_data->part_type);
if (auto &es = volume_data->shape_configuration; es.has_value())
volume->emboss_shape = std::move(es);
if (!volume_data->text_info.m_text.empty())
volume->set_text_info(volume_data->text_info);
@@ -5279,7 +5479,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool save_model_to_file(StoreParams& store_params);
// add backup logic
bool save_object_mesh(const std::string& temp_path, ModelObject const & object, int obj_id);
static void add_transformation(std::stringstream &stream, const Transform3d &tr);
private:
//QDS: add plate data related logic
bool _save_model_to_file(const std::string& filename,
@@ -5317,6 +5517,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const;
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_brim_ear_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
@@ -5725,6 +5926,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return false;
}
if (!_add_brim_ear_points_file_to_archive(archive, model)) {
close_zip_writer(&archive);
return false;
}
// QDS progress point
/*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_SUPPORT\n");
if (proFn) {
@@ -6076,18 +6282,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (data._3mf_printer_thumbnail_middle.empty()) {
stream << " <Relationship Target=\"/Metadata/plate_1.png"
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
}
if (data._3mf_printer_thumbnail_small.empty()) {
stream << "<Relationship Target=\"/Metadata/plate_1_small.png"
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
}
}
else {
@@ -6098,11 +6304,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
thumbnail_file_str = (boost::format("Metadata/plate_%1%_small.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
}
}
else if (targets.empty()) {
@@ -6182,7 +6388,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::stringstream stream;
reset_stream(stream);
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:QIDIStudio=\"http://schemas.qidilab.com/package/2021\"";
stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:QIDIStudio=\"http://schemas.qiditech.com/package/2021\"";
if (m_production_ext)
stream << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\"";
stream << ">\n";
@@ -6259,6 +6465,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
metadata_item_map[QDT_MAKERLAB_VERSION_TAG] = xml_escape(model.mk_version);
BOOST_LOG_TRIVIAL(info) << "saved mk_version " << model.mk_version;
}
/*for ml*/
if (model.mk_name.empty() && !model.makerlab_name.empty()) {
metadata_item_map[QDT_MAKERLAB_NAME] = model.makerlab_name;
metadata_item_map[QDT_MAKERLAB_REGION] = model.makerlab_region;
metadata_item_map[QDT_MAKERLAB_ID] = model.makerlab_id;
}
if (!model.md_name.empty()) {
for (unsigned int i = 0; i < model.md_name.size(); i++)
{
@@ -6768,6 +6982,17 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return flush(output_buffer, true);
}
void _QDS_3MF_Exporter::add_transformation(std::stringstream &stream, const Transform3d &tr)
{
for (unsigned c = 0; c < 4; ++c) {
for (unsigned r = 0; r < 3; ++r) {
stream << tr(r, c);
if (r != 2 || c != 3)
stream << " ";
}
}
}
bool _QDS_3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const
{
// This happens for empty projects
@@ -6788,13 +7013,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (!item.path.empty())
stream << "\" " << PPATH_ATTR << "=\"" << xml_escape(item.path);
stream << "\" " << TRANSFORM_ATTR << "=\"";
for (unsigned c = 0; c < 4; ++c) {
for (unsigned r = 0; r < 3; ++r) {
stream << item.transform(r, c);
if (r != 2 || c != 3)
stream << " ";
}
}
add_transformation(stream, item.transform);
stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\"/>\n";
}
@@ -6838,6 +7057,40 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _QDS_3MF_Exporter::_add_brim_ear_points_file_to_archive(mz_zip_archive& archive, Model& model)
{
std::string out = "";
char buffer[1024];
unsigned int count = 0;
for (const ModelObject* object : model.objects) {
++count;
const BrimPoints& brim_points = object->brim_points;
if (!brim_points.empty()) {
sprintf(buffer, "object_id=%d|", count);
out += buffer;
// Store the layer height profile as a single space separated list.
for (size_t i = 0; i < brim_points.size(); ++i) {
sprintf(buffer, (i==0 ? "%f %f %f %f" : " %f %f %f %f"), brim_points[i].pos(0), brim_points[i].pos(1), brim_points[i].pos(2), brim_points[i].head_front_radius);
out += buffer;
}
out += "\n";
}
}
if (!out.empty()) {
// Adds version header at the beginning:
out = std::string("brim_points_format_version=") + std::to_string(brim_points_format_version) + std::string("\n") + out;
if (!mz_zip_writer_add_mem(&archive, BRIM_EAR_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
add_error("Unable to add brim ear points file to archive");
return false;
}
}
return true;
}
bool _QDS_3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
{
std::string out = "";
@@ -7188,6 +7441,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
}
if (const std::optional<EmbossShape> &es = volume->emboss_shape; es.has_value())
to_xml(stream, *es, *volume, archive);
const TextInfo &text_info = volume->get_text_info();
if (!text_info.m_text.empty())
_add_text_info_to_archive(stream, text_info);
@@ -7307,7 +7563,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (!m_skip_model && instance_size > 0)
{
for (unsigned int j = 0; j < instance_size; ++j)
for (int j = 0; j < instance_size; ++j)
{
stream << " <" << INSTANCE_TAG << ">\n";
int obj_id = plate_data->objects_and_instances[j].first;
@@ -7352,7 +7608,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
// write model rels
if (save_gcode)
_add_relationships_file_to_archive(archive, QDS_MODEL_CONFIG_RELS_FILE, gcode_paths, {"http://schemas.qidilab.com/package/2021/gcode"}, Slic3r::PackingTemporaryData(), export_plate_idx);
_add_relationships_file_to_archive(archive, QDS_MODEL_CONFIG_RELS_FILE, gcode_paths, {"http://schemas.qiditech.com/package/2021/gcode"}, Slic3r::PackingTemporaryData(), export_plate_idx);
if (!m_skip_model) {
//QDS: store assemble related info
@@ -8290,4 +8546,148 @@ SaveObjectGaurd::~SaveObjectGaurd()
_QDS_Backup_Manager::get().pop_object_gaurd();
}
namespace {
// Conversion with bidirectional map
// F .. first, S .. second
template<typename F, typename S> F bimap_cvt(const boost::bimap<F, S> &bmap, S s, const F &def_value)
{
const auto &map = bmap.right;
auto found_item = map.find(s);
// only for back and forward compatibility
assert(found_item != map.end());
if (found_item == map.end()) return def_value;
return found_item->second;
}
template<typename F, typename S> S bimap_cvt(const boost::bimap<F, S> &bmap, F f, const S &def_value)
{
const auto &map = bmap.left;
auto found_item = map.find(f);
// only for back and forward compatibility
assert(found_item != map.end());
if (found_item == map.end()) return def_value;
return found_item->second;
}
} // namespace
namespace {
Transform3d create_fix(const std::optional<Transform3d> &prev, const ModelVolume &volume)
{
// IMPROVE: check if volume was modified (translated, rotated OR scaled)
// when no change do not calculate transformation only store original fix matrix
// Create transformation used after load actual stored volume
// Orca: do not bake volume transformation into meshes
// const Transform3d &actual_trmat = volume.get_matrix();
const Transform3d &actual_trmat = Transform3d::Identity();
const auto &vertices = volume.mesh().its.vertices;
Vec3d min = actual_trmat * vertices.front().cast<double>();
Vec3d max = min;
for (const Vec3f &v : vertices) {
Vec3d vd = actual_trmat * v.cast<double>();
for (size_t i = 0; i < 3; ++i) {
if (min[i] > vd[i]) min[i] = vd[i];
if (max[i] < vd[i]) max[i] = vd[i];
}
}
Vec3d center = (max + min) / 2;
Transform3d post_trmat = Transform3d::Identity();
post_trmat.translate(center);
Transform3d fix_trmat = actual_trmat.inverse() * post_trmat;
if (!prev.has_value()) return fix_trmat;
// check whether fix somehow differ previous
if (fix_trmat.isApprox(Transform3d::Identity(), 1e-5)) return *prev;
return *prev * fix_trmat;
}
bool to_xml(std::stringstream &stream, const EmbossShape::SvgFile &svg, const ModelVolume &volume, mz_zip_archive &archive)
{
if (svg.path_in_3mf.empty())
return true; // EmbossedText OR unwanted store .svg file into .3mf (protection of copyRight)
if (!svg.path.empty())
stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path) << "\" ";
stream << SVG_FILE_PATH_IN_3MF_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path_in_3mf) << "\" ";
std::shared_ptr<std::string> file_data = svg.file_data;
assert(file_data != nullptr);
if (file_data == nullptr && !svg.path.empty()) file_data = read_from_disk(svg.path);
if (file_data == nullptr) {
BOOST_LOG_TRIVIAL(warning) << "Can't write svg file no filedata";
return false;
}
const std::string &file_data_str = *file_data;
return mz_zip_writer_add_mem(&archive, svg.path_in_3mf.c_str(), (const void *) file_data_str.c_str(), file_data_str.size(), MZ_DEFAULT_COMPRESSION);
}
} // namespace
void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive)
{
stream << " <" << SHAPE_TAG << " ";
if (es.svg_file.has_value())
if (!to_xml(stream, *es.svg_file, volume, archive)) BOOST_LOG_TRIVIAL(warning) << "Can't write svg file defiden embossed shape into 3mf";
stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" ";
if (!es.final_shape.is_healed) stream << UNHEALED_ATTR << "=\"" << 1 << "\" ";
// projection
const EmbossProjection &p = es.projection;
stream << DEPTH_ATTR << "=\"" << p.depth << "\" ";
if (p.use_surface) stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
// FIX of baked transformation
Transform3d fix = create_fix(es.fix_3mf_tr, volume);
stream << TRANSFORM_ATTR << "=\"";
_QDS_3MF_Exporter::add_transformation(stream, fix);
stream << "\" ";
stream << "/>\n"; // end SHAPE_TAG
}
std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes)
{
double scale = qds_get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
int unhealed = qds_get_attribute_value_int(attributes, num_attributes, UNHEALED_ATTR);
bool is_healed = unhealed != 1;
EmbossProjection projection;
projection.depth = qds_get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
if (is_approx(projection.depth, 0.)) projection.depth = 10.;
int use_surface = qds_get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
if (use_surface == 1) projection.use_surface = true;
std::optional<Transform3d> fix_tr_mat;
std::string fix_tr_mat_str = qds_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
if (!fix_tr_mat_str.empty()) { fix_tr_mat = qds_get_transform_from_3mf_specs_string(fix_tr_mat_str); }
std::string file_path = qds_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR);
std::string file_path_3mf = qds_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_IN_3MF_ATTR);
// MayBe: store also shapes to not store svg
// But be carefull curve will be lost -> scale will not change sampling
// shapes could be loaded from SVG
ExPolygonsWithIds shapes;
// final shape could be calculated from shapes
HealedExPolygons final_shape;
final_shape.is_healed = is_healed;
EmbossShape::SvgFile svg{file_path, file_path_3mf};
return EmbossShape{std::move(shapes), std::move(final_shape), scale, std::move(projection), std::move(fix_tr_mat), std::move(svg)};
}
} // namespace Slic3r

View File

@@ -141,6 +141,10 @@ inline bool operator & (SaveStrategy & lhs, SaveStrategy rhs)
return ((static_cast<T>(lhs) & static_cast<T>(rhs))) == static_cast<T>(rhs);
}
enum {
brim_points_format_version = 0
};
enum class LoadStrategy
{
Default = 0,