ENH: some improvements to 3mf loading

1. convert instance to object when loading previous 3mf
2. fix an exception issue caused by previous commit caused by nil value of import_project_action

Change-Id: Ieed853f0e8d458aab1716acf52307c5d672ebe22
This commit is contained in:
lane.wei 2022-11-29 22:10:10 +08:00 committed by Lane.Wei
parent 1637981be5
commit c0ccb733dd
2 changed files with 59 additions and 42 deletions

View file

@ -661,7 +661,7 @@ ModelVolumeType type_from_string(const std::string &s)
: m_version(0) : m_version(0)
, m_check_version(false) , m_check_version(false)
, m_xml_parser(nullptr) , m_xml_parser(nullptr)
, m_model(nullptr) , m_model(nullptr)
, m_unit_factor(1.0f) , m_unit_factor(1.0f)
, m_curr_metadata_name("") , m_curr_metadata_name("")
, m_curr_characters("") , m_curr_characters("")
@ -934,6 +934,18 @@ ModelVolumeType type_from_string(const std::string &s)
++object_idx; ++object_idx;
} }
//BBS: copy object isteadof instance
int object_size = model.objects.size();
for (int obj_index = 0; obj_index < object_size; obj_index ++) {
ModelObject* object = model.objects[obj_index];
while (object->instances.size() > 1) {
ModelObject* new_model_object = model.add_object(*object);
new_model_object->clear_instances();
new_model_object->add_instance(*object->instances.back());
object->delete_last_instance();
}
}
// // fixes the min z of the model if negative // // fixes the min z of the model if negative
// model.adjust_min_z(); // model.adjust_min_z();
@ -1005,8 +1017,8 @@ ModelVolumeType type_from_string(const std::string &s)
} }
void _3MF_Importer::_extract_print_config_from_archive( void _3MF_Importer::_extract_print_config_from_archive(
mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, mz_zip_archive& archive, const mz_zip_archive_file_stat& stat,
DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions,
const std::string& archive_filename) const std::string& archive_filename)
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
@ -1227,7 +1239,7 @@ ModelVolumeType type_from_string(const std::string &s)
} }
} }
} }
void _3MF_Importer::_extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat) void _3MF_Importer::_extract_sla_drain_holes_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{ {
if (stat.m_uncomp_size > 0) { if (stat.m_uncomp_size > 0) {
@ -1237,13 +1249,13 @@ ModelVolumeType type_from_string(const std::string &s)
add_error("Error while reading sla support points data to buffer"); add_error("Error while reading sla support points data to buffer");
return; return;
} }
if (buffer.back() == '\n') if (buffer.back() == '\n')
buffer.pop_back(); buffer.pop_back();
std::vector<std::string> objects; std::vector<std::string> objects;
boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off); boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
// Info on format versioning - see 3mf.hpp // Info on format versioning - see 3mf.hpp
int version = 0; int version = 0;
std::string key("drain_holes_format_version="); std::string key("drain_holes_format_version=");
@ -1252,38 +1264,38 @@ ModelVolumeType type_from_string(const std::string &s)
version = std::stoi(objects[0]); version = std::stoi(objects[0]);
objects.erase(objects.begin()); // pop the header objects.erase(objects.begin()); // pop the header
} }
for (const std::string& object : objects) { for (const std::string& object : objects) {
std::vector<std::string> object_data; std::vector<std::string> object_data;
boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off); boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
if (object_data.size() != 2) { if (object_data.size() != 2) {
add_error("Error while reading object data"); add_error("Error while reading object data");
continue; continue;
} }
std::vector<std::string> object_data_id; std::vector<std::string> object_data_id;
boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off); boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
if (object_data_id.size() != 2) { if (object_data_id.size() != 2) {
add_error("Error while reading object id"); add_error("Error while reading object id");
continue; continue;
} }
int object_id = std::atoi(object_data_id[1].c_str()); int object_id = std::atoi(object_data_id[1].c_str());
if (object_id == 0) { if (object_id == 0) {
add_error("Found invalid object id"); add_error("Found invalid object id");
continue; continue;
} }
IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id); IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id);
if (object_item != m_sla_drain_holes.end()) { if (object_item != m_sla_drain_holes.end()) {
add_error("Found duplicated SLA drain holes"); add_error("Found duplicated SLA drain holes");
continue; continue;
} }
std::vector<std::string> object_data_points; std::vector<std::string> object_data_points;
boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off); boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
sla::DrainHoles sla_drain_holes; sla::DrainHoles sla_drain_holes;
if (version == 1) { if (version == 1) {
@ -1306,7 +1318,7 @@ ModelVolumeType type_from_string(const std::string &s)
hole.pos += hole.normal.normalized(); hole.pos += hole.normal.normalized();
hole.height -= 1.f; hole.height -= 1.f;
} }
if (!sla_drain_holes.empty()) if (!sla_drain_holes.empty())
m_sla_drain_holes.insert({ object_id, sla_drain_holes }); m_sla_drain_holes.insert({ object_id, sla_drain_holes });
} }
@ -1394,11 +1406,11 @@ ModelVolumeType type_from_string(const std::string &s)
pt::ptree attr_tree = tree.find("<xmlattr>")->second; pt::ptree attr_tree = tree.find("<xmlattr>")->second;
if (attr_tree.find("type") == attr_tree.not_found()) { if (attr_tree.find("type") == attr_tree.not_found()) {
// It means that data was saved in old version (2.2.0 and older) of PrusaSlicer // It means that data was saved in old version (2.2.0 and older) of PrusaSlicer
// read old data ... // read old data ...
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode"); std::string gcode = tree.get<std::string> ("<xmlattr>.gcode");
// ... and interpret them to the new data // ... and interpret them to the new data
type = gcode == "M600" ? CustomGCode::ColorChange : type = gcode == "M600" ? CustomGCode::ColorChange :
gcode == "M601" ? CustomGCode::PausePrint : gcode == "M601" ? CustomGCode::PausePrint :
gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom; gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom;
extra = type == CustomGCode::PausePrint ? color : extra = type == CustomGCode::PausePrint ? color :
type == CustomGCode::Custom ? gcode : ""; type == CustomGCode::Custom ? gcode : "";
@ -2113,7 +2125,7 @@ ModelVolumeType type_from_string(const std::string &s)
tri_id -= min_id; tri_id -= min_id;
} }
if (m_prusaslicer_generator_version && if (m_prusaslicer_generator_version &&
*m_prusaslicer_generator_version >= *Semver::parse("2.4.0-alpha1") && *m_prusaslicer_generator_version >= *Semver::parse("2.4.0-alpha1") &&
*m_prusaslicer_generator_version < *Semver::parse("2.4.0-alpha3")) *m_prusaslicer_generator_version < *Semver::parse("2.4.0-alpha3"))
// PrusaSlicer 2.4.0-alpha2 contained a bug, where all vertices of a single object were saved for each volume the object contained. // PrusaSlicer 2.4.0-alpha2 contained a bug, where all vertices of a single object were saved for each volume the object contained.
@ -2227,7 +2239,7 @@ ModelVolumeType type_from_string(const std::string &s)
if (importer != nullptr) if (importer != nullptr)
importer->_handle_start_config_xml_element(name, attributes); importer->_handle_start_config_xml_element(name, attributes);
} }
void XMLCALL _3MF_Importer::_handle_end_config_xml_element(void* userData, const char* name) void XMLCALL _3MF_Importer::_handle_end_config_xml_element(void* userData, const char* name)
{ {
_3MF_Importer* importer = (_3MF_Importer*)userData; _3MF_Importer* importer = (_3MF_Importer*)userData;
@ -2340,7 +2352,7 @@ ModelVolumeType type_from_string(const std::string &s)
} }
} }
// Adds relationships file ("_rels/.rels"). // Adds relationships file ("_rels/.rels").
// The content of this file is the same for each PrusaSlicer 3mf. // The content of this file is the same for each PrusaSlicer 3mf.
// The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA. // The relationshis file contains a reference to the geometry file "3D/3dmodel.model", the name was chosen to be compatible with CURA.
if (!_add_relationships_file_to_archive(archive)) { if (!_add_relationships_file_to_archive(archive)) {
@ -2384,13 +2396,13 @@ ModelVolumeType type_from_string(const std::string &s)
boost::filesystem::remove(filename); boost::filesystem::remove(filename);
return false; return false;
} }
if (!_add_sla_drain_holes_file_to_archive(archive, model)) { if (!_add_sla_drain_holes_file_to_archive(archive, model)) {
close_zip_writer(&archive); close_zip_writer(&archive);
boost::filesystem::remove(filename); boost::filesystem::remove(filename);
return false; return false;
} }
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml"). // Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml").
// All custom gcode per height of whole Model are stored here // All custom gcode per height of whole Model are stored here
@ -2502,11 +2514,11 @@ ModelVolumeType type_from_string(const std::string &s)
bool _3MF_Exporter::_add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, IdToObjectDataMap& objects_data) bool _3MF_Exporter::_add_model_file_to_archive(const std::string& filename, mz_zip_archive& archive, const Model& model, IdToObjectDataMap& objects_data)
{ {
mz_zip_writer_staged_context context; mz_zip_writer_staged_context context;
if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(), if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(),
m_zip64 ? m_zip64 ?
// Maximum expected and allowed 3MF file size is 16GiB. // Maximum expected and allowed 3MF file size is 16GiB.
// This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records. // This switches the ZIP file to a 64bit mode, which adds a tiny bit of overhead to file records.
(uint64_t(1) << 30) * 16 : (uint64_t(1) << 30) * 16 :
// Maximum expected 3MF file size is 4GB-1. This is a workaround for interoperability with Windows 10 3D model fixing API, see // Maximum expected 3MF file size is 4GB-1. This is a workaround for interoperability with Windows 10 3D model fixing API, see
// GH issue #6193. // GH issue #6193.
(uint64_t(1) << 32) - 1, (uint64_t(1) << 32) - 1,
@ -2589,7 +2601,7 @@ ModelVolumeType type_from_string(const std::string &s)
} }
stream << "</" << MODEL_TAG << ">\n"; stream << "</" << MODEL_TAG << ">\n";
std::string buf = stream.str(); std::string buf = stream.str();
if ((! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) || if ((! buf.empty() && ! mz_zip_writer_add_staged_data(&context, buf.data(), buf.size())) ||
@ -2877,7 +2889,7 @@ ModelVolumeType type_from_string(const std::string &s)
sprintf(buffer, (i == 0) ? "%f" : ";%f", layer_height_profile[i]); sprintf(buffer, (i == 0) ? "%f" : ";%f", layer_height_profile[i]);
out += buffer; out += buffer;
} }
out += "\n"; out += "\n";
} }
} }
@ -2936,8 +2948,8 @@ ModelVolumeType type_from_string(const std::string &s)
boost::replace_all(out, "><option", ">\n <option"); boost::replace_all(out, "><option", ">\n <option");
boost::replace_all(out, "></range>", ">\n </range>"); boost::replace_all(out, "></range>", ">\n </range>");
boost::replace_all(out, "></object>", ">\n </object>"); boost::replace_all(out, "></object>", ">\n </object>");
// OR just // OR just
boost::replace_all(out, "><", ">\n<"); boost::replace_all(out, "><", ">\n<");
} }
if (!out.empty()) { if (!out.empty()) {
@ -2984,13 +2996,13 @@ ModelVolumeType type_from_string(const std::string &s)
} }
return true; return true;
} }
bool _3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model) bool _3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model)
{ {
assert(is_decimal_separator_point()); assert(is_decimal_separator_point());
const char *const fmt = "object_id=%d|"; const char *const fmt = "object_id=%d|";
std::string out; std::string out;
unsigned int count = 0; unsigned int count = 0;
for (const ModelObject* object : model.objects) { for (const ModelObject* object : model.objects) {
++count; ++count;
@ -3007,7 +3019,7 @@ ModelVolumeType type_from_string(const std::string &s)
if (!drain_holes.empty()) { if (!drain_holes.empty()) {
out += string_printf(fmt, count); out += string_printf(fmt, count);
// Store the layer height profile as a single space separated list. // Store the layer height profile as a single space separated list.
for (size_t i = 0; i < drain_holes.size(); ++i) for (size_t i = 0; i < drain_holes.size(); ++i)
out += string_printf((i == 0 ? "%f %f %f %f %f %f %f %f" : " %f %f %f %f %f %f %f %f"), out += string_printf((i == 0 ? "%f %f %f %f %f %f %f %f" : " %f %f %f %f %f %f %f %f"),
@ -3019,15 +3031,15 @@ ModelVolumeType type_from_string(const std::string &s)
drain_holes[i].normal(2), drain_holes[i].normal(2),
drain_holes[i].radius, drain_holes[i].radius,
drain_holes[i].height); drain_holes[i].height);
out += "\n"; out += "\n";
} }
} }
if (!out.empty()) { if (!out.empty()) {
// Adds version header at the beginning: // Adds version header at the beginning:
out = std::string("drain_holes_format_version=") + std::to_string(drain_holes_format_version) + std::string("\n") + out; out = std::string("drain_holes_format_version=") + std::to_string(drain_holes_format_version) + std::string("\n") + out;
if (!mz_zip_writer_add_mem(&archive, SLA_DRAIN_HOLES_FILE.c_str(), static_cast<const void*>(out.data()), out.length(), mz_uint(MZ_DEFAULT_COMPRESSION))) { if (!mz_zip_writer_add_mem(&archive, SLA_DRAIN_HOLES_FILE.c_str(), static_cast<const void*>(out.data()), out.length(), mz_uint(MZ_DEFAULT_COMPRESSION))) {
add_error("Unable to add sla support points file to archive"); add_error("Unable to add sla support points file to archive");
return false; return false;
@ -3099,7 +3111,7 @@ ModelVolumeType type_from_string(const std::string &s)
if (volume->is_modifier()) if (volume->is_modifier())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
// stores volume's type (overrides the modifier field above) // stores volume's type (overrides the modifier field above)
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " << stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << VOLUME_TYPE_KEY << "\" " <<
VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n"; VALUE_ATTR << "=\"" << ModelVolume::type_to_string(volume->type()) << "\"/>\n";
// stores volume's local matrix // stores volume's local matrix
@ -3137,7 +3149,7 @@ ModelVolumeType type_from_string(const std::string &s)
for (const std::string& key : volume->config.keys()) { for (const std::string& key : volume->config.keys()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n"; stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
} }
// stores mesh's statistics // stores mesh's statistics
const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors; const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors;
stream << " <" << MESH_TAG << " "; stream << " <" << MESH_TAG << " ";
@ -3190,12 +3202,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
std::string gcode = //code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") : std::string gcode = //code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") :
code.type == CustomGCode::PausePrint ? config->opt_string("machine_pause_gcode") : code.type == CustomGCode::PausePrint ? config->opt_string("machine_pause_gcode") :
code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") : code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") :
code.type == CustomGCode::ToolChange ? "tool_change" : code.extra; code.type == CustomGCode::ToolChange ? "tool_change" : code.extra;
code_tree.put("<xmlattr>.gcode" , gcode ); code_tree.put("<xmlattr>.gcode" , gcode );
} }
pt::ptree& mode_tree = main_tree.add("mode", ""); pt::ptree& mode_tree = main_tree.add("mode", "");
// store mode of a custom_gcode_per_print_z // store mode of a custom_gcode_per_print_z
mode_tree.put("<xmlattr>.value", model.custom_gcode_per_print_z.mode == CustomGCode::Mode::SingleExtruder ? CustomGCode::SingleExtruderMode : mode_tree.put("<xmlattr>.value", model.custom_gcode_per_print_z.mode == CustomGCode::Mode::SingleExtruder ? CustomGCode::SingleExtruderMode :
model.custom_gcode_per_print_z.mode == CustomGCode::Mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode : model.custom_gcode_per_print_z.mode == CustomGCode::Mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode :
CustomGCode::MultiExtruderMode); CustomGCode::MultiExtruderMode);
@ -3208,7 +3220,7 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
// Post processing("beautification") of the output string // Post processing("beautification") of the output string
boost::replace_all(out, "><", ">\n<"); boost::replace_all(out, "><", ">\n<");
} }
} }
if (!out.empty()) { if (!out.empty()) {
if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) { if (!mz_zip_writer_add_mem(&archive, CUSTOM_GCODE_PER_PRINT_Z_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {

View file

@ -2948,7 +2948,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
wxGetApp().get_tab(Preset::TYPE_PRINT)->update(); wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
} }
LoadType load_type = static_cast<LoadType>(std::stoi(wxGetApp().app_config->get("import_project_action"))); std::string import_project_action = wxGetApp().app_config->get("import_project_action");
LoadType load_type;
if (import_project_action.empty())
load_type = LoadType::Unknown;
else
load_type = static_cast<LoadType>(std::stoi(import_project_action));
// BBS: version check // BBS: version check
Semver app_version = *(Semver::parse(SLIC3R_VERSION)); Semver app_version = *(Semver::parse(SLIC3R_VERSION));