Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::_3MF_Importer Class Reference
+ Inheritance diagram for Slic3r::_3MF_Importer:
+ Collaboration diagram for Slic3r::_3MF_Importer:

Classes

struct  Component
 
struct  CurrentConfig
 
struct  CurrentObject
 
struct  CutObjectInfo
 
struct  Geometry
 
struct  Instance
 
struct  Metadata
 

Public Member Functions

 _3MF_Importer ()
 
 ~_3MF_Importer ()
 
bool load_model_from_file (const std::string &filename, Model &model, DynamicPrintConfig &config, ConfigSubstitutionContext &config_substitutions, bool check_version)
 
unsigned int version () const
 
boost::optional< Semverprusaslicer_generator_version () const
 
void log_errors ()
 

Protected Member Functions

void add_error (const std::string &error)
 
void clear_errors ()
 

Private Types

typedef std::vector< ComponentComponentsList
 
typedef std::vector< MetadataMetadataList
 
typedef std::map< int, int > IdToModelObjectMap
 
typedef std::map< int, ComponentsListIdToAliasesMap
 
typedef std::vector< InstanceInstancesList
 
typedef std::map< int, ObjectMetadataIdToMetadataMap
 
typedef std::map< int, GeometryIdToGeometryMap
 
typedef std::map< int, std::vector< coordf_t > > IdToLayerHeightsProfileMap
 
typedef std::map< int, t_layer_config_rangesIdToLayerConfigRangesMap
 
typedef std::map< int, CutObjectInfoIdToCutObjectInfoMap
 
typedef std::map< int, std::vector< sla::SupportPoint > > IdToSlaSupportPointsMap
 
typedef std::map< int, std::vector< sla::DrainHole > > IdToSlaDrainHolesMap
 

Private Member Functions

void _destroy_xml_parser ()
 
void _stop_xml_parser (const std::string &msg=std::string())
 
bool parse_error () const
 
const char * parse_error_message () const
 
bool _load_model_from_file (const std::string &filename, Model &model, DynamicPrintConfig &config, ConfigSubstitutionContext &config_substitutions)
 
bool _extract_model_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
 
void _extract_cut_information_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions)
 
void _extract_layer_heights_profile_config_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
 
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_custom_gcode_per_print_z_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
 
void _extract_print_config_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, DynamicPrintConfig &config, ConfigSubstitutionContext &subs_context, const std::string &archive_filename)
 
bool _extract_model_config_from_archive (mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, Model &model)
 
void _handle_start_model_xml_element (const char *name, const char **attributes)
 
void _handle_end_model_xml_element (const char *name)
 
void _handle_model_xml_characters (const XML_Char *s, int len)
 
void _handle_start_config_xml_element (const char *name, const char **attributes)
 
void _handle_end_config_xml_element (const char *name)
 
