add drain hole 3mf export and import
This commit is contained in:
parent
3b0241c98b
commit
5be66a52c0
@ -51,6 +51,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_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 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 std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
|
||||||
|
|
||||||
const char* MODEL_TAG = "model";
|
const char* MODEL_TAG = "model";
|
||||||
const char* RESOURCES_TAG = "resources";
|
const char* RESOURCES_TAG = "resources";
|
||||||
@ -227,6 +228,15 @@ bool is_valid_object_type(const std::string& type)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class...Args> std::string string_printf(const char *const fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
int bufflen = snprintf(nullptr, 0, fmt, std::forward<Args>(args)...);
|
||||||
|
std::vector<char> buffer(size_t(bufflen), '\0');
|
||||||
|
|
||||||
|
snprintf(buffer.data(), buffer.size(), fmt, std::forward<Args>(args)...);
|
||||||
|
return std::string(buffer.begin(), buffer.end());
|
||||||
|
}
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
//! macro used to mark string used at localization,
|
//! macro used to mark string used at localization,
|
||||||
@ -379,6 +389,7 @@ namespace Slic3r {
|
|||||||
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, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
||||||
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
||||||
|
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;
|
||||||
|
|
||||||
// Version of the 3mf file
|
// Version of the 3mf file
|
||||||
unsigned int m_version;
|
unsigned int m_version;
|
||||||
@ -397,6 +408,7 @@ namespace Slic3r {
|
|||||||
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
||||||
IdToLayerConfigRangesMap m_layer_config_ranges;
|
IdToLayerConfigRangesMap m_layer_config_ranges;
|
||||||
IdToSlaSupportPointsMap m_sla_support_points;
|
IdToSlaSupportPointsMap m_sla_support_points;
|
||||||
|
IdToSlaDrainHolesMap m_sla_drain_holes;
|
||||||
std::string m_curr_metadata_name;
|
std::string m_curr_metadata_name;
|
||||||
std::string m_curr_characters;
|
std::string m_curr_characters;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
@ -416,6 +428,7 @@ namespace Slic3r {
|
|||||||
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_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_sla_drain_holes_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);
|
||||||
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
|
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
|
||||||
@ -621,6 +634,11 @@ namespace Slic3r {
|
|||||||
// extract sla support points file
|
// extract sla support points file
|
||||||
_extract_sla_support_points_from_archive(archive, stat);
|
_extract_sla_support_points_from_archive(archive, stat);
|
||||||
}
|
}
|
||||||
|
else if (boost::algorithm::iequals(name, SLA_DRAIN_HOLES_FILE))
|
||||||
|
{
|
||||||
|
// extract sla support points file
|
||||||
|
_extract_sla_drain_holes_from_archive(archive, stat);
|
||||||
|
}
|
||||||
else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
|
else if (boost::algorithm::iequals(name, PRINT_CONFIG_FILE))
|
||||||
{
|
{
|
||||||
// extract slic3r print config file
|
// extract slic3r print config file
|
||||||
@ -671,6 +689,11 @@ namespace Slic3r {
|
|||||||
model_object->sla_points_status = sla::PointsStatus::UserModified;
|
model_object->sla_points_status = sla::PointsStatus::UserModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdToSlaDrainHolesMap::iterator obj_drain_holes = m_sla_drain_holes.find(object.second + 1);
|
||||||
|
if (obj_drain_holes != m_sla_drain_holes.end() && !obj_drain_holes->second.empty()) {
|
||||||
|
model_object->sla_drain_holes = obj_drain_holes->second;
|
||||||
|
}
|
||||||
|
|
||||||
IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first);
|
IdToMetadataMap::iterator obj_metadata = m_objects_metadata.find(object.first);
|
||||||
if (obj_metadata != m_objects_metadata.end())
|
if (obj_metadata != m_objects_metadata.end())
|
||||||
{
|
{
|
||||||
@ -942,8 +965,9 @@ namespace Slic3r {
|
|||||||
|
|
||||||
// Info on format versioning - see 3mf.hpp
|
// Info on format versioning - see 3mf.hpp
|
||||||
int version = 0;
|
int version = 0;
|
||||||
if (!objects.empty() && objects[0].find("support_points_format_version=") != std::string::npos) {
|
std::string key("support_points_format_version=");
|
||||||
objects[0].erase(objects[0].begin(), objects[0].begin() + 30); // removes the string
|
if (!objects.empty() && objects[0].find(key) != std::string::npos) {
|
||||||
|
objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
|
||||||
version = std::stoi(objects[0]);
|
version = std::stoi(objects[0]);
|
||||||
objects.erase(objects.begin()); // pop the header
|
objects.erase(objects.begin()); // pop the header
|
||||||
}
|
}
|
||||||
@ -1010,6 +1034,90 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 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=");
|
||||||
|
if (!objects.empty() && objects[0].find(key) != std::string::npos) {
|
||||||
|
objects[0].erase(objects[0].begin(), objects[0].begin() + long(key.size())); // removes the string
|
||||||
|
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) {
|
||||||
|
for (unsigned int i=0; i<object_data_points.size(); i+=8)
|
||||||
|
sla_drain_holes.emplace_back(Vec3f{float(std::atof(object_data_points[i+0].c_str())),
|
||||||
|
float(std::atof(object_data_points[i+1].c_str())),
|
||||||
|
float(std::atof(object_data_points[i+2].c_str()))},
|
||||||
|
Vec3f{float(std::atof(object_data_points[i+3].c_str())),
|
||||||
|
float(std::atof(object_data_points[i+4].c_str())),
|
||||||
|
float(std::atof(object_data_points[i+5].c_str()))},
|
||||||
|
float(std::atof(object_data_points[i+6].c_str())),
|
||||||
|
float(std::atof(object_data_points[i+7].c_str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sla_drain_holes.empty())
|
||||||
|
m_sla_drain_holes.insert(IdToSlaDrainHolesMap::value_type(object_id, sla_drain_holes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
|
bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
|
||||||
{
|
{
|
||||||
@ -1836,6 +1944,7 @@ namespace Slic3r {
|
|||||||
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_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_sla_drain_holes_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);
|
||||||
};
|
};
|
||||||
@ -1940,6 +2049,14 @@ namespace Slic3r {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_add_sla_drain_holes_file_to_archive(archive, model))
|
||||||
|
{
|
||||||
|
close_zip_writer(&archive);
|
||||||
|
boost::filesystem::remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adds slic3r print config file ("Metadata/Slic3r_PE.config").
|
// Adds slic3r print config file ("Metadata/Slic3r_PE.config").
|
||||||
// This file contains the content of FullPrintConfing / SLAFullPrintConfig.
|
// This file contains the content of FullPrintConfing / SLAFullPrintConfig.
|
||||||
if (config != nullptr)
|
if (config != nullptr)
|
||||||
@ -2388,6 +2505,50 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _3MF_Exporter::_add_sla_drain_holes_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
|
{
|
||||||
|
const char *const fmt = "object_id=%d|";
|
||||||
|
std::string out;
|
||||||
|
|
||||||
|
unsigned int count = 0;
|
||||||
|
for (const ModelObject* object : model.objects)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
auto& drain_holes = object->sla_drain_holes;
|
||||||
|
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"),
|
||||||
|
drain_holes[i].pos(0),
|
||||||
|
drain_holes[i].pos(1),
|
||||||
|
drain_holes[i].pos(2),
|
||||||
|
drain_holes[i].normal(0),
|
||||||
|
drain_holes[i].normal(1),
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config)
|
bool _3MF_Exporter::_add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config)
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
@ -20,6 +20,10 @@ namespace Slic3r {
|
|||||||
support_points_format_version = 1
|
support_points_format_version = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
drain_holes_format_version = 1
|
||||||
|
};
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
class DynamicPrintConfig;
|
class DynamicPrintConfig;
|
||||||
#if ENABLE_THUMBNAIL_GENERATOR
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
@ -183,6 +183,22 @@ static inline bool is_approx(Number value, Number test_value)
|
|||||||
return std::fabs(double(value) - double(test_value)) < double(EPSILON);
|
return std::fabs(double(value) - double(test_value)) < double(EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class...Args>
|
||||||
|
std::string string_printf(const char *const fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
static const size_t INITIAL_LEN = 1024;
|
||||||
|
std::vector<char> buffer(INITIAL_LEN, '\0');
|
||||||
|
|
||||||
|
int bufflen = snprintf(buffer.data(), INITIAL_LEN - 1, fmt, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
if (bufflen >= int(INITIAL_LEN)) {
|
||||||
|
buffer.resize(size_t(bufflen) + 1);
|
||||||
|
snprintf(buffer.data(), buffer.size(), fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(buffer.begin(), buffer.begin() + bufflen);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,4 +11,31 @@ TEST_CASE("sort_remove_duplicates", "[utils]") {
|
|||||||
REQUIRE(data_src == data_dst);
|
REQUIRE(data_src == data_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("string_printf", "[utils]") {
|
||||||
|
SECTION("Empty format with empty data should return empty string") {
|
||||||
|
std::string outs = Slic3r::string_printf("");
|
||||||
|
REQUIRE(outs.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("String output length should be the same as input") {
|
||||||
|
std::string outs = Slic3r::string_printf("1234");
|
||||||
|
REQUIRE(outs.size() == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("String format should be interpreted as with sprintf") {
|
||||||
|
std::string outs = Slic3r::string_printf("%d %f %s", 10, 11.4, " This is a string");
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
sprintf(buffer, "%d %f %s", 10, 11.4, " This is a string");
|
||||||
|
|
||||||
|
REQUIRE(outs.compare(buffer) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("String format should survive large input data") {
|
||||||
|
std::string input(2048, 'A');
|
||||||
|
std::string outs = Slic3r::string_printf("%s", input.c_str());
|
||||||
|
REQUIRE(outs.compare(input) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user