Save/Load new color print data to/from amf and 3mf files.

This commit is contained in:
YuSanka 2019-11-11 16:01:34 +01:00
parent 6c8bb51f4a
commit 519291394a
4 changed files with 172 additions and 3 deletions

View File

@ -45,6 +45,7 @@ const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config_ranges.xml";
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const std::string CUSTOM_GCODE_PER_HEIGHT_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_height.xml";
const char* MODEL_TAG = "model";
const char* RESOURCES_TAG = "resources";
@ -411,6 +412,8 @@ namespace Slic3r {
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_custom_gcode_per_height_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, const std::string& archive_filename);
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
@ -620,6 +623,11 @@ namespace Slic3r {
// extract slic3r print config file
_extract_print_config_from_archive(archive, stat, config, filename);
}
if (boost::algorithm::iequals(name, CUSTOM_GCODE_PER_HEIGHT_FILE))
{
// extract slic3r layer config ranges file
_extract_custom_gcode_per_height_from_archive(archive, stat);
}
else if (boost::algorithm::iequals(name, MODEL_CONFIG_FILE))
{
// extract slic3r model config file
@ -1050,6 +1058,43 @@ namespace Slic3r {
return true;
}
void _3MF_Importer::_extract_custom_gcode_per_height_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
{
if (stat.m_uncomp_size > 0)
{
std::string buffer((size_t)stat.m_uncomp_size, 0);
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
if (res == 0) {
add_error("Error while reading custom Gcodes per height data to buffer");
return;
}
std::istringstream iss(buffer); // wrap returned xml to istringstream
pt::ptree main_tree;
pt::read_xml(iss, main_tree);
if (main_tree.front().first != "custom_gcodes_per_height")
return;
pt::ptree code_tree = main_tree.front().second;
if (!m_model->custom_gcode_per_height.empty())
m_model->custom_gcode_per_height.clear();
for (const auto& code : code_tree)
{
if (code.first != "code")
continue;
pt::ptree tree = code.second;
double height = tree.get<double>("<xmlattr>.height");
std::string gcode = tree.get<std::string>("<xmlattr>.gcode");
int extruder = tree.get<int>("<xmlattr>.extruder");
std::string color = tree.get<std::string>("<xmlattr>.color");
m_model->custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color)) ;
}
}
}
void _3MF_Importer::_handle_start_model_xml_element(const char* name, const char** attributes)
{
if (m_xml_parser == nullptr)
@ -1821,6 +1866,7 @@ namespace Slic3r {
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
bool _add_custom_gcode_per_height_file_to_archive(mz_zip_archive& archive, Model& model);
};
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
@ -1898,6 +1944,15 @@ namespace Slic3r {
return false;
}
// Adds custom gcode per height file ("Metadata/Prusa_Slicer_custom_gcode_per_height.xml").
// All custom gcode per height of whole Model are stored here
if (!_add_custom_gcode_per_height_file_to_archive(archive, model))
{
close_zip_writer(&archive);
boost::filesystem::remove(filename);
return false;
}
// Adds slic3r print config file ("Metadata/Slic3r_PE.config").
// This file contains the content of FullPrintConfing / SLAFullPrintConfig.
if (config != nullptr)
@ -2256,7 +2311,7 @@ namespace Slic3r {
if (!tree.empty())
{
std::ostringstream oss;
boost::property_tree::write_xml(oss, tree);
pt::write_xml(oss, tree);
out = oss.str();
// Post processing("beautification") of the output string for a better preview
@ -2442,6 +2497,48 @@ namespace Slic3r {
return true;
}
bool _3MF_Exporter::_add_custom_gcode_per_height_file_to_archive( mz_zip_archive& archive, Model& model)
{
std::string out = "";
if (!model.custom_gcode_per_height.empty())
{
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
for (const Model::CustomGCode& code : model.custom_gcode_per_height)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
code_tree.put("<xmlattr>.height" , code.height );
code_tree.put("<xmlattr>.gcode" , code.gcode );
code_tree.put("<xmlattr>.extruder" , code.extruder );
code_tree.put("<xmlattr>.color" , code.color );
}
if (!tree.empty())
{
std::ostringstream oss;
boost::property_tree::write_xml(oss, tree);
out = oss.str();
// 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_HEIGHT_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add custom Gcodes per height file to archive");
return false;
}
}
return true;
}
bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version)
{
if ((path == nullptr) || (config == nullptr) || (model == nullptr))

View File

@ -16,6 +16,10 @@
#include "AMF.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
namespace pt = boost::property_tree;
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/nowide/fstream.hpp>
@ -147,6 +151,8 @@ struct AMFParserContext
NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory
NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz
NODE_TYPE_PRINTABLE, // amf/constellation/instance/mirrorz
NODE_TYPE_CUSTOM_GCODE, // amf/custom_code_per_height
NODE_TYPE_GCODE_PER_HEIGHT, // amf/custom_code_per_height/code
NODE_TYPE_METADATA, // anywhere under amf/*/metadata
};
@ -227,7 +233,7 @@ struct AMFParserContext
// Current instance allocated for an amf/constellation/instance subtree.
Instance *m_instance;
// Generic string buffer for vertices, face indices, metadata etc.
std::string m_value[3];
std::string m_value[4];
// Pointer to config to update if config data are stored inside the amf file
DynamicPrintConfig *m_config;
@ -268,6 +274,8 @@ void AMFParserContext::startElement(const char *name, const char **atts)
}
} else if (strcmp(name, "constellation") == 0) {
node_type_new = NODE_TYPE_CONSTELLATION;
} else if (strcmp(name, "custom_gcodes_per_height") == 0) {
node_type_new = NODE_TYPE_CUSTOM_GCODE;
}
break;
case 2:
@ -295,6 +303,13 @@ void AMFParserContext::startElement(const char *name, const char **atts)
else
this->stop();
}
else if (strcmp(name, "code") == 0 && m_path[1] == NODE_TYPE_CUSTOM_GCODE) {
node_type_new = NODE_TYPE_GCODE_PER_HEIGHT;
m_value[0] = get_attribute(atts, "height");
m_value[1] = get_attribute(atts, "gcode");
m_value[2] = get_attribute(atts, "extruder");
m_value[3] = get_attribute(atts, "color");
}
break;
case 3:
if (m_path[2] == NODE_TYPE_MESH) {
@ -616,6 +631,19 @@ void AMFParserContext::endElement(const char * /* name */)
m_instance = nullptr;
break;
case NODE_TYPE_GCODE_PER_HEIGHT: {
double height = double(atof(m_value[0].c_str()));
const std::string& gcode = m_value[1];
int extruder = atoi(m_value[2].c_str());
const std::string& color = m_value[3];
m_model.custom_gcode_per_height.push_back(Model::CustomGCode(height, gcode, extruder, color));
for (std::string& val: m_value)
val.clear();
break;
}
case NODE_TYPE_METADATA:
if ((m_config != nullptr) && strncmp(m_value[0].c_str(), SLIC3R_CONFIG_TYPE, strlen(SLIC3R_CONFIG_TYPE)) == 0)
m_config->load_from_gcode_string(m_value[1].c_str());
@ -1190,6 +1218,42 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << instances;
stream << " </constellation>\n";
}
if (!model->custom_gcode_per_height.empty())
{
std::string out = "";
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
for (const Model::CustomGCode& code : model->custom_gcode_per_height)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
code_tree.put("<xmlattr>.height", code.height);
code_tree.put("<xmlattr>.gcode", code.gcode);
code_tree.put("<xmlattr>.extruder", code.extruder);
code_tree.put("<xmlattr>.color", code.color);
}
if (!tree.empty())
{
std::ostringstream oss;
pt::write_xml(oss, tree);
out = oss.str();
int del_header_pos = out.find("<custom_gcodes_per_height");
if (del_header_pos != std::string::npos)
out.erase(out.begin(), out.begin() + del_header_pos);
// Post processing("beautification") of the output string
boost::replace_all(out, "><code", ">\n <code");
boost::replace_all(out, "><", ">\n<");
stream << out << "\n";
}
}
stream << "</amf>\n";
std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(export_path).filename().string(), ".zip.amf", ".amf");

View File

@ -41,6 +41,9 @@ Model& Model::assign_copy(const Model &rhs)
mo->set_model(this);
this->objects.emplace_back(mo);
}
// copy custom code per height
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
return *this;
}
@ -59,6 +62,9 @@ Model& Model::assign_copy(Model &&rhs)
for (ModelObject *model_object : this->objects)
model_object->set_model(this);
rhs.objects.clear();
// copy custom code per height
this->custom_gcode_per_height = rhs.custom_gcode_per_height;
return *this;
}

View File

@ -2270,6 +2270,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// and place the loaded config over the base.
config += std::move(config_loaded);
}
this->model.custom_gcode_per_height = model.custom_gcode_per_height;
}
if (load_config)