bool _handle_start_model (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_model ()
 
bool _handle_start_resources (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_resources ()
 
bool _handle_start_object (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_object ()
 
bool _handle_start_mesh (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_mesh ()
 
bool _handle_start_vertices (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_vertices ()
 
bool _handle_start_vertex (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_vertex ()
 
bool _handle_start_triangles (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_triangles ()
 
bool _handle_start_triangle (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_triangle ()
 
bool _handle_start_components (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_components ()
 
bool _handle_start_component (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_component ()
 
bool _handle_start_build (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_build ()
 
bool _handle_start_item (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_item ()
 
bool _handle_start_metadata (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_metadata ()
 
bool _handle_start_text_configuration (const char **attributes, unsigned int num_attributes)
 
bool _create_object_instance (int object_id, const Transform3d &transform, const bool printable, unsigned int recur_counter)
 
void _apply_transform (ModelInstance &instance, const Transform3d &transform)
 
bool _handle_start_config (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_config ()
 
bool _handle_start_config_object (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_config_object ()
 
bool _handle_start_config_volume (const char **attributes, unsigned int num_attributes)
 
bool _handle_start_config_volume_mesh (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_config_volume ()
 
bool _handle_end_config_volume_mesh ()
 
bool _handle_start_config_metadata (const char **attributes, unsigned int num_attributes)
 
bool _handle_end_config_metadata ()
 
bool _generate_volumes (ModelObject &object, const Geometry &geometry, const ObjectMetadata::VolumeMetadataList &volumes, ConfigSubstitutionContext &config_substitutions)
 

Static Private Member Functions

static void XMLCALL _handle_start_model_xml_element (void *userData, const char *name, const char **attributes)
 
static void XMLCALL _handle_end_model_xml_element (void *userData, const char *name)
 
static void XMLCALL _handle_model_xml_characters (void *userData, const XML_Char *s, int len)
 
static void XMLCALL _handle_start_config_xml_element (void *userData, const char *name, const char **attributes)
 
static void XMLCALL _handle_end_config_xml_element (void *userData, const char *name)
 

Private Attributes

unsigned int m_version
 
bool m_check_version
 
boost::optional< Semverm_prusaslicer_generator_version
 
unsigned int m_fdm_supports_painting_version = 0
 
unsigned int m_seam_painting_version = 0
 
unsigned int m_mm_painting_version = 0
 
XML_Parser m_xml_parser
 
bool m_parse_error { false }
 
std::string m_parse_error_message
 
Modelm_model
 
float m_unit_factor
 
CurrentObject m_curr_object
 
IdToModelObjectMap m_objects
 
IdToAliasesMap m_objects_aliases
 
InstancesList m_instances
 
IdToGeometryMap m_geometries
 
CurrentConfig m_curr_config
 
IdToMetadataMap m_objects_metadata
 
IdToCutObjectInfoMap m_cut_object_infos
 
IdToLayerHeightsProfileMap m_layer_heights_profiles
 
IdToLayerConfigRangesMap m_layer_config_ranges
 
IdToSlaSupportPointsMap m_sla_support_points
 
IdToSlaDrainHolesMap m_sla_drain_holes
 
std::string m_curr_metadata_name
 
std::string m_curr_characters
 
std::string m_name
 
std::vector< std::string > m_errors
 

Detailed Description


Class Documentation

◆ Slic3r::_3MF_Importer::CurrentConfig

struct Slic3r::_3MF_Importer::CurrentConfig
Class Members
int object_id
int volume_id

◆ Slic3r::_3MF_Importer::CutObjectInfo

struct Slic3r::_3MF_Importer::CutObjectInfo
+ Collaboration diagram for Slic3r::_3MF_Importer::CutObjectInfo:
Class Members
vector< Connector > connectors
CutObjectBase id

◆ Slic3r::_3MF_Importer::ObjectMetadata

struct Slic3r::_3MF_Importer::ObjectMetadata
+ Collaboration diagram for Slic3r::_3MF_Importer::ObjectMetadata:
Class Members
typedef vector< VolumeMetadata > VolumeMetadataList
Class Members
MetadataList metadata
VolumeMetadataList volumes

Member Typedef Documentation

◆ ComponentsList

typedef std::vector<Component> Slic3r::_3MF_Importer::ComponentsList
private

◆ IdToAliasesMap

typedef std::map<int, ComponentsList> Slic3r::_3MF_Importer::IdToAliasesMap
private

◆ IdToCutObjectInfoMap

◆ IdToGeometryMap

typedef std::map<int, Geometry> Slic3r::_3MF_Importer::IdToGeometryMap
private

◆ IdToLayerConfigRangesMap

◆ IdToLayerHeightsProfileMap

typedef std::map<int, std::vector<coordf_t> > Slic3r::_3MF_Importer::IdToLayerHeightsProfileMap
private

◆ IdToMetadataMap

◆ IdToModelObjectMap

typedef std::map<int, int> Slic3r::_3MF_Importer::IdToModelObjectMap
private

◆ IdToSlaDrainHolesMap

typedef std::map<int, std::vector<sla::DrainHole> > Slic3r::_3MF_Importer::IdToSlaDrainHolesMap
private

◆ IdToSlaSupportPointsMap

typedef std::map<int, std::vector<sla::SupportPoint> > Slic3r::_3MF_Importer::IdToSlaSupportPointsMap
private

◆ InstancesList

typedef std::vector<Instance> Slic3r::_3MF_Importer::InstancesList
private

◆ MetadataList

typedef std::vector<Metadata> Slic3r::_3MF_Importer::MetadataList
private

Constructor & Destructor Documentation

◆ _3MF_Importer()

Slic3r::_3MF_Importer::_3MF_Importer ( )
605 : m_version(0)
606 , m_check_version(false)
607 , m_xml_parser(nullptr)
608 , m_model(nullptr)
609 , m_unit_factor(1.0f)
612 , m_name("")
613 {
614 }
unsigned int m_version
Definition 3mf.cpp:458
Model * m_model
Definition 3mf.cpp:472
float m_unit_factor
Definition 3mf.cpp:473
std::string m_curr_metadata_name
Definition 3mf.cpp:486
std::string m_curr_characters
Definition 3mf.cpp:487
XML_Parser m_xml_parser
Definition 3mf.cpp:467
bool m_check_version
Definition 3mf.cpp:459
std::string m_name
Definition 3mf.cpp:488

◆ ~_3MF_Importer()

Slic3r::_3MF_Importer::~_3MF_Importer ( )
617 {
619 }
void _destroy_xml_parser()
Definition 3mf.cpp:648

References _destroy_xml_parser().

+ Here is the call graph for this function:

Member Function Documentation

◆ _apply_transform()

void Slic3r::_3MF_Importer::_apply_transform ( ModelInstance instance,
const Transform3d transform 
)
private
1994 {
1996 // invalid scale value, return
1997 if (!t.get_scaling_factor().all())
1998 return;
1999
2000 instance.set_transformation(t);
2001 }
Definition Geometry.hpp:380
Linef3 transform(const Linef3 &line, const Transform3d &t)
Definition Line.cpp:10

References Slic3r::Geometry::Transformation::get_scaling_factor(), and Slic3r::ModelInstance::set_transformation().

+ Here is the call graph for this function:

◆ _create_object_instance()

bool Slic3r::_3MF_Importer::_create_object_instance ( int  object_id,
const Transform3d transform,
const bool  printable,
unsigned int  recur_counter 
)
private
1948 {
1949 static const unsigned int MAX_RECURSIONS = 10;
1950
1951 // escape from circular aliasing
1952 if (recur_counter > MAX_RECURSIONS) {
1953 add_error("Too many recursions");
1954 return false;
1955 }
1956
1957 IdToAliasesMap::iterator it = m_objects_aliases.find(object_id);
1958 if (it == m_objects_aliases.end()) {
1959 add_error("Found item with invalid object id");
1960 return false;
1961 }
1962
1963 if (it->second.size() == 1 && it->second[0].object_id == object_id) {
1964 // aliasing to itself
1965
1966 IdToModelObjectMap::iterator object_item = m_objects.find(object_id);
1967 if (object_item == m_objects.end() || object_item->second == -1) {
1968 add_error("Found invalid object");
1969 return false;
1970 }
1971 else {
1972 ModelInstance* instance = m_model->objects[object_item->second]->add_instance();
1973 if (instance == nullptr) {
1974 add_error("Unable to add object instance");
1975 return false;
1976 }
1977 instance->printable = printable;
1978
1979 m_instances.emplace_back(instance, transform);
1980 }
1981 }
1982 else {
1983 // recursively process nested components
1984 for (const Component& component : it->second) {
1985 if (!_create_object_instance(component.object_id, transform * component.transform, printable, recur_counter + 1))
1986 return false;
1987 }
1988 }
1989
1990 return true;
1991 }
void add_error(const std::string &error)
Definition 3mf.cpp:305
bool _create_object_instance(int object_id, const Transform3d &transform, const bool printable, unsigned int recur_counter)
Definition 3mf.cpp:1947
IdToAliasesMap m_objects_aliases
Definition 3mf.cpp:476
InstancesList m_instances
Definition 3mf.cpp:477
IdToModelObjectMap m_objects
Definition 3mf.cpp:475
ModelObjectPtrs objects
Definition Model.hpp:1254

References Slic3r::Model::objects, and Slic3r::ModelInstance::printable.

◆ _destroy_xml_parser()

void Slic3r::_3MF_Importer::_destroy_xml_parser ( )
private
649 {
650 if (m_xml_parser != nullptr) {
651 XML_ParserFree(m_xml_parser);
652 m_xml_parser = nullptr;
653 }
654 }

References m_xml_parser.

Referenced by ~_3MF_Importer(), and _extract_model_from_archive().

+ Here is the caller graph for this function:

◆ _extract_custom_gcode_per_print_z_from_archive()

void Slic3r::_3MF_Importer::_extract_custom_gcode_per_print_z_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat 
)
private
1397 {
1398 if (stat.m_uncomp_size > 0) {
1399 std::string buffer((size_t)stat.m_uncomp_size, 0);
1400 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1401 if (res == 0) {
1402 add_error("Error while reading custom Gcodes per height data to buffer");
1403 return;
1404 }
1405
1406 std::istringstream iss(buffer); // wrap returned xml to istringstream
1407 pt::ptree main_tree;
1408 pt::read_xml(iss, main_tree);
1409
1410 if (main_tree.front().first != "custom_gcodes_per_print_z")
1411 return;
1412 pt::ptree code_tree = main_tree.front().second;
1413
1415
1416 for (const auto& code : code_tree) {
1417 if (code.first == "mode") {
1418 pt::ptree tree = code.second;
1419 std::string mode = tree.get<std::string>("<xmlattr>.value");
1423 }
1424 if (code.first != "code")
1425 continue;
1426
1427 pt::ptree tree = code.second;
1428 double print_z = tree.get<double> ("<xmlattr>.print_z" );
1429 int extruder = tree.get<int> ("<xmlattr>.extruder");
1430 std::string color = tree.get<std::string> ("<xmlattr>.color" );
1431
1432 CustomGCode::Type type;
1433 std::string extra;
1434 pt::ptree attr_tree = tree.find("<xmlattr>")->second;
1435 if (attr_tree.find("type") == attr_tree.not_found()) {
1436 // It means that data was saved in old version (2.2.0 and older) of PrusaSlicer
1437 // read old data ...
1438 std::string gcode = tree.get<std::string> ("<xmlattr>.gcode");
1439 // ... and interpret them to the new data
1440 type = gcode == "M600" ? CustomGCode::ColorChange :
1441 gcode == "M601" ? CustomGCode::PausePrint :
1443 extra = type == CustomGCode::PausePrint ? color :
1444 type == CustomGCode::Custom ? gcode : "";
1445 }
1446 else {
1447 type = static_cast<CustomGCode::Type>(tree.get<int>("<xmlattr>.type"));
1448 extra = tree.get<std::string>("<xmlattr>.extra");
1449 }
1450 m_model->custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, type, extruder, color, extra}) ;
1451 }
1452 }
1453 }
CustomGCode::Info custom_gcode_per_print_z
Definition Model.hpp:1259
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
Definition miniz.c:4528
int mz_bool
Definition miniz.h:492
static constexpr char SingleExtruderMode[]
Definition CustomGCode.hpp:58
static constexpr char MultiAsSingleMode[]
Definition CustomGCode.hpp:59
@ MultiAsSingle
Definition CustomGCode.hpp:51
@ SingleExtruder
Definition CustomGCode.hpp:50
@ MultiExtruder
Definition CustomGCode.hpp:54
Type
Definition CustomGCode.hpp:14
@ PausePrint
Definition CustomGCode.hpp:16
@ ToolChange
Definition CustomGCode.hpp:17
@ Custom
Definition CustomGCode.hpp:19
@ ColorChange
Definition CustomGCode.hpp:15
IGL_INLINE void mode(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &X, const int d, Eigen::Matrix< T, Eigen::Dynamic, 1 > &M)
Definition mode.cpp:14
Mode mode
Definition CustomGCode.hpp:64
std::vector< Item > gcodes
Definition CustomGCode.hpp:65
#define stat
Definition unistd.h:53

References Slic3r::Model::custom_gcode_per_print_z, Slic3r::CustomGCode::Info::gcodes, Slic3r::CustomGCode::Info::mode, mz_zip_reader_extract_to_mem(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_cut_information_from_archive()

void Slic3r::_3MF_Importer::_extract_cut_information_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat,
ConfigSubstitutionContext config_substitutions 
)
private
989 {
990 if (stat.m_uncomp_size > 0) {
991 std::string buffer((size_t)stat.m_uncomp_size, 0);
992 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
993 if (res == 0) {
994 add_error("Error while reading cut information data to buffer");
995 return;
996 }
997
998 std::istringstream iss(buffer); // wrap returned xml to istringstream
999 pt::ptree objects_tree;
1000 pt::read_xml(iss, objects_tree);
1001
1002 for (const auto& object : objects_tree.get_child("objects")) {
1003 pt::ptree object_tree = object.second;
1004 int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
1005 if (obj_idx <= 0) {
1006 add_error("Found invalid object id");
1007 continue;
1008 }
1009
1010 IdToCutObjectInfoMap::iterator object_item = m_cut_object_infos.find(obj_idx);
1011 if (object_item != m_cut_object_infos.end()) {
1012 add_error("Found duplicated cut_object_id");
1013 continue;
1014 }
1015
1016 CutObjectBase cut_id;
1017 std::vector<CutObjectInfo::Connector> connectors;
1018
1019 for (const auto& obj_cut_info : object_tree) {
1020 if (obj_cut_info.first == "cut_id") {
1021 pt::ptree cut_id_tree = obj_cut_info.second;
1022 cut_id = CutObjectBase(ObjectID( cut_id_tree.get<size_t>("<xmlattr>.id")),
1023 cut_id_tree.get<size_t>("<xmlattr>.check_sum"),
1024 cut_id_tree.get<size_t>("<xmlattr>.connectors_cnt"));
1025 }
1026 if (obj_cut_info.first == "connectors") {
1027 pt::ptree cut_connectors_tree = obj_cut_info.second;
1028 for (const auto& cut_connector : cut_connectors_tree) {
1029 if (cut_connector.first != "connector")
1030 continue;
1031 pt::ptree connector_tree = cut_connector.second;
1032 CutObjectInfo::Connector connector = {connector_tree.get<int>("<xmlattr>.volume_id"),
1033 connector_tree.get<int>("<xmlattr>.type"),
1034 connector_tree.get<float>("<xmlattr>.r_tolerance"),
1035 connector_tree.get<float>("<xmlattr>.h_tolerance")};
1036 connectors.emplace_back(connector);
1037 }
1038 }
1039 }
1040
1041 CutObjectInfo cut_info {cut_id, connectors};
1042 m_cut_object_infos.insert({ obj_idx, cut_info });
1043 }
1044 }
1045 }
IdToCutObjectInfoMap m_cut_object_infos
Definition 3mf.cpp:481

References mz_zip_reader_extract_to_mem(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_layer_config_ranges_from_archive()

void Slic3r::_3MF_Importer::_extract_layer_config_ranges_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat,
ConfigSubstitutionContext config_substitutions 
)
private
1133 {
1134 if (stat.m_uncomp_size > 0) {
1135 std::string buffer((size_t)stat.m_uncomp_size, 0);
1136 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1137 if (res == 0) {
1138 add_error("Error while reading layer config ranges data to buffer");
1139 return;
1140 }
1141
1142 std::istringstream iss(buffer); // wrap returned xml to istringstream
1143 pt::ptree objects_tree;
1144 pt::read_xml(iss, objects_tree);
1145
1146 for (const auto& object : objects_tree.get_child("objects")) {
1147 pt::ptree object_tree = object.second;
1148 int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
1149 if (obj_idx <= 0) {
1150 add_error("Found invalid object id");
1151 continue;
1152 }
1153
1154 IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(obj_idx);
1155 if (object_item != m_layer_config_ranges.end()) {
1156 add_error("Found duplicated layer config range");
1157 continue;
1158 }
1159
1160 t_layer_config_ranges config_ranges;
1161
1162 for (const auto& range : object_tree) {
1163 if (range.first != "range")
1164 continue;
1165 pt::ptree range_tree = range.second;
1166 double min_z = range_tree.get<double>("<xmlattr>.min_z");
1167 double max_z = range_tree.get<double>("<xmlattr>.max_z");
1168
1169 // get Z range information
1170 DynamicPrintConfig config;
1171
1172 for (const auto& option : range_tree) {
1173 if (option.first != "option")
1174 continue;
1175 std::string opt_key = option.second.get<std::string>("<xmlattr>.opt_key");
1176 std::string value = option.second.data();
1177 config.set_deserialize(opt_key, value, config_substitutions);
1178 }
1179
1180 config_ranges[{ min_z, max_z }].assign_config(std::move(config));
1181 }
1182
1183 if (!config_ranges.empty())
1184 m_layer_config_ranges.insert({ obj_idx, std::move(config_ranges) });
1185 }
1186 }
1187 }
IdToLayerConfigRangesMap m_layer_config_ranges
Definition 3mf.cpp:483
Definition getopt.h:102
auto range(Cont &&cont)
Definition libslic3r.h:356
std::map< t_layer_height_range, ModelConfig > t_layer_config_ranges
Definition Slicing.hpp:130

References mz_zip_reader_extract_to_mem(), Slic3r::range(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_layer_heights_profile_config_from_archive()

void Slic3r::_3MF_Importer::_extract_layer_heights_profile_config_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat 
)
private
1071 {
1072 if (stat.m_uncomp_size > 0) {
1073 std::string buffer((size_t)stat.m_uncomp_size, 0);
1074 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1075 if (res == 0) {
1076 add_error("Error while reading layer heights profile data to buffer");
1077 return;
1078 }
1079
1080 if (buffer.back() == '\n')
1081 buffer.pop_back();
1082
1083 std::vector<std::string> objects;
1084 boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
1085
1086 for (const std::string& object : objects) {
1087 std::vector<std::string> object_data;
1088 boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
1089 if (object_data.size() != 2) {
1090 add_error("Error while reading object data");
1091 continue;
1092 }
1093
1094 std::vector<std::string> object_data_id;
1095 boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
1096 if (object_data_id.size() != 2) {
1097 add_error("Error while reading object id");
1098 continue;
1099 }
1100
1101 int object_id = std::atoi(object_data_id[1].c_str());
1102 if (object_id == 0) {
1103 add_error("Found invalid object id");
1104 continue;
1105 }
1106
1107 IdToLayerHeightsProfileMap::iterator object_item = m_layer_heights_profiles.find(object_id);
1108 if (object_item != m_layer_heights_profiles.end()) {
1109 add_error("Found duplicated layer heights profile");
1110 continue;
1111 }
1112
1113 std::vector<std::string> object_data_profile;
1114 boost::split(object_data_profile, object_data[1], boost::is_any_of(";"), boost::token_compress_off);
1115 if (object_data_profile.size() <= 4 || object_data_profile.size() % 2 != 0) {
1116 add_error("Found invalid layer heights profile");
1117 continue;
1118 }
1119
1120 std::vector<coordf_t> profile;
1121 profile.reserve(object_data_profile.size());
1122
1123 for (const std::string& value : object_data_profile) {
1124 profile.push_back((coordf_t)std::atof(value.c_str()));
1125 }
1126
1127 m_layer_heights_profiles.insert({ object_id, profile });
1128 }
1129 }
1130 }
IdToLayerHeightsProfileMap m_layer_heights_profiles
Definition 3mf.cpp:482
double coordf_t
Definition libslic3r.h:45

References mz_zip_reader_extract_to_mem(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_model_config_from_archive()

bool Slic3r::_3MF_Importer::_extract_model_config_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat,
Model model 
)
private
1357 {
1358 if (stat.m_uncomp_size == 0) {
1359 add_error("Found invalid size");
1360 return false;
1361 }
1362
1364
1365 m_xml_parser = XML_ParserCreate(nullptr);
1366 if (m_xml_parser == nullptr) {
1367 add_error("Unable to create parser");
1368 return false;
1369 }
1370
1371 XML_SetUserData(m_xml_parser, (void*)this);
1373
1374 void* parser_buffer = XML_GetBuffer(m_xml_parser, (int)stat.m_uncomp_size);
1375 if (parser_buffer == nullptr) {
1376 add_error("Unable to create buffer");
1377 return false;
1378 }
1379
1380 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, parser_buffer, (size_t)stat.m_uncomp_size, 0);
1381 if (res == 0) {
1382 add_error("Error while reading config data to buffer");
1383 return false;
1384 }
1385
1386 if (!XML_ParseBuffer(m_xml_parser, (int)stat.m_uncomp_size, 1)) {
1387 char error_buf[1024];
1388 ::sprintf(error_buf, "Error (%s) while parsing xml file at line %d", XML_ErrorString(XML_GetErrorCode(m_xml_parser)), (int)XML_GetCurrentLineNumber(m_xml_parser));
1389 add_error(error_buf);
1390 return false;
1391 }
1392
1393 return true;
1394 }
void _handle_end_config_xml_element(const char *name)
Definition 3mf.cpp:1562
void _handle_start_config_xml_element(const char *name, const char **attributes)
Definition 3mf.cpp:1537

References mz_zip_reader_extract_to_mem(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_model_from_archive()

bool Slic3r::_3MF_Importer::_extract_model_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat 
)
private
925 {
926 if (stat.m_uncomp_size == 0) {
927 add_error("Found invalid size");
928 return false;
929 }
930
932
933 m_xml_parser = XML_ParserCreate(nullptr);
934 if (m_xml_parser == nullptr) {
935 add_error("Unable to create parser");
936 return false;
937 }
938
939 XML_SetUserData(m_xml_parser, (void*)this);
941 XML_SetCharacterDataHandler(m_xml_parser, _3MF_Importer::_handle_model_xml_characters);
942
943 struct CallbackData
944 {
945 XML_Parser& parser;
946 _3MF_Importer& importer;
948
949 CallbackData(XML_Parser& parser, _3MF_Importer& importer, const mz_zip_archive_file_stat& stat) : parser(parser), importer(importer), stat(stat) {}
950 };
951
952 CallbackData data(m_xml_parser, *this, stat);
953
954 mz_bool res = 0;
955
956 try
957 {
958 res = mz_zip_reader_extract_to_callback(&archive, stat.m_file_index, [](void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)->size_t {
959 CallbackData* data = (CallbackData*)pOpaque;
960 if (!XML_Parse(data->parser, (const char*)pBuf, (int)n, (file_ofs + n == data->stat.m_uncomp_size) ? 1 : 0) || data->importer.parse_error()) {
961 char error_buf[1024];
962 ::sprintf(error_buf, "Error (%s) while parsing '%s' at line %d", data->importer.parse_error_message(), data->stat.m_filename, (int)XML_GetCurrentLineNumber(data->parser));
963 throw Slic3r::FileIOError(error_buf);
964 }
965
966 return n;
967 }, &data, 0);
968 }
969 catch (const version_error& e)
970 {
971 // rethrow the exception
972 throw Slic3r::FileIOError(e.what());
973 }
974 catch (std::exception& e)
975 {
976 add_error(e.what());
977 return false;
978 }
979
980 if (res == 0) {
981 add_error("Error while extracting model data from ZIP archive");
982 return false;
983 }
984
985 return true;
986 }
void _handle_end_model_xml_element(const char *name)
Definition 3mf.cpp:1494
void _handle_start_model_xml_element(const char *name, const char **attributes)
Definition 3mf.cpp:1455
void _handle_model_xml_characters(const XML_Char *s, int len)
Definition 3mf.cpp:1532
Definition 3mf.cpp:188
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
Definition miniz.c:4592
uint64_t mz_uint64
Definition miniz.h:491
Definition miniz.h:924
constexpr auto data(C &c) -> decltype(c.data())
Definition span.hpp:195

References _destroy_xml_parser(), _handle_end_model_xml_element(), _handle_model_xml_characters(), _handle_start_model_xml_element(), Slic3r::_3MF_Base::add_error(), m_xml_parser, mz_zip_reader_extract_to_callback(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_print_config_from_archive()

void Slic3r::_3MF_Importer::_extract_print_config_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat,
DynamicPrintConfig config,
ConfigSubstitutionContext subs_context,
const std::string &  archive_filename 
)
private
1051 {
1052 if (stat.m_uncomp_size > 0) {
1053 std::string buffer((size_t)stat.m_uncomp_size, 0);
1054 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1055 if (res == 0) {
1056 add_error("Error while reading config data to buffer");
1057 return;
1058 }
1059 //FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
1060 // Each config line is prefixed with a semicolon (G-code comment), that is ugly.
1061
1062 // Replacing the legacy function with load_from_ini_string_commented leads to issues when
1063 // parsing 3MFs from before PrusaSlicer 2.0.0 (which can have duplicated entries in the INI.
1064 // See https://github.com/prusa3d/PrusaSlicer/issues/7155. We'll revert it for now.
1065 //config_substitutions.substitutions = config.load_from_ini_string_commented(std::move(buffer), config_substitutions.rule);
1066 ConfigBase::load_from_gcode_string_legacy(config, buffer.data(), config_substitutions);
1067 }
1068 }
static size_t load_from_gcode_string_legacy(ConfigBase &config, const char *str, ConfigSubstitutionContext &substitutions)
Definition Config.cpp:804

References mz_zip_reader_extract_to_mem(), and stat.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_sla_drain_holes_from_archive()

void Slic3r::_3MF_Importer::_extract_sla_drain_holes_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat 
)
private
1272 {
1273 if (stat.m_uncomp_size > 0) {
1274 std::string buffer(size_t(stat.m_uncomp_size), 0);
1275 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1276 if (res == 0) {
1277 add_error("Error while reading sla support points data to buffer");
1278 return;
1279 }
1280
1281 if (buffer.back() == '\n')
1282 buffer.pop_back();
1283
1284 std::vector<std::string> objects;
1285 boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
1286
1287 // Info on format versioning - see 3mf.hpp
1288 int version = 0;
1289 std::string key("drain_holes_format_version=");
1290 if (!objects.empty() && objects[0].find(key) != std::string::npos) {
1291 objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
1292 version = std::stoi(objects[0]);
1293 objects.erase(objects.begin()); // pop the header
1294 }
1295
1296 for (const std::string& object : objects) {
1297 std::vector<std::string> object_data;
1298 boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
1299
1300 if (object_data.size() != 2) {
1301 add_error("Error while reading object data");
1302 continue;
1303 }
1304
1305 std::vector<std::string> object_data_id;
1306 boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
1307 if (object_data_id.size() != 2) {
1308 add_error("Error while reading object id");
1309 continue;
1310 }
1311
1312 int object_id = std::atoi(object_data_id[1].c_str());
1313 if (object_id == 0) {
1314 add_error("Found invalid object id");
1315 continue;
1316 }
1317
1318 IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id);
1319 if (object_item != m_sla_drain_holes.end()) {
1320 add_error("Found duplicated SLA drain holes");
1321 continue;
1322 }
1323
1324 std::vector<std::string> object_data_points;
1325 boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
1326
1327 sla::DrainHoles sla_drain_holes;
1328
1329 if (version == 1) {
1330 for (unsigned int i=0; i<object_data_points.size(); i+=8)
1331 sla_drain_holes.emplace_back(Vec3f{float(std::atof(object_data_points[i+0].c_str())),
1332 float(std::atof(object_data_points[i+1].c_str())),
1333 float(std::atof(object_data_points[i+2].c_str()))},
1334 Vec3f{float(std::atof(object_data_points[i+3].c_str())),
1335 float(std::atof(object_data_points[i+4].c_str())),
1336 float(std::atof(object_data_points[i+5].c_str()))},
1337 float(std::atof(object_data_points[i+6].c_str())),
1338 float(std::atof(object_data_points[i+7].c_str())));
1339 }
1340
1341 // The holes are saved elevated above the mesh and deeper (bad idea indeed).
1342 // This is retained for compatibility.
1343 // Place the hole to the mesh and make it shallower to compensate.
1344 // The offset is 1 mm above the mesh.
1345 for (sla::DrainHole& hole : sla_drain_holes) {
1346 hole.pos += hole.normal.normalized();
1347 hole.height -= 1.f;
1348 }
1349
1350 if (!sla_drain_holes.empty())
1351 m_sla_drain_holes.insert({ object_id, sla_drain_holes });
1352 }
1353 }
1354 }
IdToSlaDrainHolesMap m_sla_drain_holes
Definition 3mf.cpp:485
unsigned int version() const
Definition 3mf.cpp:495
std::vector< DrainHole > DrainHoles
Definition Hollowing.hpp:76
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:49
S::iterator begin(S &sh, const PathTag &)
Definition geometry_traits.hpp:614
Slic3r::Polygon & hole(Slic3r::ExPolygon &sh, unsigned long idx)
Definition geometries.hpp:200

References mz_zip_reader_extract_to_mem(), stat, and version.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _extract_sla_support_points_from_archive()

void Slic3r::_3MF_Importer::_extract_sla_support_points_from_archive ( mz_zip_archive archive,
const mz_zip_archive_file_stat stat 
)
private
1190 {
1191 if (stat.m_uncomp_size > 0) {
1192 std::string buffer((size_t)stat.m_uncomp_size, 0);
1193 mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
1194 if (res == 0) {
1195 add_error("Error while reading sla support points data to buffer");
1196 return;
1197 }
1198
1199 if (buffer.back() == '\n')
1200 buffer.pop_back();
1201
1202 std::vector<std::string> objects;
1203 boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
1204
1205 // Info on format versioning - see 3mf.hpp
1206 int version = 0;
1207 std::string key("support_points_format_version=");
1208 if (!objects.empty() && objects[0].find(key) != std::string::npos) {
1209 objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
1210 version = std::stoi(objects[0]);
1211 objects.erase(objects.begin()); // pop the header
1212 }
1213
1214 for (const std::string& object : objects) {
1215 std::vector<std::string> object_data;
1216 boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
1217
1218 if (object_data.size() != 2) {
1219 add_error("Error while reading object data");
1220 continue;
1221 }
1222
1223 std::vector<std::string> object_data_id;
1224 boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
1225 if (object_data_id.size() != 2) {
1226 add_error("Error while reading object id");
1227 continue;
1228 }
1229
1230 int object_id = std::atoi(object_data_id[1].c_str());
1231 if (object_id == 0) {
1232 add_error("Found invalid object id");
1233 continue;
1234 }
1235
1236 IdToSlaSupportPointsMap::iterator object_item = m_sla_support_points.find(object_id);
1237 if (object_item != m_sla_support_points.end()) {
1238 add_error("Found duplicated SLA support points");
1239 continue;
1240 }
1241
1242 std::vector<std::string> object_data_points;
1243 boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
1244
1245 std::vector<sla::SupportPoint> sla_support_points;
1246
1247 if (version == 0) {
1248 for (unsigned int i=0; i<object_data_points.size(); i+=3)
1249 sla_support_points.emplace_back(float(std::atof(object_data_points[i+0].c_str())),
1250 float(std::atof(object_data_points[i+1].c_str())),
1251 float(std::atof(object_data_points[i+2].c_str())),
1252 0.4f,
1253 false);
1254 }
1255 if (version == 1) {
1256 for (unsigned int i=0; i<object_data_points.size(); i+=5)
1257 sla_support_points.emplace_back(float(std::atof(object_data_points[i+0].c_str())),
1258 float(std::atof(object_data_points[i+1].c_str())),
1259 float(std::atof(object_data_points[i+2].c_str())),
1260 float(std::atof(object_data_points[i+3].c_str())),
1261 //FIXME storing boolean as 0 / 1 and importing it as float.
1262 std::abs(std::atof(object_data_points[i+4].c_str()) - 1.) < EPSILON);
1263 }
1264
1265 if (!sla_support_points.empty())
1266 m_sla_support_points.insert({ object_id, sla_support_points });
1267 }
1268 }
1269 }
IdToSlaSupportPointsMap m_sla_support_points
Definition 3mf.cpp:484
static constexpr double EPSILON
Definition libslic3r.h:51

References EPSILON, mz_zip_reader_extract_to_mem(), stat, and version.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _generate_volumes()

bool Slic3r::_3MF_Importer::_generate_volumes ( ModelObject object,
const Geometry geometry,
const ObjectMetadata::VolumeMetadataList volumes,
ConfigSubstitutionContext config_substitutions 
)
private
2125 {
2126 if (!object.volumes.empty()) {
2127 add_error("Found invalid volumes count");
2128 return false;
2129 }
2130
2131 unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
2132 unsigned int renamed_volumes_count = 0;
2133
2134 for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) {
2135 if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) {
2136 add_error("Found invalid triangle id");
2137 return false;
2138 }
2139
2140 Transform3d volume_matrix_to_object = Transform3d::Identity();
2141 bool has_transform = false;
2142 // extract the volume transformation from the volume's metadata, if present
2143 for (const Metadata& metadata : volume_data.metadata) {
2144 if (metadata.key == MATRIX_KEY) {
2145 volume_matrix_to_object = Slic3r::Geometry::transform3d_from_string(metadata.value);
2146 has_transform = ! volume_matrix_to_object.isApprox(Transform3d::Identity(), 1e-10);
2147 break;
2148 }
2149 }
2150
2151 // splits volume out of imported geometry
2153 its.indices.assign(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1);
2154 const size_t triangles_count = its.indices.size();
2155 if (triangles_count == 0) {
2156 add_error("An empty triangle mesh found");
2157 return false;
2158 }
2159
2160 {
2161 int min_id = its.indices.front()[0];
2162 int max_id = min_id;
2163 for (const Vec3i& face : its.indices) {
2164 for (const int tri_id : face) {
2165 if (tri_id < 0 || tri_id >= int(geometry.vertices.size())) {
2166 add_error("Found invalid vertex id");
2167 return false;
2168 }
2169 min_id = std::min(min_id, tri_id);
2170 max_id = std::max(max_id, tri_id);
2171 }
2172 }
2173 its.vertices.assign(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1);
2174
2175 // rebase indices to the current vertices list
2176 for (Vec3i& face : its.indices)
2177 for (int& tri_id : face)
2178 tri_id -= min_id;
2179 }
2180
2182 *m_prusaslicer_generator_version >= *Semver::parse("2.4.0-alpha1") &&
2184 // PrusaSlicer 2.4.0-alpha2 contained a bug, where all vertices of a single object were saved for each volume the object contained.
2185 // Remove the vertices, that are not referenced by any face.
2186 its_compactify_vertices(its, true);
2187
2188 TriangleMesh triangle_mesh(std::move(its), volume_data.mesh_stats);
2189
2190 if (m_version == 0) {
2191 // if the 3mf was not produced by PrusaSlicer and there is only one instance,
2192 // bake the transformation into the geometry to allow the reload from disk command
2193 // to work properly
2194 if (object.instances.size() == 1) {
2195 triangle_mesh.transform(object.instances.front()->get_transformation().get_matrix(), false);
2196 object.instances.front()->set_transformation(Slic3r::Geometry::Transformation());
2197 //FIXME do the mesh fixing?
2198 }
2199 }
2200 if (triangle_mesh.volume() < 0)
2201 triangle_mesh.flip_triangles();
2202
2203 ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
2204 // stores the volume matrix taken from the metadata, if present
2205 if (has_transform)
2206 volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
2207
2208 // recreate custom supports, seam and mmu segmentation from previously loaded attribute
2209 volume->supported_facets.reserve(triangles_count);
2210 volume->seam_facets.reserve(triangles_count);
2211 volume->mmu_segmentation_facets.reserve(triangles_count);
2212 for (size_t i=0; i<triangles_count; ++i) {
2213 size_t index = volume_data.first_triangle_id + i;
2214 assert(index < geometry.custom_supports.size());
2215 assert(index < geometry.custom_seam.size());
2216 assert(index < geometry.mmu_segmentation.size());
2217 if (! geometry.custom_supports[index].empty())
2218 volume->supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
2219 if (! geometry.custom_seam[index].empty())
2220 volume->seam_facets.set_triangle_from_string(i, geometry.custom_seam[index]);
2221 if (! geometry.mmu_segmentation[index].empty())
2222 volume->mmu_segmentation_facets.set_triangle_from_string(i, geometry.mmu_segmentation[index]);
2223 }
2224 volume->supported_facets.shrink_to_fit();
2225 volume->seam_facets.shrink_to_fit();
2226 volume->mmu_segmentation_facets.shrink_to_fit();
2227 auto &tc = volume_data.text_configuration;
2228 if (tc.has_value()) {
2229 volume->text_configuration = std::move(tc);
2230
2232 //const Transform3d &pre_trmat = *tc->fix_3mf_tr;
2236
2238 //assert(tc->fix_3mf_tr.has_value());
2239 //volume->text_configuration->fix_3mf_tr =
2240 // pre_trmat.inverse() *
2241 // volume->get_transformation().get_matrix();
2242 }
2243
2244 // apply the remaining volume's metadata
2245 for (const Metadata& metadata : volume_data.metadata) {
2246 if (metadata.key == NAME_KEY)
2247 volume->name = metadata.value;
2248 else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1"))
2250 else if (metadata.key == VOLUME_TYPE_KEY)
2251 volume->set_type(ModelVolume::type_from_string(metadata.value));
2252 else if (metadata.key == SOURCE_FILE_KEY)
2253 volume->source.input_file = metadata.value;
2254 else if (metadata.key == SOURCE_OBJECT_ID_KEY)
2255 volume->source.object_idx = ::atoi(metadata.value.c_str());
2256 else if (metadata.key == SOURCE_VOLUME_ID_KEY)
2257 volume->source.volume_idx = ::atoi(metadata.value.c_str());
2258 else if (metadata.key == SOURCE_OFFSET_X_KEY)
2259 volume->source.mesh_offset.x() = ::atof(metadata.value.c_str());
2260 else if (metadata.key == SOURCE_OFFSET_Y_KEY)
2261 volume->source.mesh_offset.y() = ::atof(metadata.value.c_str());
2262 else if (metadata.key == SOURCE_OFFSET_Z_KEY)
2263 volume->source.mesh_offset.z() = ::atof(metadata.value.c_str());
2264 else if (metadata.key == SOURCE_IN_INCHES_KEY)
2265 volume->source.is_converted_from_inches = metadata.value == "1";
2266 else if (metadata.key == SOURCE_IN_METERS_KEY)
2267 volume->source.is_converted_from_meters = metadata.value == "1";
2268 else if (metadata.key == SOURCE_IS_BUILTIN_VOLUME_KEY)
2269 volume->source.is_from_builtin_objects = metadata.value == "1";
2270 else
2271 volume->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
2272 }
2273
2274 // this may happen for 3mf saved by 3rd part softwares
2275 if (volume->name.empty()) {
2276 volume->name = object.name;
2277 if (renamed_volumes_count > 0)
2278 volume->name += "_" + std::to_string(renamed_volumes_count + 1);
2279 ++renamed_volumes_count;
2280 }
2281 }
2282
2283 return true;
2284 }
static constexpr const char * SOURCE_VOLUME_ID_KEY
Definition 3mf.cpp:134
static constexpr const char * SOURCE_IN_INCHES_KEY
Definition 3mf.cpp:138
static constexpr const char * NAME_KEY
Definition 3mf.cpp:128
static constexpr const char * SOURCE_IS_BUILTIN_VOLUME_KEY
Definition 3mf.cpp:140
static constexpr const char * SOURCE_IN_METERS_KEY
Definition 3mf.cpp:139
static constexpr const char * MODIFIER_KEY
Definition 3mf.cpp:129
static constexpr const char * SOURCE_OFFSET_Z_KEY
Definition 3mf.cpp:137
static constexpr const char * SOURCE_OFFSET_X_KEY
Definition 3mf.cpp:135
static constexpr const char * SOURCE_OBJECT_ID_KEY
Definition 3mf.cpp:133
static constexpr const char * SOURCE_OFFSET_Y_KEY
Definition 3mf.cpp:136
static constexpr const char * MATRIX_KEY
Definition 3mf.cpp:131
static constexpr const char * SOURCE_FILE_KEY
Definition 3mf.cpp:132
static constexpr const char * VOLUME_TYPE_KEY
Definition 3mf.cpp:130
boost::optional< Semver > m_prusaslicer_generator_version
Definition 3mf.cpp:462
static ModelVolumeType type_from_string(const std::string &s)
Definition Model.cpp:2117
static boost::optional< Semver > parse(const std::string &str)
Definition Semver.hpp:58
static EIGEN_DEVICE_FUNC const Transform Identity()
Returns an identity transformation.
Definition Transform.h:539
Transform3d transform3d_from_string(const std::string &transform_str)
Definition Geometry.cpp:679
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:81
Eigen::Matrix< int, 3, 1, Eigen::DontAlign > Vec3i
Definition Point.hpp:40
int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit)
Definition TriangleMesh.cpp:765
IGL_INLINE void volume(const Eigen::MatrixBase< DerivedV > &V, const Eigen::MatrixBase< DerivedT > &T, Eigen::PlainObjectBase< Derivedvol > &vol)
Definition volume.cpp:15
Definition stl.h:157
std::vector< stl_vertex > vertices
Definition stl.h:165
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164

References Slic3r::_3MF_Importer::Geometry::custom_seam, Slic3r::_3MF_Importer::Geometry::custom_supports, Slic3r::TriangleMesh::flip_triangles(), indexed_triangle_set::indices, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::isApprox(), Slic3r::its_compactify_vertices(), MATRIX_KEY, Slic3r::_3MF_Importer::Geometry::mmu_segmentation, MODIFIER_KEY, NAME_KEY, SOURCE_FILE_KEY, SOURCE_IN_INCHES_KEY, SOURCE_IN_METERS_KEY, SOURCE_IS_BUILTIN_VOLUME_KEY, SOURCE_OBJECT_ID_KEY, SOURCE_OFFSET_X_KEY, SOURCE_OFFSET_Y_KEY, SOURCE_OFFSET_Z_KEY, SOURCE_VOLUME_ID_KEY, Slic3r::TriangleMesh::transform(), Slic3r::Geometry::transform3d_from_string(), Slic3r::_3MF_Importer::Geometry::triangles, indexed_triangle_set::vertices, Slic3r::_3MF_Importer::Geometry::vertices, Slic3r::TriangleMesh::volume(), and VOLUME_TYPE_KEY.

Referenced by _load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _handle_end_build()

bool Slic3r::_3MF_Importer::_handle_end_build ( )
private
1827 {
1828 // do nothing
1829 return true;
1830 }

◆ _handle_end_component()

bool Slic3r::_3MF_Importer::_handle_end_component ( )
private
1815 {
1816 // do nothing
1817 return true;
1818 }

◆ _handle_end_components()

bool Slic3r::_3MF_Importer::_handle_end_components ( )
private
1790 {
1791 // do nothing
1792 return true;
1793 }

◆ _handle_end_config()

bool Slic3r::_3MF_Importer::_handle_end_config ( )
private
2010 {
2011 // do nothing
2012 return true;
2013 }

◆ _handle_end_config_metadata()

bool Slic3r::_3MF_Importer::_handle_end_config_metadata ( )
private
2119 {
2120 // do nothing
2121 return true;
2122 }

◆ _handle_end_config_object()

bool Slic3r::_3MF_Importer::_handle_end_config_object ( )
private
2033 {
2034 // do nothing
2035 return true;
2036 }

◆ _handle_end_config_volume()

bool Slic3r::_3MF_Importer::_handle_end_config_volume ( )
private
2081 {
2082 // do nothing
2083 return true;
2084 }

◆ _handle_end_config_volume_mesh()

bool Slic3r::_3MF_Importer::_handle_end_config_volume_mesh ( )
private
2087 {
2088 // do nothing
2089 return true;
2090 }

◆ _handle_end_config_xml_element() [1/2]

void Slic3r::_3MF_Importer::_handle_end_config_xml_element ( const char *  name)
private
1563 {
1564 if (m_xml_parser == nullptr)
1565 return;
1566
1567 bool res = true;
1568
1569 if (::strcmp(CONFIG_TAG, name) == 0)
1570 res = _handle_end_config();
1571 else if (::strcmp(OBJECT_TAG, name) == 0)
1573 else if (::strcmp(VOLUME_TAG, name) == 0)
1575 else if (::strcmp(MESH_TAG, name) == 0)
1577 else if (::strcmp(METADATA_TAG, name) == 0)
1579
1580 if (!res)
1582 }
static constexpr const char * VOLUME_TAG
Definition 3mf.cpp:100
static constexpr const char * MESH_TAG
Definition 3mf.cpp:88
static constexpr const char * CONFIG_TAG
Definition 3mf.cpp:99
static constexpr const char * METADATA_TAG
Definition 3mf.cpp:97
static constexpr const char * OBJECT_TAG
Definition 3mf.cpp:87
bool _handle_end_config_volume_mesh()
Definition 3mf.cpp:2086
bool _handle_end_config_metadata()
Definition 3mf.cpp:2118
void _stop_xml_parser(const std::string &msg=std::string())
Definition 3mf.cpp:656
bool _handle_end_config()
Definition 3mf.cpp:2009
bool _handle_end_config_volume()
Definition 3mf.cpp:2080
bool _handle_end_config_object()
Definition 3mf.cpp:2032

References CONFIG_TAG, MESH_TAG, METADATA_TAG, OBJECT_TAG, and VOLUME_TAG.

Referenced by _handle_end_config_xml_element().

+ Here is the caller graph for this function:

◆ _handle_end_config_xml_element() [2/2]

void XMLCALL Slic3r::_3MF_Importer::_handle_end_config_xml_element ( void userData,
const char *  name 
)
staticprivate
2315 {
2316 _3MF_Importer* importer = (_3MF_Importer*)userData;
2317 if (importer != nullptr)
2318 importer->_handle_end_config_xml_element(name);
2319 }
_3MF_Importer()
Definition 3mf.cpp:604

References _handle_end_config_xml_element().

+ Here is the call graph for this function:

◆ _handle_end_item()

bool Slic3r::_3MF_Importer::_handle_end_item ( )
private
1849 {
1850 // do nothing
1851 return true;
1852 }

◆ _handle_end_mesh()

bool Slic3r::_3MF_Importer::_handle_end_mesh ( )
private
1706 {
1707 // do nothing
1708 return true;
1709 }

◆ _handle_end_metadata()

bool Slic3r::_3MF_Importer::_handle_end_metadata ( )
private
1872 {
1874 m_version = (unsigned int)atoi(m_curr_characters.c_str());
1876 // std::string msg = _u8L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.");
1877 // throw version_error(msg.c_str());
1878 const std::string msg = (boost::format(_u8L("The selected 3mf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str();
1879 throw version_error(msg);
1880 }
1881 } else if (m_curr_metadata_name == "Application") {
1882 // Generator application of the 3MF.
1883 // SLIC3R_APP_KEY - SLIC3R_VERSION
1884 if (boost::starts_with(m_curr_characters, "PrusaSlicer-"))
1887 m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
1889 _u8L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."));
1891 m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
1893 _u8L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."));
1895 m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
1897 _u8L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."));
1898 }
1899
1900 return true;
1901 }
const unsigned int SEAM_PAINTING_VERSION
Definition 3mf.cpp:63
const unsigned int VERSION_3MF_COMPATIBLE
Definition 3mf.cpp:56
const std::string SLIC3RPE_SEAM_PAINTING_VERSION
Definition 3mf.cpp:67
const std::string SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION
Definition 3mf.cpp:66
const unsigned int FDM_SUPPORTS_PAINTING_VERSION
Definition 3mf.cpp:62
const std::string SLIC3RPE_MM_PAINTING_VERSION
Definition 3mf.cpp:68
const unsigned int MM_PAINTING_VERSION
Definition 3mf.cpp:64
const char * SLIC3RPE_3MF_VERSION
Definition 3mf.cpp:57
#define _u8L(s)
macro used to mark string used at localization, return same string
Definition SLAPrint.cpp:29
unsigned int m_fdm_supports_painting_version
Definition 3mf.cpp:463
unsigned int m_seam_painting_version
Definition 3mf.cpp:464
unsigned int m_mm_painting_version
Definition 3mf.cpp:465
static void check_painting_version(unsigned int loaded_version, unsigned int highest_supported_version, const std::string &error_msg)
Definition 3mf.cpp:1865

References _u8L, Slic3r::check_painting_version(), FDM_SUPPORTS_PAINTING_VERSION, MM_PAINTING_VERSION, SEAM_PAINTING_VERSION, SLIC3RPE_3MF_VERSION, SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION, SLIC3RPE_MM_PAINTING_VERSION, SLIC3RPE_SEAM_PAINTING_VERSION, and VERSION_3MF_COMPATIBLE.

+ Here is the call graph for this function:

◆ _handle_end_model()

bool Slic3r::_3MF_Importer::_handle_end_model ( )
private
1591 {
1592 // deletes all non-built or non-instanced objects
1593 for (const IdToModelObjectMap::value_type& object : m_objects) {
1594 if (object.second >= int(m_model->objects.size())) {
1595 add_error("Unable to find object");
1596 return false;
1597 }
1598 ModelObject *model_object = m_model->objects[object.second];
1599 if (model_object != nullptr && model_object->instances.size() == 0)
1600 m_model->delete_object(model_object);
1601 }
1602
1603 if (m_version == 0) {
1604 // if the 3mf was not produced by PrusaSlicer and there is only one object,
1605 // set the object name to match the filename
1606 if (m_model->objects.size() == 1)
1607 m_model->objects.front()->name = m_name;
1608 }
1609
1610 // applies instances' matrices
1611 for (Instance& instance : m_instances) {
1612 if (instance.instance != nullptr && instance.instance->get_object() != nullptr)
1613 // apply the transform to the instance
1614 _apply_transform(*instance.instance, instance.transform);
1615 }
1616
1617 return true;
1618 }
void _apply_transform(ModelInstance &instance, const Transform3d &transform)
Definition 3mf.cpp:1993
void delete_object(size_t idx)
Definition Model.cpp:233

References Slic3r::Model::delete_object(), Slic3r::ModelObject::instances, and Slic3r::Model::objects.

+ Here is the call graph for this function:

◆ _handle_end_model_xml_element() [1/2]

void Slic3r::_3MF_Importer::_handle_end_model_xml_element ( const char *  name)
private
1495 {
1496 if (m_xml_parser == nullptr)
1497 return;
1498
1499 bool res = true;
1500
1501 if (::strcmp(MODEL_TAG, name) == 0)
1502 res = _handle_end_model();
1503 else if (::strcmp(RESOURCES_TAG, name) == 0)
1504 res = _handle_end_resources();
1505 else if (::strcmp(OBJECT_TAG, name) == 0)
1506 res = _handle_end_object();
1507 else if (::strcmp(MESH_TAG, name) == 0)
1508 res = _handle_end_mesh();
1509 else if (::strcmp(VERTICES_TAG, name) == 0)
1510 res = _handle_end_vertices();
1511 else if (::strcmp(VERTEX_TAG, name) == 0)
1512 res = _handle_end_vertex();
1513 else if (::strcmp(TRIANGLES_TAG, name) == 0)
1514 res = _handle_end_triangles();
1515 else if (::strcmp(TRIANGLE_TAG, name) == 0)
1516 res = _handle_end_triangle();
1517 else if (::strcmp(COMPONENTS_TAG, name) == 0)
1518 res = _handle_end_components();
1519 else if (::strcmp(COMPONENT_TAG, name) == 0)
1520 res = _handle_end_component();
1521 else if (::strcmp(BUILD_TAG, name) == 0)
1522 res = _handle_end_build();
1523 else if (::strcmp(ITEM_TAG, name) == 0)
1524 res = _handle_end_item();
1525 else if (::strcmp(METADATA_TAG, name) == 0)
1526 res = _handle_end_metadata();
1527
1528 if (!res)
1530 }
static constexpr const char * BUILD_TAG
Definition 3mf.cpp:95
static constexpr const char * TRIANGLES_TAG
Definition 3mf.cpp:91
static constexpr const char * RESOURCES_TAG
Definition 3mf.cpp:86
static constexpr const char * VERTEX_TAG
Definition 3mf.cpp:90
static constexpr const char * ITEM_TAG
Definition 3mf.cpp:96
static constexpr const char * COMPONENTS_TAG
Definition 3mf.cpp:93
static constexpr const char * COMPONENT_TAG
Definition 3mf.cpp:94
static constexpr const char * MODEL_TAG
Definition 3mf.cpp:85
static constexpr const char * VERTICES_TAG
Definition 3mf.cpp:89
static constexpr const char * TRIANGLE_TAG
Definition 3mf.cpp:92
bool _handle_end_resources()
Definition 3mf.cpp:1626
bool _handle_end_build()
Definition 3mf.cpp:1826
bool _handle_end_component()
Definition 3mf.cpp:1814
bool _handle_end_metadata()
Definition 3mf.cpp:1871
bool _handle_end_vertex()
Definition 3mf.cpp:1735
bool _handle_end_item()
Definition 3mf.cpp:1848
bool _handle_end_components()
Definition 3mf.cpp:1789
bool _handle_end_object()
Definition 3mf.cpp:1657
bool _handle_end_vertices()
Definition 3mf.cpp:1718
bool _handle_end_triangles()
Definition 3mf.cpp:1748
bool _handle_end_triangle()
Definition 3mf.cpp:1776
bool _handle_end_model()
Definition 3mf.cpp:1590
bool _handle_end_mesh()
Definition 3mf.cpp:1705

References BUILD_TAG, COMPONENT_TAG, COMPONENTS_TAG, ITEM_TAG, MESH_TAG, METADATA_TAG, MODEL_TAG, OBJECT_TAG, RESOURCES_TAG, TRIANGLE_TAG, TRIANGLES_TAG, VERTEX_TAG, and VERTICES_TAG.

Referenced by _extract_model_from_archive(), and _handle_end_model_xml_element().

+ Here is the caller graph for this function:

◆ _handle_end_model_xml_element() [2/2]

void XMLCALL Slic3r::_3MF_Importer::_handle_end_model_xml_element ( void userData,
const char *  name 
)
staticprivate
2294 {
2295 _3MF_Importer* importer = (_3MF_Importer*)userData;
2296 if (importer != nullptr)
2297 importer->_handle_end_model_xml_element(name);
2298 }

References _handle_end_model_xml_element().

+ Here is the call graph for this function:

◆ _handle_end_object()

bool Slic3r::_3MF_Importer::_handle_end_object ( )
private
1658 {
1659 if (m_curr_object.object != nullptr) {
1661 // no geometry defined
1662 // remove the object from the model
1664
1665 if (m_curr_object.components.empty()) {
1666 // no components defined -> invalid object, delete it
1667 IdToModelObjectMap::iterator object_item = m_objects.find(m_curr_object.id);
1668 if (object_item != m_objects.end())
1669 m_objects.erase(object_item);
1670
1671 IdToAliasesMap::iterator alias_item = m_objects_aliases.find(m_curr_object.id);
1672 if (alias_item != m_objects_aliases.end())
1673 m_objects_aliases.erase(alias_item);
1674 }
1675 else
1676 // adds components to aliases
1678 }
1679 else {
1680 // geometry defined, store it for later use
1681 m_geometries.insert({ m_curr_object.id, std::move(m_curr_object.geometry) });
1682
1683 // stores the object for later use
1684 if (m_objects.find(m_curr_object.id) == m_objects.end()) {
1686 m_objects_aliases.insert({ m_curr_object.id, { 1, Component(m_curr_object.id) } }); // aliases itself
1687 }
1688 else {
1689 add_error("Found object with duplicate id");
1690 return false;
1691 }
1692 }
1693 }
1694
1695 return true;
1696 }
IdToGeometryMap m_geometries
Definition 3mf.cpp:478
CurrentObject m_curr_object
Definition 3mf.cpp:474
int id
Definition 3mf.cpp:360
int model_object_idx
Definition 3mf.cpp:362
ModelObject * object
Definition 3mf.cpp:364
ComponentsList components
Definition 3mf.cpp:365
Geometry geometry
Definition 3mf.cpp:363
bool empty()
Definition 3mf.cpp:346

References Slic3r::_3MF_Importer::CurrentObject::components, Slic3r::Model::delete_object(), Slic3r::_3MF_Importer::Geometry::empty(), Slic3r::_3MF_Importer::CurrentObject::geometry, Slic3r::_3MF_Importer::CurrentObject::id, Slic3r::_3MF_Importer::CurrentObject::model_object_idx, and Slic3r::_3MF_Importer::CurrentObject::object.

+ Here is the call graph for this function:

◆ _handle_end_resources()

bool Slic3r::_3MF_Importer::_handle_end_resources ( )
private
1627 {
1628 // do nothing
1629 return true;
1630 }

◆ _handle_end_triangle()

bool Slic3r::_3MF_Importer::_handle_end_triangle ( )
private
1777 {
1778 // do nothing
1779 return true;
1780 }

◆ _handle_end_triangles()

bool Slic3r::_3MF_Importer::_handle_end_triangles ( )
private
1749 {
1750 // do nothing
1751 return true;
1752 }

◆ _handle_end_vertex()

bool Slic3r::_3MF_Importer::_handle_end_vertex ( )
private
1736 {
1737 // do nothing
1738 return true;
1739 }

◆ _handle_end_vertices()

bool Slic3r::_3MF_Importer::_handle_end_vertices ( )
private
1719 {
1720 // do nothing
1721 return true;
1722 }

◆ _handle_model_xml_characters() [1/2]

void Slic3r::_3MF_Importer::_handle_model_xml_characters ( const XML_Char *  s,
int  len 
)
private
1533 {
1534 m_curr_characters.append(s, len);
1535 }

Referenced by _extract_model_from_archive(), and _handle_model_xml_characters().

+ Here is the caller graph for this function:

◆ _handle_model_xml_characters() [2/2]

void XMLCALL Slic3r::_3MF_Importer::_handle_model_xml_characters ( void userData,
const XML_Char *  s,
int  len 
)
staticprivate
2301 {
2302 _3MF_Importer* importer = (_3MF_Importer*)userData;
2303 if (importer != nullptr)
2304 importer->_handle_model_xml_characters(s, len);
2305 }

References _handle_model_xml_characters().

+ Here is the call graph for this function:

◆ _handle_start_build()

bool Slic3r::_3MF_Importer::_handle_start_build ( const char **  attributes,
unsigned int  num_attributes 
)
private
1821 {
1822 // do nothing
1823 return true;
1824 }

◆ _handle_start_component()

bool Slic3r::_3MF_Importer::_handle_start_component ( const char **  attributes,
unsigned int  num_attributes 
)
private
1796 {
1797 int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
1799
1800 IdToModelObjectMap::iterator object_item = m_objects.find(object_id);
1801 if (object_item == m_objects.end()) {
1802 IdToAliasesMap::iterator alias_item = m_objects_aliases.find(object_id);
1803 if (alias_item == m_objects_aliases.end()) {
1804 add_error("Found component with invalid object id");
1805 return false;
1806 }
1807 }
1808
1809 m_curr_object.components.emplace_back(object_id, transform);
1810
1811 return true;
1812 }
int get_attribute_value_int(const char **attributes, unsigned int attributes_size, const char *attribute_key)
Definition 3mf.cpp:221
Slic3r::Transform3d get_transform_from_3mf_specs_string(const std::string &mat_str)
Definition 3mf.cpp:235
std::string get_attribute_value_string(const char **attributes, unsigned int attributes_size, const char *attribute_key)
Definition 3mf.cpp:207
static constexpr const char * TRANSFORM_ATTR
Definition 3mf.cpp:113
static constexpr const char * OBJECTID_ATTR
Definition 3mf.cpp:112

References Slic3r::_3MF_Importer::CurrentObject::components, get_attribute_value_int(), get_attribute_value_string(), get_transform_from_3mf_specs_string(), OBJECTID_ATTR, and TRANSFORM_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_components()

bool Slic3r::_3MF_Importer::_handle_start_components ( const char **  attributes,
unsigned int  num_attributes 
)
private
1783 {
1784 // reset current components
1785 m_curr_object.components.clear();
1786 return true;
1787 }

References Slic3r::_3MF_Importer::CurrentObject::components.

◆ _handle_start_config()

bool Slic3r::_3MF_Importer::_handle_start_config ( const char **  attributes,
unsigned int  num_attributes 
)
private
2004 {
2005 // do nothing
2006 return true;
2007 }

◆ _handle_start_config_metadata()

bool Slic3r::_3MF_Importer::_handle_start_config_metadata ( const char **  attributes,
unsigned int  num_attributes 
)
private
2093 {
2094 IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
2095 if (object == m_objects_metadata.end()) {
2096 add_error("Cannot assign metadata to valid object id");
2097 return false;
2098 }
2099
2100 std::string type = get_attribute_value_string(attributes, num_attributes, TYPE_ATTR);
2101 std::string key = get_attribute_value_string(attributes, num_attributes, KEY_ATTR);
2102 std::string value = get_attribute_value_string(attributes, num_attributes, VALUE_ATTR);
2103
2104 if (type == OBJECT_TYPE)
2105 object->second.metadata.emplace_back(key, value);
2106 else if (type == VOLUME_TYPE) {
2107 if (size_t(m_curr_config.volume_id) < object->second.volumes.size())
2108 object->second.volumes[m_curr_config.volume_id].metadata.emplace_back(key, value);
2109 }
2110 else {
2111 add_error("Found invalid metadata type");
2112 return false;
2113 }
2114
2115 return true;
2116 }
static constexpr const char * VOLUME_TYPE
Definition 3mf.cpp:126
static constexpr const char * OBJECT_TYPE
Definition 3mf.cpp:125
static constexpr const char * VALUE_ATTR
Definition 3mf.cpp:121
static constexpr const char * TYPE_ATTR
Definition 3mf.cpp:104
static constexpr const char * KEY_ATTR
Definition 3mf.cpp:120
IdToMetadataMap m_objects_metadata
Definition 3mf.cpp:480
int volume_id
Definition 3mf.cpp:381
int object_id
Definition 3mf.cpp:380
CurrentConfig m_curr_config
Definition 3mf.cpp:479

References get_attribute_value_string(), KEY_ATTR, Slic3r::_3MF_Importer::CurrentConfig::object_id, OBJECT_TYPE, TYPE_ATTR, VALUE_ATTR, Slic3r::_3MF_Importer::CurrentConfig::volume_id, and VOLUME_TYPE.

+ Here is the call graph for this function:

◆ _handle_start_config_object()

bool Slic3r::_3MF_Importer::_handle_start_config_object ( const char **  attributes,
unsigned int  num_attributes 
)
private
2016 {
2017 int object_id = get_attribute_value_int(attributes, num_attributes, ID_ATTR);
2018 IdToMetadataMap::iterator object_item = m_objects_metadata.find(object_id);
2019 if (object_item != m_objects_metadata.end()) {
2020 add_error("Found duplicated object id");
2021 return false;
2022 }
2023
2024 // Added because of github #3435, currently not used by PrusaSlicer
2025 // int instances_count_id = get_attribute_value_int(attributes, num_attributes, INSTANCESCOUNT_ATTR);
2026
2027 m_objects_metadata.insert({ object_id, ObjectMetadata() });
2028 m_curr_config.object_id = object_id;
2029 return true;
2030 }
static constexpr const char * ID_ATTR
Definition 3mf.cpp:105

References get_attribute_value_int(), ID_ATTR, and Slic3r::_3MF_Importer::CurrentConfig::object_id.

+ Here is the call graph for this function:

◆ _handle_start_config_volume()

bool Slic3r::_3MF_Importer::_handle_start_config_volume ( const char **  attributes,
unsigned int  num_attributes 
)
private
2039 {
2040 IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
2041 if (object == m_objects_metadata.end()) {
2042 add_error("Cannot assign volume to a valid object");
2043 return false;
2044 }
2045
2046 m_curr_config.volume_id = (int)object->second.volumes.size();
2047
2048 unsigned int first_triangle_id = (unsigned int)get_attribute_value_int(attributes, num_attributes, FIRST_TRIANGLE_ID_ATTR);
2049 unsigned int last_triangle_id = (unsigned int)get_attribute_value_int(attributes, num_attributes, LAST_TRIANGLE_ID_ATTR);
2050
2051 object->second.volumes.emplace_back(first_triangle_id, last_triangle_id);
2052 return true;
2053 }
static constexpr const char * FIRST_TRIANGLE_ID_ATTR
Definition 3mf.cpp:122
static constexpr const char * LAST_TRIANGLE_ID_ATTR
Definition 3mf.cpp:123

References FIRST_TRIANGLE_ID_ATTR, get_attribute_value_int(), LAST_TRIANGLE_ID_ATTR, Slic3r::_3MF_Importer::CurrentConfig::object_id, and Slic3r::_3MF_Importer::CurrentConfig::volume_id.

+ Here is the call graph for this function:

◆ _handle_start_config_volume_mesh()

bool Slic3r::_3MF_Importer::_handle_start_config_volume_mesh ( const char **  attributes,
unsigned int  num_attributes 
)
private
2056 {
2057 IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
2058 if (object == m_objects_metadata.end()) {
2059 add_error("Cannot assign volume mesh to a valid object");
2060 return false;
2061 }
2062 if (object->second.volumes.empty()) {
2063 add_error("Cannot assign mesh to a valid volume");
2064 return false;
2065 }
2066
2067 ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back();
2068
2069 int edges_fixed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_EDGES_FIXED );
2070 int degenerate_facets = get_attribute_value_int(attributes, num_attributes, MESH_STAT_DEGENERATED_FACETS);
2071 int facets_removed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_REMOVED );
2072 int facets_reversed = get_attribute_value_int(attributes, num_attributes, MESH_STAT_FACETS_RESERVED );
2073 int backwards_edges = get_attribute_value_int(attributes, num_attributes, MESH_STAT_BACKWARDS_EDGES );
2074
2075 volume.mesh_stats = { edges_fixed, degenerate_facets, facets_removed, facets_reversed, backwards_edges };
2076
2077 return true;
2078 }
static constexpr const char * MESH_STAT_BACKWARDS_EDGES
Definition 3mf.cpp:146
static constexpr const char * MESH_STAT_EDGES_FIXED
Definition 3mf.cpp:142
static constexpr const char * MESH_STAT_FACETS_RESERVED
Definition 3mf.cpp:145
static constexpr const char * MESH_STAT_FACETS_REMOVED
Definition 3mf.cpp:144
static constexpr const char * MESH_STAT_DEGENERATED_FACETS
Definition 3mf.cpp:143

References get_attribute_value_int(), MESH_STAT_BACKWARDS_EDGES, MESH_STAT_DEGENERATED_FACETS, MESH_STAT_EDGES_FIXED, MESH_STAT_FACETS_REMOVED, MESH_STAT_FACETS_RESERVED, and Slic3r::_3MF_Importer::CurrentConfig::object_id.

+ Here is the call graph for this function:

◆ _handle_start_config_xml_element() [1/2]

void Slic3r::_3MF_Importer::_handle_start_config_xml_element ( const char *  name,
const char **  attributes 
)
private
1538 {
1539 if (m_xml_parser == nullptr)
1540 return;
1541
1542 bool res = true;
1543 unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(m_xml_parser);
1544
1545 if (::strcmp(CONFIG_TAG, name) == 0)
1546 res = _handle_start_config(attributes, num_attributes);
1547 else if (::strcmp(OBJECT_TAG, name) == 0)
1548 res = _handle_start_config_object(attributes, num_attributes);
1549 else if (::strcmp(VOLUME_TAG, name) == 0)
1550 res = _handle_start_config_volume(attributes, num_attributes);
1551 else if (::strcmp(MESH_TAG, name) == 0)
1552 res = _handle_start_config_volume_mesh(attributes, num_attributes);
1553 else if (::strcmp(METADATA_TAG, name) == 0)
1554 res = _handle_start_config_metadata(attributes, num_attributes);
1555 else if (::strcmp(TEXT_TAG, name) == 0)
1556 res = _handle_start_text_configuration(attributes, num_attributes);
1557
1558 if (!res)
1560 }
static constexpr const char * TEXT_TAG
Definition 3mf.cpp:149
bool _handle_start_config_object(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:2015
bool _handle_start_config_volume_mesh(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:2055
bool _handle_start_text_configuration(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1931
bool _handle_start_config(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:2003
bool _handle_start_config_metadata(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:2092
bool _handle_start_config_volume(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:2038

References CONFIG_TAG, MESH_TAG, METADATA_TAG, OBJECT_TAG, TEXT_TAG, and VOLUME_TAG.

Referenced by _handle_start_config_xml_element().

+ Here is the caller graph for this function:

◆ _handle_start_config_xml_element() [2/2]

void XMLCALL Slic3r::_3MF_Importer::_handle_start_config_xml_element ( void userData,
const char *  name,
const char **  attributes 
)
staticprivate
2308 {
2309 _3MF_Importer* importer = (_3MF_Importer*)userData;
2310 if (importer != nullptr)
2311 importer->_handle_start_config_xml_element(name, attributes);
2312 }

References _handle_start_config_xml_element().

+ Here is the call graph for this function:

◆ _handle_start_item()

bool Slic3r::_3MF_Importer::_handle_start_item ( const char **  attributes,
unsigned int  num_attributes 
)
private
1833 {
1834 // we are ignoring the following attributes
1835 // thumbnail
1836 // partnumber
1837 // pid
1838 // pindex
1839 // see specifications
1840
1841 int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
1843 int printable = get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR);
1844
1845 return _create_object_instance(object_id, transform, printable, 1);
1846 }
bool get_attribute_value_bool(const char **attributes, unsigned int attributes_size, const char *attribute_key)
Definition 3mf.cpp:229
static constexpr const char * PRINTABLE_ATTR
Definition 3mf.cpp:114

References get_attribute_value_bool(), get_attribute_value_int(), get_attribute_value_string(), get_transform_from_3mf_specs_string(), OBJECTID_ATTR, PRINTABLE_ATTR, and TRANSFORM_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_mesh()

bool Slic3r::_3MF_Importer::_handle_start_mesh ( const char **  attributes,
unsigned int  num_attributes 
)
private
1699 {
1700 // reset current geometry
1702 return true;
1703 }
void reset()
Definition 3mf.cpp:348

References Slic3r::_3MF_Importer::CurrentObject::geometry, and Slic3r::_3MF_Importer::Geometry::reset().

+ Here is the call graph for this function:

◆ _handle_start_metadata()

bool Slic3r::_3MF_Importer::_handle_start_metadata ( const char **  attributes,
unsigned int  num_attributes 
)
private
1855 {
1856 m_curr_characters.clear();
1857
1858 std::string name = get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
1859 if (!name.empty())
1860 m_curr_metadata_name = name;
1861
1862 return true;
1863 }
static constexpr const char * NAME_ATTR
Definition 3mf.cpp:103

References get_attribute_value_string(), and NAME_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_model()

bool Slic3r::_3MF_Importer::_handle_start_model ( const char **  attributes,
unsigned int  num_attributes 
)
private
1585 {
1586 m_unit_factor = get_unit_factor(get_attribute_value_string(attributes, num_attributes, UNIT_ATTR));
1587 return true;
1588 }
static constexpr const char * UNIT_ATTR
Definition 3mf.cpp:102
float get_unit_factor(const std::string &unit)
Definition 3mf.cpp:264

References get_attribute_value_string(), get_unit_factor(), and UNIT_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_model_xml_element() [1/2]

void Slic3r::_3MF_Importer::_handle_start_model_xml_element ( const char *  name,
const char **  attributes 
)
private
1456 {
1457 if (m_xml_parser == nullptr)
1458 return;
1459
1460 bool res = true;
1461 unsigned int num_attributes = (unsigned int)XML_GetSpecifiedAttributeCount(m_xml_parser);
1462
1463 if (::strcmp(MODEL_TAG, name) == 0)
1464 res = _handle_start_model(attributes, num_attributes);
1465 else if (::strcmp(RESOURCES_TAG, name) == 0)
1466 res = _handle_start_resources(attributes, num_attributes);
1467 else if (::strcmp(OBJECT_TAG, name) == 0)
1468 res = _handle_start_object(attributes, num_attributes);
1469 else if (::strcmp(MESH_TAG, name) == 0)
1470 res = _handle_start_mesh(attributes, num_attributes);
1471 else if (::strcmp(VERTICES_TAG, name) == 0)
1472 res = _handle_start_vertices(attributes, num_attributes);
1473 else if (::strcmp(VERTEX_TAG, name) == 0)
1474 res = _handle_start_vertex(attributes, num_attributes);
1475 else if (::strcmp(TRIANGLES_TAG, name) == 0)
1476 res = _handle_start_triangles(attributes, num_attributes);
1477 else if (::strcmp(TRIANGLE_TAG, name) == 0)
1478 res = _handle_start_triangle(attributes, num_attributes);
1479 else if (::strcmp(COMPONENTS_TAG, name) == 0)
1480 res = _handle_start_components(attributes, num_attributes);
1481 else if (::strcmp(COMPONENT_TAG, name) == 0)
1482 res = _handle_start_component(attributes, num_attributes);
1483 else if (::strcmp(BUILD_TAG, name) == 0)
1484 res = _handle_start_build(attributes, num_attributes);
1485 else if (::strcmp(ITEM_TAG, name) == 0)
1486 res = _handle_start_item(attributes, num_attributes);
1487 else if (::strcmp(METADATA_TAG, name) == 0)
1488 res = _handle_start_metadata(attributes, num_attributes);
1489
1490 if (!res)
1492 }
bool _handle_start_build(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1820
bool _handle_start_mesh(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1698
bool _handle_start_component(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1795
bool _handle_start_object(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1632
bool _handle_start_resources(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1620
bool _handle_start_vertices(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1711
bool _handle_start_item(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1832
bool _handle_start_model(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1584
bool _handle_start_triangle(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1754
bool _handle_start_vertex(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1724
bool _handle_start_metadata(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1854
bool _handle_start_triangles(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1741
bool _handle_start_components(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:1782

References BUILD_TAG, COMPONENT_TAG, COMPONENTS_TAG, ITEM_TAG, MESH_TAG, METADATA_TAG, MODEL_TAG, OBJECT_TAG, RESOURCES_TAG, TRIANGLE_TAG, TRIANGLES_TAG, VERTEX_TAG, and VERTICES_TAG.

Referenced by _extract_model_from_archive(), and _handle_start_model_xml_element().

+ Here is the caller graph for this function:

◆ _handle_start_model_xml_element() [2/2]

void XMLCALL Slic3r::_3MF_Importer::_handle_start_model_xml_element ( void userData,
const char *  name,
const char **  attributes 
)
staticprivate
2287 {
2288 _3MF_Importer* importer = (_3MF_Importer*)userData;
2289 if (importer != nullptr)
2290 importer->_handle_start_model_xml_element(name, attributes);
2291 }

References _handle_start_model_xml_element().

+ Here is the call graph for this function:

◆ _handle_start_object()

bool Slic3r::_3MF_Importer::_handle_start_object ( const char **  attributes,
unsigned int  num_attributes 
)
private
1633 {
1634 // reset current data
1636
1637 if (is_valid_object_type(get_attribute_value_string(attributes, num_attributes, TYPE_ATTR))) {
1638 // create new object (it may be removed later if no instances are generated from it)
1641 if (m_curr_object.object == nullptr) {
1642 add_error("Unable to create object");
1643 return false;
1644 }
1645
1646 // set object data
1647 m_curr_object.object->name = get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
1648 if (m_curr_object.object->name.empty())
1649 m_curr_object.object->name = m_name + "_" + std::to_string(m_model->objects.size());
1650
1651 m_curr_object.id = get_attribute_value_int(attributes, num_attributes, ID_ATTR);
1652 }
1653
1654 return true;
1655 }
bool is_valid_object_type(const std::string &type)
Definition 3mf.cpp:283
ModelObject * add_object()
Definition Model.cpp:189
std::string name
Definition Model.hpp:330
void reset()
Definition 3mf.cpp:369

References Slic3r::Model::add_object(), get_attribute_value_int(), get_attribute_value_string(), Slic3r::_3MF_Importer::CurrentObject::id, ID_ATTR, is_valid_object_type(), Slic3r::_3MF_Importer::CurrentObject::model_object_idx, Slic3r::ModelObject::name, NAME_ATTR, Slic3r::_3MF_Importer::CurrentObject::object, Slic3r::Model::objects, Slic3r::_3MF_Importer::CurrentObject::reset(), and TYPE_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_resources()

bool Slic3r::_3MF_Importer::_handle_start_resources ( const char **  attributes,
unsigned int  num_attributes 
)
private
1621 {
1622 // do nothing
1623 return true;
1624 }

◆ _handle_start_text_configuration()

bool Slic3r::_3MF_Importer::_handle_start_text_configuration ( const char **  attributes,
unsigned int  num_attributes 
)
private
1932 {
1933 IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
1934 if (object == m_objects_metadata.end()) {
1935 add_error("Cannot assign volume mesh to a valid object");
1936 return false;
1937 }
1938 if (object->second.volumes.empty()) {
1939 add_error("Cannot assign mesh to a valid volume");
1940 return false;
1941 }
1942 ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back();
1943 volume.text_configuration = TextConfigurationSerialization::read(attributes, num_attributes);
1944 return volume.text_configuration.has_value();
1945 }
static std::optional< TextConfiguration > read(const char **attributes, unsigned int num_attributes)
Definition 3mf.cpp:3591

References Slic3r::_3MF_Importer::CurrentConfig::object_id.

◆ _handle_start_triangle()

bool Slic3r::_3MF_Importer::_handle_start_triangle ( const char **  attributes,
unsigned int  num_attributes 
)
private
1755 {
1756 // we are ignoring the following attributes:
1757 // p1
1758 // p2
1759 // p3
1760 // pid
1761 // see specifications
1762
1763 // appends the triangle's vertices indices
1764 // missing values are set equal to ZERO
1765 m_curr_object.geometry.triangles.emplace_back(
1766 get_attribute_value_int(attributes, num_attributes, V1_ATTR),
1767 get_attribute_value_int(attributes, num_attributes, V2_ATTR),
1768 get_attribute_value_int(attributes, num_attributes, V3_ATTR));
1769
1771 m_curr_object.geometry.custom_seam.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
1773 return true;
1774 }
static constexpr const char * MMU_SEGMENTATION_ATTR
Definition 3mf.cpp:118
static constexpr const char * CUSTOM_SEAM_ATTR
Definition 3mf.cpp:117
static constexpr const char * CUSTOM_SUPPORTS_ATTR
Definition 3mf.cpp:116
static constexpr const char * V3_ATTR
Definition 3mf.cpp:111
static constexpr const char * V1_ATTR
Definition 3mf.cpp:109
static constexpr const char * V2_ATTR
Definition 3mf.cpp:110
std::vector< std::string > custom_supports
Definition 3mf.cpp:342
std::vector< std::string > custom_seam
Definition 3mf.cpp:343
std::vector< std::string > mmu_segmentation
Definition 3mf.cpp:344
std::vector< Vec3i > triangles
Definition 3mf.cpp:341

References Slic3r::_3MF_Importer::Geometry::custom_seam, CUSTOM_SEAM_ATTR, Slic3r::_3MF_Importer::Geometry::custom_supports, CUSTOM_SUPPORTS_ATTR, Slic3r::_3MF_Importer::CurrentObject::geometry, get_attribute_value_int(), get_attribute_value_string(), Slic3r::_3MF_Importer::Geometry::mmu_segmentation, MMU_SEGMENTATION_ATTR, Slic3r::_3MF_Importer::Geometry::triangles, V1_ATTR, V2_ATTR, and V3_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_triangles()

bool Slic3r::_3MF_Importer::_handle_start_triangles ( const char **  attributes,
unsigned int  num_attributes 
)
private
1742 {
1743 // reset current triangles
1745 return true;
1746 }

References Slic3r::_3MF_Importer::CurrentObject::geometry, and Slic3r::_3MF_Importer::Geometry::triangles.

◆ _handle_start_vertex()

bool Slic3r::_3MF_Importer::_handle_start_vertex ( const char **  attributes,
unsigned int  num_attributes 
)
private
1725 {
1726 // appends the vertex coordinates
1727 // missing values are set equal to ZERO
1728 m_curr_object.geometry.vertices.emplace_back(
1729 m_unit_factor * get_attribute_value_float(attributes, num_attributes, X_ATTR),
1730 m_unit_factor * get_attribute_value_float(attributes, num_attributes, Y_ATTR),
1731 m_unit_factor * get_attribute_value_float(attributes, num_attributes, Z_ATTR));
1732 return true;
1733 }
static constexpr const char * X_ATTR
Definition 3mf.cpp:106
static constexpr const char * Y_ATTR
Definition 3mf.cpp:107
static constexpr const char * Z_ATTR
Definition 3mf.cpp:108
float get_attribute_value_float(const char **attributes, unsigned int attributes_size, const char *attribute_key)
Definition 3mf.cpp:213
std::vector< Vec3f > vertices
Definition 3mf.cpp:340

References Slic3r::_3MF_Importer::CurrentObject::geometry, get_attribute_value_float(), Slic3r::_3MF_Importer::Geometry::vertices, X_ATTR, Y_ATTR, and Z_ATTR.

+ Here is the call graph for this function:

◆ _handle_start_vertices()

bool Slic3r::_3MF_Importer::_handle_start_vertices ( const char **  attributes,
unsigned int  num_attributes 
)
private
1712 {
1713 // reset current vertices
1715 return true;
1716 }

References Slic3r::_3MF_Importer::CurrentObject::geometry, and Slic3r::_3MF_Importer::Geometry::vertices.

◆ _load_model_from_file()

bool Slic3r::_3MF_Importer::_load_model_from_file ( const std::string &  filename,
Model model,
DynamicPrintConfig config,
ConfigSubstitutionContext config_substitutions 
)
private
667 {
668 mz_zip_archive archive;
669 mz_zip_zero_struct(&archive);
670
671 if (!open_zip_reader(&archive, filename)) {
672 add_error("Unable to open the file");
673 return false;
674 }
675
676 mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
677
679
680 m_name = boost::filesystem::path(filename).stem().string();
681
682 // we first loop the entries to read from the archive the .model file only, in order to extract the version from it
683 for (mz_uint i = 0; i < num_entries; ++i) {
684 if (mz_zip_reader_file_stat(&archive, i, &stat)) {
685 std::string name(stat.m_filename);
686 std::replace(name.begin(), name.end(), '\\', '/');
687
688 if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION)) {
689 try
690 {
691 // valid model name -> extract model
692 if (!_extract_model_from_archive(archive, stat)) {
693 close_zip_reader(&archive);
694 add_error("Archive does not contain a valid model");
695 return false;
696 }
697 }
698 catch (const std::exception& e)
699 {
700 // ensure the zip archive is closed and rethrow the exception
701 close_zip_reader(&archive);
702 throw Slic3r::FileIOError(e.what());
703 }
704 }
705 }
706 }
707
708 // we then loop again the entries to read other files stored in the archive
709 for (mz_uint i = 0; i < num_entries; ++i) {
710 if (mz_zip_reader_file_stat(&archive, i, &stat)) {
711 std::string name(stat.m_filename);
712 std::replace(name.begin(), name.end(), '\\', '/');
713
714 if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE)) {
715 // extract slic3r layer heights profile file
717 }
718 else if (boost::algorithm::iequals(name, CUT_INFORMATION_FILE)) {
719 // extract slic3r layer config ranges file
720 _extract_cut_information_from_archive(archive, stat, config_substitutions);
721 }
722 else if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) {
723 // extract slic3r layer config ranges file
724 _extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
725 }
726 else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE)) {
727 // extract sla support points file
729 }
730 else if (boost::algorithm::iequals(name, SLA_DRAIN_HOLES_FILE)) {
731 // extract sla support points file
733 }
734 else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE)) {
735 // extract slic3r print config file
736 _extract_print_config_from_archive(archive, stat, config, config_substitutions, filename);
737 }
738 else if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_PRINT_Z_FILE)) {
739 // extract slic3r layer config ranges file
741 }
742 else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE)) {
743 // extract slic3r model config file
744 if (!_extract_model_config_from_archive(archive, stat, model)) {
745 close_zip_reader(&archive);
746 add_error("Archive does not contain a valid model config");
747 return false;
748 }
749 }
750 }
751 }
752
753 close_zip_reader(&archive);
754
755 if (m_version == 0) {
756 // if the 3mf was not produced by PrusaSlicer and there is more than one instance,
757 // split the object in as many objects as instances
758 size_t curr_models_count = m_model->objects.size();
759 size_t i = 0;
760 while (i < curr_models_count) {
761 ModelObject* model_object = m_model->objects[i];
762 if (model_object->instances.size() > 1) {
763 // select the geometry associated with the original model object
764 const Geometry* geometry = nullptr;
765 for (const IdToModelObjectMap::value_type& object : m_objects) {
766 if (object.second == int(i)) {
767 IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
768 if (obj_geometry == m_geometries.end()) {
769 add_error("Unable to find object geometry");
770 return false;
771 }
772 geometry = &obj_geometry->second;
773 break;
774 }
775 }
776
777 if (geometry == nullptr) {
778 add_error("Unable to find object geometry");
779 return false;
780 }
781
782 // use the geometry to create the volumes in the new model objects
783 ObjectMetadata::VolumeMetadataList volumes(1, { 0, (unsigned int)geometry->triangles.size() - 1 });
784
785 // for each instance after the 1st, create a new model object containing only that instance
786 // and copy into it the geometry
787 while (model_object->instances.size() > 1) {
788 ModelObject* new_model_object = m_model->add_object(*model_object);
789 new_model_object->clear_instances();
790 new_model_object->add_instance(*model_object->instances.back());
791 model_object->delete_last_instance();
792 if (!_generate_volumes(*new_model_object, *geometry, volumes, config_substitutions))
793 return false;
794 }
795 }
796 ++i;
797 }
798 }
799
800 for (const IdToModelObjectMap::value_type& object : m_objects) {
801 if (object.second >= int(m_model->objects.size())) {
802 add_error("Unable to find object");
803 return false;
804 }
805 ModelObject* model_object = m_model->objects[object.second];
806 IdToGeometryMap::const_iterator obj_geometry = m_geometries.find(object.first);
807 if (obj_geometry == m_geometries.end()) {
808 add_error("Unable to find object geometry");
809 return false;
810 }
811
812 // m_layer_heights_profiles are indexed by a 1 based model object index.
813 IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1);
814 if (obj_layer_heights_profile != m_layer_heights_profiles.end())
815 model_object->layer_height_profile.set(std::move(obj_layer_heights_profile->second));
816
817 // m_layer_config_ranges are indexed by a 1 based model object index.
818 IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
819 if (obj_layer_config_ranges != m_layer_config_ranges.end())
820 model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second);
821
822 // m_sla_support_points are indexed by a 1 based model object index.
823 IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
824 if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
825 model_object->sla_support_points = std::move(obj_sla_support_points->second);
826 model_object->sla_points_status = sla::PointsStatus::UserModified;
827 }
828
829 IdToSlaDrainHolesMap::iterator obj_drain_holes = m_sla_drain_holes.find(object.second + 1);
830 if (obj_drain_holes != m_sla_drain_holes.end() && !obj_drain_holes->second.empty()) {
831 model_object->sla_drain_holes = std::move(obj_drain_holes->second);
832 }
833
835 ObjectMetadata::VolumeMetadataList* volumes_ptr = nullptr;
836
837 IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first);
838 if (obj_metadata != m_objects_metadata.end()) {
839 // config data has been found, this model was saved using slic3r pe
840
841 // apply object's name and config data
842 for (const Metadata& metadata : obj_metadata->second.metadata) {
843 if (metadata.key == "name")
844 model_object->name = metadata.value;
845 else
846 model_object->config.set_deserialize(metadata.key, metadata.value, config_substitutions);
847 }
848
849 // select object's detected volumes
850 volumes_ptr = &obj_metadata->second.volumes;
851 }
852 else {
853 // config data not found, this model was not saved using slic3r pe
854
855 // add the entire geometry as the single volume to generate
856 volumes.emplace_back(0, (int)obj_geometry->second.triangles.size() - 1);
857
858 // select as volumes
859 volumes_ptr = &volumes;
860 }
861
862 if (!_generate_volumes(*model_object, obj_geometry->second, *volumes_ptr, config_substitutions))
863 return false;
864
865 // Apply cut information for object if any was loaded
866 // m_cut_object_ids are indexed by a 1 based model object index.
867 IdToCutObjectInfoMap::iterator cut_object_info = m_cut_object_infos.find(object.second + 1);
868 if (cut_object_info != m_cut_object_infos.end()) {
869 model_object->cut_id = cut_object_info->second.id;
870 int vol_cnt = int(model_object->volumes.size());
871 for (auto connector : cut_object_info->second.connectors) {
872 if (connector.volume_id < 0 || connector.volume_id >= vol_cnt) {
873 add_error("Invalid connector is found");
874 continue;
875 }
876 model_object->volumes[connector.volume_id]->cut_info =
877 ModelVolume::CutInfo(CutConnectorType(connector.type), connector.r_tolerance, connector.h_tolerance, true);
878 }
879 }
880 }
881
882 // If instances contain a single volume, the volume offset should be 0,0,0
883 // This equals to say that instance world position and volume world position should match
884 // Correct all instances/volumes for which this does not hold
885 for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
886 ModelObject* o = model.objects[obj_id];
887 if (o->volumes.size() == 1) {
888 ModelVolume* v = o->volumes.front();
889 const Slic3r::Geometry::Transformation& first_inst_trafo = o->instances.front()->get_transformation();
890 const Vec3d world_vol_offset = (first_inst_trafo * v->get_transformation()).get_offset();
891 const Vec3d world_inst_offset = first_inst_trafo.get_offset();
892
893 if (!world_vol_offset.isApprox(world_inst_offset)) {
894 const Slic3r::Geometry::Transformation& vol_trafo = v->get_transformation();
895 for (int inst_id = 0; inst_id < int(o->instances.size()); ++inst_id) {
896 ModelInstance* i = o->instances[inst_id];
897 const Slic3r::Geometry::Transformation& inst_trafo = i->get_transformation();
898 i->set_offset((inst_trafo * vol_trafo).get_offset());
899 }
900 v->set_offset(Vec3d::Zero());
901 }
902 }
903 }
904
905 for (int obj_id = 0; obj_id < int(model.objects.size()); ++obj_id) {
906 ModelObject* o = model.objects[obj_id];
907 for (int vol_id = 0; vol_id < int(o->volumes.size()); ++vol_id) {
908 ModelVolume* v = o->volumes[vol_id];
909 if (v->source.input_file.empty())
910 v->source.input_file = filename;
911 if (v->source.volume_idx == -1)
912 v->source.volume_idx = vol_id;
913 if (v->source.object_idx == -1)
914 v->source.object_idx = obj_id;
915 }
916 }
917
918// // fixes the min z of the model if negative
919// model.adjust_min_z();
920
921 return true;
922 }
const std::string SLA_SUPPORT_POINTS_FILE
Definition 3mf.cpp:80
const std::string LAYER_HEIGHTS_PROFILE_FILE
Definition 3mf.cpp:78
const std::string LAYER_CONFIG_RANGES_FILE
Definition 3mf.cpp:79
const std::string MODEL_EXTENSION
Definition 3mf.cpp:71
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE
Definition 3mf.cpp:82
const std::string PRINT_CONFIG_FILE
Definition 3mf.cpp:76
const std::string CUT_INFORMATION_FILE
Definition 3mf.cpp:83
const std::string MODEL_CONFIG_FILE
Definition 3mf.cpp:77
const std::string MODEL_FOLDER
Definition 3mf.cpp:70
const std::string SLA_DRAIN_HOLES_FILE
Definition 3mf.cpp:81
void _extract_sla_support_points_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
Definition 3mf.cpp:1189
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
Definition 3mf.cpp:1396
bool _generate_volumes(ModelObject &object, const Geometry &geometry, const ObjectMetadata::VolumeMetadataList &volumes, ConfigSubstitutionContext &config_substitutions)
Definition 3mf.cpp:2124
bool _extract_model_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
Definition 3mf.cpp:924
void _extract_sla_drain_holes_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
Definition 3mf.cpp:1271
std::vector< VolumeMetadata > VolumeMetadataList
Definition 3mf.cpp:426
void _extract_cut_information_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions)
Definition 3mf.cpp:988
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
Definition 3mf.cpp:1070
void _extract_layer_config_ranges_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, ConfigSubstitutionContext &config_substitutions)
Definition 3mf.cpp:1132
bool _extract_model_config_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, Model &model)
Definition 3mf.cpp:1356
void _extract_print_config_from_archive(mz_zip_archive &archive, const mz_zip_archive_file_stat &stat, DynamicPrintConfig &config, ConfigSubstitutionContext &subs_context, const std::string &archive_filename)
Definition 3mf.cpp:1047
Vec3d get_offset() const
Definition Geometry.hpp:387
void set_offset(const Vec3d &offset)
Definition Geometry.hpp:392
void clear_instances()
Definition Model.cpp:862
mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
Definition miniz.c:7870
void mz_zip_zero_struct(mz_zip_archive *pZip)
Definition miniz.c:3792
mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
Definition miniz.c:7959
unsigned int mz_uint
Definition miniz.h:489
Definition miniz.h:1053
CutConnectorType
Definition Model.hpp:224
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:52
bool open_zip_reader(mz_zip_archive *zip, const std::string &fname)
Definition miniz_extension.cpp:62
bool close_zip_reader(mz_zip_archive *zip)
Definition miniz_extension.cpp:72

References _extract_custom_gcode_per_print_z_from_archive(), _extract_cut_information_from_archive(), _extract_layer_config_ranges_from_archive(), _extract_layer_heights_profile_config_from_archive(), _extract_model_config_from_archive(), _extract_model_from_archive(), _extract_print_config_from_archive(), _extract_sla_drain_holes_from_archive(), _extract_sla_support_points_from_archive(), _generate_volumes(), Slic3r::_3MF_Base::add_error(), Slic3r::ModelObject::add_instance(), Slic3r::Model::add_object(), Slic3r::ModelObject::clear_instances(), Slic3r::close_zip_reader(), Slic3r::ModelObject::config, CUSTOM_GCODE_PER_PRINT_Z_FILE, Slic3r::ModelObject::cut_id, CUT_INFORMATION_FILE, Slic3r::ModelObject::delete_last_instance(), Slic3r::Geometry::Transformation::get_offset(), Slic3r::ModelVolume::get_transformation(), Slic3r::ModelInstance::get_transformation(), Slic3r::ObjectBase::id(), Slic3r::ModelVolume::Source::input_file, Slic3r::ModelObject::instances, Slic3r::ModelObject::layer_config_ranges, LAYER_CONFIG_RANGES_FILE, Slic3r::ModelObject::layer_height_profile, LAYER_HEIGHTS_PROFILE_FILE, m_cut_object_infos, m_geometries, m_layer_config_ranges, m_layer_heights_profiles, m_model, m_name, m_objects, m_objects_metadata, m_sla_drain_holes, m_sla_support_points, m_version, MODEL_CONFIG_FILE, MODEL_EXTENSION, MODEL_FOLDER, mz_zip_reader_file_stat(), mz_zip_reader_get_num_files(), mz_zip_zero_struct(), Slic3r::ModelObject::name, Slic3r::ModelVolume::Source::object_idx, Slic3r::Model::objects, Slic3r::open_zip_reader(), PRINT_CONFIG_FILE, Slic3r::LayerHeightProfile::set(), Slic3r::ModelConfig::set_deserialize(), Slic3r::ModelVolume::set_offset(), Slic3r::ModelInstance::set_offset(), Slic3r::ModelObject::sla_drain_holes, SLA_DRAIN_HOLES_FILE, Slic3r::ModelObject::sla_points_status, Slic3r::ModelObject::sla_support_points, SLA_SUPPORT_POINTS_FILE, Slic3r::ModelVolume::source, stat, Slic3r::_3MF_Importer::Geometry::triangles, Slic3r::sla::UserModified, Slic3r::ModelVolume::Source::volume_idx, and Slic3r::ModelObject::volumes.

Referenced by load_model_from_file().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _stop_xml_parser()

void Slic3r::_3MF_Importer::_stop_xml_parser ( const std::string &  msg = std::string())
private
657 {
658 assert(! m_parse_error);
659 assert(m_parse_error_message.empty());
660 assert(m_xml_parser != nullptr);
661 m_parse_error = true;
663 XML_StopParser(m_xml_parser, false);
664 }
bool m_parse_error
Definition 3mf.cpp:470
std::string m_parse_error_message
Definition 3mf.cpp:471

References m_parse_error, m_parse_error_message, and m_xml_parser.

◆ add_error()

void Slic3r::_3MF_Base::add_error ( const std::string &  error)
inlineprotectedinherited
305{ m_errors.push_back(error); }
std::vector< std::string > m_errors
Definition 3mf.cpp:302
static char error[256]
Definition tga.cpp:50

References error, and Slic3r::_3MF_Base::m_errors.

Referenced by _extract_model_from_archive(), and _load_model_from_file().

+ Here is the caller graph for this function:

◆ clear_errors()

void Slic3r::_3MF_Base::clear_errors ( )
inlineprotectedinherited
306{ m_errors.clear(); }

References Slic3r::_3MF_Base::m_errors.

Referenced by load_model_from_file().

+ Here is the caller graph for this function:

◆ load_model_from_file()

bool Slic3r::_3MF_Importer::load_model_from_file ( const std::string &  filename,
Model model,
DynamicPrintConfig config,
ConfigSubstitutionContext config_substitutions,
bool  check_version 
)
622 {
623 m_version = 0;
627 m_check_version = check_version;
628 m_model = &model;
629 m_unit_factor = 1.0f;
631 m_objects.clear();
632 m_objects_aliases.clear();
633 m_instances.clear();
634 m_geometries.clear();
637 m_objects_metadata.clear();
639 m_layer_config_ranges.clear();
640 m_sla_support_points.clear();
641 m_curr_metadata_name.clear();
642 m_curr_characters.clear();
643 clear_errors();
644
645 return _load_model_from_file(filename, model, config, config_substitutions);
646 }
void clear_errors()
Definition 3mf.cpp:306
bool _load_model_from_file(const std::string &filename, Model &model, DynamicPrintConfig &config, ConfigSubstitutionContext &config_substitutions)
Definition 3mf.cpp:666

References _load_model_from_file(), Slic3r::_3MF_Base::clear_errors(), m_check_version, m_curr_characters, m_curr_config, m_curr_metadata_name, m_curr_object, m_fdm_supports_painting_version, m_geometries, m_instances, m_layer_config_ranges, m_layer_heights_profiles, m_mm_painting_version, m_model, m_objects, m_objects_aliases, m_objects_metadata, m_seam_painting_version, m_sla_support_points, m_unit_factor, m_version, Slic3r::_3MF_Importer::CurrentConfig::object_id, Slic3r::_3MF_Importer::CurrentObject::reset(), and Slic3r::_3MF_Importer::CurrentConfig::volume_id.

Referenced by Slic3r::load_3mf().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ log_errors()

void Slic3r::_3MF_Base::log_errors ( )
inlineinherited
310 {
311 for (const std::string& error : m_errors)
312 BOOST_LOG_TRIVIAL(error) << error;
313 }

References error, and Slic3r::_3MF_Base::m_errors.

Referenced by Slic3r::load_3mf(), and Slic3r::store_3mf().

+ Here is the caller graph for this function:

◆ parse_error()

bool Slic3r::_3MF_Importer::parse_error ( ) const
inlineprivate
502{ return m_parse_error; }

References m_parse_error.

◆ parse_error_message()

const char * Slic3r::_3MF_Importer::parse_error_message ( ) const
inlineprivate
503 {
504 return m_parse_error ?
505 // The error was signalled by the user code, not the expat parser.
506 (m_parse_error_message.empty() ? "Invalid 3MF format" : m_parse_error_message.c_str()) :
507 // The error was signalled by the expat parser.
508 XML_ErrorString(XML_GetErrorCode(m_xml_parser));
509 }

References m_parse_error, m_parse_error_message, and m_xml_parser.

◆ prusaslicer_generator_version()

boost::optional< Semver > Slic3r::_3MF_Importer::prusaslicer_generator_version ( ) const
inline

References m_prusaslicer_generator_version.

Referenced by Slic3r::load_3mf().

+ Here is the caller graph for this function:

◆ version()

unsigned int Slic3r::_3MF_Importer::version ( ) const
inline
495{ return m_version; }

References m_version.

Referenced by Slic3r::load_3mf().

+ Here is the caller graph for this function:

Member Data Documentation

◆ m_check_version

bool Slic3r::_3MF_Importer::m_check_version
private

Referenced by load_model_from_file().

◆ m_curr_characters

std::string Slic3r::_3MF_Importer::m_curr_characters
private

Referenced by load_model_from_file().

◆ m_curr_config

CurrentConfig Slic3r::_3MF_Importer::m_curr_config
private

Referenced by load_model_from_file().

◆ m_curr_metadata_name

std::string Slic3r::_3MF_Importer::m_curr_metadata_name
private

Referenced by load_model_from_file().

◆ m_curr_object

CurrentObject Slic3r::_3MF_Importer::m_curr_object
private

Referenced by load_model_from_file().

◆ m_cut_object_infos

IdToCutObjectInfoMap Slic3r::_3MF_Importer::m_cut_object_infos
private

Referenced by _load_model_from_file().

◆ m_errors

std::vector<std::string> Slic3r::_3MF_Base::m_errors
privateinherited

◆ m_fdm_supports_painting_version

unsigned int Slic3r::_3MF_Importer::m_fdm_supports_painting_version = 0
private

Referenced by load_model_from_file().

◆ m_geometries

IdToGeometryMap Slic3r::_3MF_Importer::m_geometries
private

◆ m_instances

InstancesList Slic3r::_3MF_Importer::m_instances
private

Referenced by load_model_from_file().

◆ m_layer_config_ranges

IdToLayerConfigRangesMap Slic3r::_3MF_Importer::m_layer_config_ranges
private

◆ m_layer_heights_profiles

IdToLayerHeightsProfileMap Slic3r::_3MF_Importer::m_layer_heights_profiles
private

◆ m_mm_painting_version

unsigned int Slic3r::_3MF_Importer::m_mm_painting_version = 0
private

Referenced by load_model_from_file().

◆ m_model

Model* Slic3r::_3MF_Importer::m_model
private

◆ m_name

std::string Slic3r::_3MF_Importer::m_name
private

Referenced by _load_model_from_file().

◆ m_objects

IdToModelObjectMap Slic3r::_3MF_Importer::m_objects
private

◆ m_objects_aliases

IdToAliasesMap Slic3r::_3MF_Importer::m_objects_aliases
private

Referenced by load_model_from_file().

◆ m_objects_metadata

IdToMetadataMap Slic3r::_3MF_Importer::m_objects_metadata
private

◆ m_parse_error

bool Slic3r::_3MF_Importer::m_parse_error { false }
private

◆ m_parse_error_message

std::string Slic3r::_3MF_Importer::m_parse_error_message
private

◆ m_prusaslicer_generator_version

boost::optional<Semver> Slic3r::_3MF_Importer::m_prusaslicer_generator_version
private

◆ m_seam_painting_version

unsigned int Slic3r::_3MF_Importer::m_seam_painting_version = 0
private

Referenced by load_model_from_file().

◆ m_sla_drain_holes

IdToSlaDrainHolesMap Slic3r::_3MF_Importer::m_sla_drain_holes
private

Referenced by _load_model_from_file().

◆ m_sla_support_points

IdToSlaSupportPointsMap Slic3r::_3MF_Importer::m_sla_support_points
private

◆ m_unit_factor

float Slic3r::_3MF_Importer::m_unit_factor
private

Referenced by load_model_from_file().

◆ m_version

unsigned int Slic3r::_3MF_Importer::m_version
private

◆ m_xml_parser

XML_Parser Slic3r::_3MF_Importer::m_xml_parser
private

The documentation for this class was generated from the following file: