|
@@ -11,6 +11,7 @@
|
|
#include <boost/algorithm/string/classification.hpp>
|
|
#include <boost/algorithm/string/classification.hpp>
|
|
#include <boost/algorithm/string/split.hpp>
|
|
#include <boost/algorithm/string/split.hpp>
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
|
|
+#include <boost/algorithm/string/replace.hpp>
|
|
#include <boost/filesystem/operations.hpp>
|
|
#include <boost/filesystem/operations.hpp>
|
|
#include <boost/nowide/fstream.hpp>
|
|
#include <boost/nowide/fstream.hpp>
|
|
#include <boost/nowide/cstdio.hpp>
|
|
#include <boost/nowide/cstdio.hpp>
|
|
@@ -33,6 +34,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 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";
|
|
@@ -331,6 +333,7 @@ namespace Slic3r {
|
|
typedef std::map<int, ObjectMetadata> IdToMetadataMap;
|
|
typedef std::map<int, ObjectMetadata> IdToMetadataMap;
|
|
typedef std::map<int, Geometry> IdToGeometryMap;
|
|
typedef std::map<int, Geometry> IdToGeometryMap;
|
|
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
|
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
|
|
|
+ typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
|
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
|
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
|
|
|
|
|
// Version of the 3mf file
|
|
// Version of the 3mf file
|
|
@@ -347,6 +350,7 @@ namespace Slic3r {
|
|
CurrentConfig m_curr_config;
|
|
CurrentConfig m_curr_config;
|
|
IdToMetadataMap m_objects_metadata;
|
|
IdToMetadataMap m_objects_metadata;
|
|
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
|
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
|
|
|
+ IdToLayerConfigRangesMap m_layer_config_ranges;
|
|
IdToSlaSupportPointsMap m_sla_support_points;
|
|
IdToSlaSupportPointsMap m_sla_support_points;
|
|
std::string m_curr_metadata_name;
|
|
std::string m_curr_metadata_name;
|
|
std::string m_curr_characters;
|
|
std::string m_curr_characters;
|
|
@@ -365,6 +369,7 @@ namespace Slic3r {
|
|
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
|
|
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
|
|
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
|
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
|
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
|
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);
|
|
void _extract_sla_support_points_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_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
|
|
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
|
|
@@ -476,6 +481,7 @@ namespace Slic3r {
|
|
m_curr_config.volume_id = -1;
|
|
m_curr_config.volume_id = -1;
|
|
m_objects_metadata.clear();
|
|
m_objects_metadata.clear();
|
|
m_layer_heights_profiles.clear();
|
|
m_layer_heights_profiles.clear();
|
|
|
|
+ m_layer_config_ranges.clear();
|
|
m_sla_support_points.clear();
|
|
m_sla_support_points.clear();
|
|
m_curr_metadata_name.clear();
|
|
m_curr_metadata_name.clear();
|
|
m_curr_characters.clear();
|
|
m_curr_characters.clear();
|
|
@@ -546,9 +552,14 @@ namespace Slic3r {
|
|
|
|
|
|
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
|
|
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
|
|
{
|
|
{
|
|
- // extract slic3r lazer heights profile file
|
|
|
|
|
|
+ // extract slic3r layer heights profile file
|
|
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
|
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
|
}
|
|
}
|
|
|
|
+ if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE))
|
|
|
|
+ {
|
|
|
|
+ // extract slic3r layer config ranges file
|
|
|
|
+ _extract_layer_config_ranges_from_archive(archive, stat);
|
|
|
|
+ }
|
|
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
|
|
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
|
|
{
|
|
{
|
|
// extract sla support points file
|
|
// extract sla support points file
|
|
@@ -592,6 +603,11 @@ namespace Slic3r {
|
|
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
|
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
|
model_object->layer_height_profile = obj_layer_heights_profile->second;
|
|
model_object->layer_height_profile = obj_layer_heights_profile->second;
|
|
|
|
|
|
|
|
+ // m_layer_config_ranges are indexed by a 1 based model object index.
|
|
|
|
+ IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
|
|
|
|
+ if (obj_layer_config_ranges != m_layer_config_ranges.end())
|
|
|
|
+ model_object->layer_config_ranges = obj_layer_config_ranges->second;
|
|
|
|
+
|
|
// m_sla_support_points are indexed by a 1 based model object index.
|
|
// m_sla_support_points are indexed by a 1 based model object index.
|
|
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
|
|
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
|
|
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
|
|
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
|
|
@@ -769,6 +785,115 @@ namespace Slic3r {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ void _3MF_Importer::_extract_layer_config_ranges_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 layer config ranges data to buffer");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (buffer.back() == '|')
|
|
|
|
+ buffer.pop_back();
|
|
|
|
+
|
|
|
|
+ std::vector<std::string> objects;
|
|
|
|
+ boost::split(objects, buffer, boost::is_any_of("|"), boost::token_compress_off);
|
|
|
|
+
|
|
|
|
+ for (std::string& object : objects)
|
|
|
|
+ {
|
|
|
|
+ // delete all spaces
|
|
|
|
+ boost::replace_all(object, " ", "");
|
|
|
|
+
|
|
|
|
+ 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");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(object_id);
|
|
|
|
+ if (object_item != m_layer_config_ranges.end()) {
|
|
|
|
+ add_error("Found duplicated layer config range");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ t_layer_config_ranges config_ranges;
|
|
|
|
+
|
|
|
|
+ // get ranges information
|
|
|
|
+ for (size_t i = 1; i < object_data.size(); ++i)
|
|
|
|
+ {
|
|
|
|
+ if (object_data[i].back() == '\n')
|
|
|
|
+ object_data[i].pop_back();
|
|
|
|
+
|
|
|
|
+ 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
|
|
|
|
+ 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[z_range];
|
|
|
|
+
|
|
|
|
+ // get configuration options for the range
|
|
|
|
+ for (size_t j = 1; j < range_data.size(); ++j)
|
|
|
|
+ {
|
|
|
|
+ std::vector<std::string> key_val;
|
|
|
|
+ boost::split(key_val, range_data[j], boost::is_any_of("="), boost::token_compress_off);
|
|
|
|
+ if (key_val.size() != 2) {
|
|
|
|
+ add_error("Error while reading config value");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ config.set_deserialize(key_val[0], key_val[1]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!config_ranges.empty())
|
|
|
|
+ m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(object_id, config_ranges));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
void _3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
|
void _3MF_Importer::_extract_sla_support_points_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)
|
|
@@ -1624,6 +1749,7 @@ namespace Slic3r {
|
|
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
|
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
|
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
|
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
|
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
|
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
|
|
|
+ bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
|
|
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
|
|
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_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_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
|
|
@@ -1684,6 +1810,16 @@ namespace Slic3r {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt").
|
|
|
|
+ // All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
|
|
|
+ // The index differes from the index of an object ID of an object instance of a 3MF file!
|
|
|
|
+ if (!_add_layer_config_ranges_file_to_archive(archive, model))
|
|
|
|
+ {
|
|
|
|
+ close_zip_writer(&archive);
|
|
|
|
+ boost::filesystem::remove(filename);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
// Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
|
|
// Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
|
|
// All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
|
// All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
|
@@ -2013,6 +2149,50 @@ namespace Slic3r {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
|
|
|
|
+ {
|
|
|
|
+ std::string out = "";
|
|
|
|
+ char buffer[1024];
|
|
|
|
+
|
|
|
|
+ unsigned int object_cnt = 0;
|
|
|
|
+ for (const ModelObject* object : model.objects)
|
|
|
|
+ {
|
|
|
|
+ object_cnt++;
|
|
|
|
+ const t_layer_config_ranges& ranges = object->layer_config_ranges;
|
|
|
|
+ if (!ranges.empty())
|
|
|
|
+ {
|
|
|
|
+ sprintf(buffer, "object_id=%d\n", object_cnt);
|
|
|
|
+ out += buffer;
|
|
|
|
+
|
|
|
|
+ // Store the layer config ranges.
|
|
|
|
+ for (const auto& range : ranges)
|
|
|
|
+ {
|
|
|
|
+ // store minX and maxZ
|
|
|
|
+ sprintf(buffer, "*z_range = %f;%f\n", range.first.first, range.first.second);
|
|
|
|
+ out += buffer;
|
|
|
|
+
|
|
|
|
+ // store range configuration
|
|
|
|
+ const DynamicPrintConfig& config = range.second;
|
|
|
|
+ for (const std::string& key : config.keys())
|
|
|
|
+ out += " " + key + " = " + config.serialize(key) + "\n";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ out += "|";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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))
|
|
|
|
+ {
|
|
|
|
+ add_error("Unable to add layer heights profile file to archive");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
|
|
bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
|
|
{
|
|
{
|
|
std::string out = "";
|
|
std::string out = "";
|