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_check_version(false)
, m_xml_parser(nullptr)
, m_model(nullptr)
, m_model(nullptr)
, m_unit_factor(1.0f)
, m_curr_metadata_name("")
, m_curr_characters("")
@ -934,6 +934,18 @@ ModelVolumeType type_from_string(const std::string &s)
++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
// model.adjust_min_z();
@ -1005,8 +1017,8 @@ ModelVolumeType type_from_string(const std::string &s)
}
void _3MF_Importer::_extract_print_config_from_archive(
mz_zip_archive& archive, const mz_zip_archive_file_stat& stat,
DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions,
mz_zip_archive& archive, const mz_zip_archive_file_stat& stat,
DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions,
const std::string& archive_filename)
{
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)
{
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");
return;
}
if (buffer.back() == '\n')
buffer.pop_back();
std::vector<std::string> objects;
boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
// Info on format versioning - see 3mf.hpp
int version = 0;
std::string key("drain_holes_format_version=");
@ -1252,38 +1264,38 @@ ModelVolumeType type_from_string(const std::string &s)
version = std::stoi(objects[0]);
objects.erase(objects.begin()); // pop the header
}
for (const std::string& object : objects) {
std::vector<std::string> object_data;
boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
if (object_data.size() != 2) {
add_error("Error while reading object data");
continue;
}
std::vector<std::string> object_data_id;
boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
if (object_data_id.size() != 2) {
add_error("Error while reading object id");
continue;
}
int object_id = std::atoi(object_data_id[1].c_str());
if (object_id == 0) {
add_error("Found invalid object id");
continue;
}
IdToSlaDrainHolesMap::iterator object_item = m_sla_drain_holes.find(object_id);
if (object_item != m_sla_drain_holes.end()) {
add_error("Found duplicated SLA drain holes");
continue;
}
std::vector<std::string> object_data_points;
boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
sla::DrainHoles sla_drain_holes;
if (version == 1) {
@ -1306,7 +1318,7 @@ ModelVolumeType type_from_string(const std::string &s)
hole.pos += hole.normal.normalized();
hole.height -= 1.f;
}
if (!sla_drain_holes.empty())
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;
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
// read old data ...
// read old data ...
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode");
// ... and interpret them to the new data
type = gcode == "M600" ? CustomGCode::ColorChange :
gcode == "M601" ? CustomGCode::PausePrint :
type = gcode == "M600" ? CustomGCode::ColorChange :
gcode == "M601" ? CustomGCode::PausePrint :
gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom;
extra = type == CustomGCode::PausePrint ? color :
type == CustomGCode::Custom ? gcode : "";
@ -2113,7 +2125,7 @@ ModelVolumeType type_from_string(const std::string &s)
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-alpha3"))
// 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)
importer->_handle_start_config_xml_element(name, attributes);
}
void XMLCALL _3MF_Importer::_handle_end_config_xml_element(void* userData, const char* name)
{
_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 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)) {
@ -2384,13 +2396,13 @@ ModelVolumeType type_from_string(const std::string &s)
boost::filesystem::remove(filename);
return false;
}
if (!_add_sla_drain_holes_file_to_archive(archive, model)) {
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// 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
@ -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)
{
mz_zip_writer_staged_context context;
if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(),
m_zip64 ?
if (!mz_zip_writer_add_staged_open(&archive, &context, MODEL_FILE.c_str(),
m_zip64 ?
// 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.
(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
// GH issue #6193.
(uint64_t(1) << 32) - 1,
@ -2589,7 +2601,7 @@ ModelVolumeType type_from_string(const std::string &s)
}
stream << "</" << MODEL_TAG << ">\n";
std::string buf = stream.str();
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]);
out += buffer;
}
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, "></range>", ">\n </range>");
boost::replace_all(out, "></object>", ">\n </object>");
// OR just
boost::replace_all(out, "><", ">\n<");
// OR just
boost::replace_all(out, "><", ">\n<");
}
if (!out.empty()) {
@ -2984,13 +2996,13 @@ ModelVolumeType type_from_string(const std::string &s)
}
return true;
}
bool _3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model)
{
assert(is_decimal_separator_point());
const char *const fmt = "object_id=%d|";
std::string out;
unsigned int count = 0;
for (const ModelObject* object : model.objects) {
++count;
@ -3007,7 +3019,7 @@ ModelVolumeType type_from_string(const std::string &s)
if (!drain_holes.empty()) {
out += string_printf(fmt, count);
// Store the layer height profile as a single space separated list.
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"),
@ -3019,15 +3031,15 @@ ModelVolumeType type_from_string(const std::string &s)
drain_holes[i].normal(2),
drain_holes[i].radius,
drain_holes[i].height);
out += "\n";
}
}
if (!out.empty()) {
// Adds version header at the beginning:
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))) {
add_error("Unable to add sla support points file to archive");
return false;
@ -3099,7 +3111,7 @@ ModelVolumeType type_from_string(const std::string &s)
if (volume->is_modifier())
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MODIFIER_KEY << "\" " << VALUE_ATTR << "=\"1\"/>\n";
// 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";
// 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()) {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
}
// stores mesh's statistics
const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors;
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") :
code.type == CustomGCode::PausePrint ? config->opt_string("machine_pause_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 );
}
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 :
model.custom_gcode_per_print_z.mode == CustomGCode::Mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode :
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
boost::replace_all(out, "><", ">\n<");
}
}
}
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)) {

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();
}
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
Semver app_version = *(Semver::parse(SLIC3R_VERSION));