Rewrote layers information export/import to/from 3mf using Boost Property Tree (xml_parser)

This commit is contained in:
YuSanka 2019-06-27 13:54:51 +02:00
parent 1058721dba
commit cecc134550

View File

@ -16,6 +16,12 @@
#include <boost/nowide/fstream.hpp> #include <boost/nowide/fstream.hpp>
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/foreach.hpp>
namespace pt = boost::property_tree;
#include <expat.h> #include <expat.h>
#include <Eigen/Dense> #include <Eigen/Dense>
#include "miniz_extension.hpp" #include "miniz_extension.hpp"
@ -34,7 +40,7 @@ const std::string RELATIONSHIPS_FILE = "_rels/.rels";
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config"; const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config"; 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_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Slic3r_PE_layer_config_ranges.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 SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
const char* MODEL_TAG = "model"; const char* MODEL_TAG = "model";
@ -796,43 +802,20 @@ namespace Slic3r {
return; return;
} }
if (buffer.back() == '|') std::istringstream iss(buffer); // wrap returned xml to istringstream
buffer.pop_back(); pt::ptree objects_tree;
pt::read_xml(iss, objects_tree);
std::vector<std::string> objects; for (const auto& object : objects_tree.get_child("objects"))
boost::split(objects, buffer, boost::is_any_of("|"), boost::token_compress_off);
for (std::string& object : objects)
{ {
// delete all spaces pt::ptree object_tree = object.second;
boost::replace_all(object, " ", ""); int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
if (obj_idx <= 0) {
std::vector<std::string> object_data;
boost::split(object_data, object, boost::is_any_of("*"), boost::token_compress_off);
/* there should be at least one layer config range in the object
* object_data[0] => object information
* object_data[i>=1] => range information
*/
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;
}
// get object information
int object_id = std::atoi(object_data_id[1].c_str());
if (object_id == 0) {
add_error("Found invalid object id"); add_error("Found invalid object id");
continue; continue;
} }
IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(object_id); IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(obj_idx);
if (object_item != m_layer_config_ranges.end()) { if (object_item != m_layer_config_ranges.end()) {
add_error("Found duplicated layer config range"); add_error("Found duplicated layer config range");
continue; continue;
@ -840,56 +823,26 @@ namespace Slic3r {
t_layer_config_ranges config_ranges; t_layer_config_ranges config_ranges;
// get ranges information for (const auto& range : object_tree.get_child("ranges"))
for (size_t i = 1; i < object_data.size(); ++i)
{ {
if (object_data[i].back() == '\n') pt::ptree range_tree = range.second;
object_data[i].pop_back(); double min_z = range_tree.get<double>("<xmlattr>.min_z");
double max_z = range_tree.get<double>("<xmlattr>.max_z");
std::vector<std::string> range_data;
boost::split(range_data, object_data[i], boost::is_any_of("\n"), boost::token_compress_off);
/* There should be at least two options for layer config range
* range_data[0] => Z range information
* range_data[i>=1] => configuration for the range
*/
if (range_data.size() < 3) {
add_error("Found invalid layer config range");
continue;
}
std::vector<std::string> z_range_str;
boost::split(z_range_str, range_data[0], boost::is_any_of("="), boost::token_compress_off);
if (z_range_str.size() != 2) {
add_error("Error while reading layer config range");
continue;
}
std::vector<std::string> z_values;
boost::split(z_values, z_range_str[1], boost::is_any_of(";"), boost::token_compress_off);
if (z_values.size() != 2) {
add_error("Found invalid layer config range");
continue;
}
// get Z range information // get Z range information
t_layer_height_range z_range = { (coordf_t)std::atof(z_values[0].c_str()) , (coordf_t)std::atof(z_values[1].c_str()) }; DynamicPrintConfig& config = config_ranges[{ min_z, max_z }];
DynamicPrintConfig& config = config_ranges[z_range];
// get configuration options for the range for (const auto& option : range_tree.get_child("config"))
for (size_t j = 1; j < range_data.size(); ++j)
{ {
std::vector<std::string> key_val; std::string opt_key = option.second.get<std::string>("<xmlattr>.opt_key");
boost::split(key_val, range_data[j], boost::is_any_of("="), boost::token_compress_off); std::string value = option.second.data();
if (key_val.size() != 2) {
add_error("Error while reading config value"); config.set_deserialize(opt_key, value);
continue;
}
config.set_deserialize(key_val[0], key_val[1]);
} }
} }
if (!config_ranges.empty()) if (!config_ranges.empty())
m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(object_id, config_ranges)); m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(obj_idx, config_ranges));
} }
} }
} }
@ -2152,7 +2105,7 @@ namespace Slic3r {
bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model) bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
{ {
std::string out = ""; std::string out = "";
char buffer[1024]; pt::ptree tree;
unsigned int object_cnt = 0; unsigned int object_cnt = 0;
for (const ModelObject* object : model.objects) for (const ModelObject* object : model.objects)
@ -2161,26 +2114,53 @@ namespace Slic3r {
const t_layer_config_ranges& ranges = object->layer_config_ranges; const t_layer_config_ranges& ranges = object->layer_config_ranges;
if (!ranges.empty()) if (!ranges.empty())
{ {
sprintf(buffer, "object_id=%d\n", object_cnt); pt::ptree& obj_tree = tree.add("objects.object","");
out += buffer;
obj_tree.put("<xmlattr>.id", object_cnt);
obj_tree.add("ranges", "");
// Store the layer config ranges. // Store the layer config ranges.
for (const auto& range : ranges) for (const auto& range : ranges)
{ {
pt::ptree& range_tree = obj_tree.add("ranges.range", "");
// store minX and maxZ // store minX and maxZ
sprintf(buffer, "*z_range = %f;%f\n", range.first.first, range.first.second); range_tree.put("<xmlattr>.min_z", range.first.first);
out += buffer; range_tree.put("<xmlattr>.max_z", range.first.second);
range_tree.add("config","");
// store range configuration // store range configuration
const DynamicPrintConfig& config = range.second; const DynamicPrintConfig& config = range.second;
for (const std::string& key : config.keys()) for (const std::string& opt_key : config.keys())
out += " " + key + " = " + config.serialize(key) + "\n"; {
pt::ptree& opt_tree = range_tree.add("config.option", config.serialize(opt_key));
opt_tree.put("<xmlattr>.opt_key", opt_key);
}
} }
out += "|";
} }
} }
if (!tree.empty())
{
std::ostringstream oss;
boost::property_tree::write_xml(oss, tree);
out = oss.str();
// Post processing of the output string for a better preview
// JUST
// boost::replace_all(out, "><", ">\n<");
// OR more "beautification"
boost::replace_all(out, "><object", ">\n <object");
boost::replace_all(out, "><ranges", ">\n <ranges");
boost::replace_all(out, "><range", ">\n <range");
boost::replace_all(out, "><config", ">\n <config");
boost::replace_all(out, "><option", ">\n <option");
boost::replace_all(out, "></config", ">\n </config");
boost::replace_all(out, "></range ", ">\n </range ");
boost::replace_all(out, "></ranges", ">\n </ranges");
boost::replace_all(out, "></object", ">\n </object");
}
if (!out.empty()) if (!out.empty())
{ {
if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))