mirror of
https://github.com/QIDITECH/QIDIStudio.git
synced 2026-02-07 12:21:50 +03:00
update libslic3r
This commit is contained in:
@@ -18,6 +18,8 @@
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
@@ -46,6 +48,11 @@ namespace pt = boost::property_tree;
|
||||
#include <Eigen/Dense>
|
||||
#include "miniz_extension.hpp"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "EmbossShape.hpp"
|
||||
#include "ExPolygonSerialize.hpp"
|
||||
#include "NSVGUtils.hpp"
|
||||
|
||||
#include <fast_float/fast_float.h>
|
||||
|
||||
// Slightly faster than sprintf("%.9g"), but there is an issue with the karma floating point formatter,
|
||||
@@ -130,6 +137,9 @@ const std::string QDT_APPLICATION_TAG = "Application";
|
||||
const std::string QDT_MAKERLAB_TAG = "MakerLab";
|
||||
const std::string QDT_MAKERLAB_VERSION_TAG = "MakerLabVersion";
|
||||
|
||||
const std::string QDT_MAKERLAB_NAME = "MakerLab";
|
||||
const std::string QDT_MAKERLAB_REGION = "MakerLabRegion";
|
||||
const std::string QDT_MAKERLAB_ID = "MakerLabFileId";
|
||||
|
||||
const std::string QDT_PROFILE_TITLE_TAG = "ProfileTitle";
|
||||
const std::string QDT_PROFILE_COVER_TAG = "ProfileCover";
|
||||
@@ -163,6 +173,7 @@ const std::string QDS_MODEL_CONFIG_RELS_FILE = "Metadata/_rels/model_settings.co
|
||||
const std::string SLICE_INFO_CONFIG_FILE = "Metadata/slice_info.config";
|
||||
const std::string QDS_LAYER_HEIGHTS_PROFILE_FILE = "Metadata/layer_heights_profile.txt";
|
||||
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/layer_config_ranges.xml";
|
||||
const std::string BRIM_EAR_POINTS_FILE = "Metadata/brim_ear_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 std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/custom_gcode_per_layer.xml";
|
||||
@@ -332,6 +343,40 @@ static constexpr const char* MESH_STAT_FACETS_REMOVED = "facets_removed";
|
||||
static constexpr const char* MESH_STAT_FACETS_RESERVED = "facets_reversed";
|
||||
static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges";
|
||||
|
||||
// Store / load of TextConfiguration
|
||||
static constexpr const char *TEXT_DATA_ATTR = "text";
|
||||
// TextConfiguration::EmbossStyle
|
||||
static constexpr const char *STYLE_NAME_ATTR = "style_name";
|
||||
static constexpr const char *FONT_DESCRIPTOR_ATTR = "font_descriptor";
|
||||
static constexpr const char *FONT_DESCRIPTOR_TYPE_ATTR = "font_descriptor_type";
|
||||
|
||||
// TextConfiguration::FontProperty
|
||||
static constexpr const char *CHAR_GAP_ATTR = "char_gap";
|
||||
static constexpr const char *LINE_GAP_ATTR = "line_gap";
|
||||
static constexpr const char *LINE_HEIGHT_ATTR = "line_height";
|
||||
static constexpr const char *BOLDNESS_ATTR = "boldness";
|
||||
static constexpr const char *SKEW_ATTR = "skew";
|
||||
static constexpr const char *PER_GLYPH_ATTR = "per_glyph";
|
||||
static constexpr const char *HORIZONTAL_ALIGN_ATTR = "horizontal";
|
||||
static constexpr const char *VERTICAL_ALIGN_ATTR = "vertical";
|
||||
static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
|
||||
|
||||
static constexpr const char *FONT_FAMILY_ATTR = "family";
|
||||
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
|
||||
static constexpr const char *FONT_STYLE_ATTR = "style";
|
||||
static constexpr const char *FONT_WEIGHT_ATTR = "weight";
|
||||
|
||||
// Store / load of EmbossShape
|
||||
static constexpr const char *SHAPE_TAG = "slic3rpe:shape";
|
||||
static constexpr const char *SHAPE_SCALE_ATTR = "scale";
|
||||
static constexpr const char *UNHEALED_ATTR = "unhealed";
|
||||
static constexpr const char *SVG_FILE_PATH_ATTR = "filepath";
|
||||
static constexpr const char *SVG_FILE_PATH_IN_3MF_ATTR = "filepath3mf";
|
||||
|
||||
// EmbossProjection
|
||||
static constexpr const char *DEPTH_ATTR = "depth";
|
||||
static constexpr const char *USE_SURFACE_ATTR = "use_surface";
|
||||
// static constexpr const char *FIX_TRANSFORMATION_ATTR = "transform";
|
||||
|
||||
const unsigned int QDS_VALID_OBJECT_TYPES_COUNT = 2;
|
||||
const char* QDS_VALID_OBJECT_TYPES[] =
|
||||
@@ -719,7 +764,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
RepairedMeshErrors mesh_stats;
|
||||
ModelVolumeType part_type;
|
||||
TextInfo text_info;
|
||||
|
||||
std::optional<EmbossShape> shape_configuration;
|
||||
VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id, ModelVolumeType type = ModelVolumeType::MODEL_PART)
|
||||
: first_triangle_id(first_triangle_id)
|
||||
, last_triangle_id(last_triangle_id)
|
||||
@@ -770,8 +815,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
//typedef std::map<Id, Geometry> IdToGeometryMap;
|
||||
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
||||
typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
||||
typedef std::map<int, BrimPoints> IdToBrimPointsMap;
|
||||
/*typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
||||
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;*/
|
||||
using PathToEmbossShapeFileMap = std::map<std::string, std::shared_ptr<std::string>>;
|
||||
|
||||
struct ObjectImporter
|
||||
{
|
||||
@@ -836,7 +883,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
bool extract_object_model()
|
||||
{
|
||||
mz_zip_archive archive;
|
||||
mz_zip_archive_file_stat stat;
|
||||
//mz_zip_archive_file_stat stat;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
||||
if (!open_zip_reader(&archive, zip_path)) {
|
||||
@@ -964,8 +1011,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
IdToCutObjectInfoMap m_cut_object_infos;
|
||||
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
||||
IdToLayerConfigRangesMap m_layer_config_ranges;
|
||||
IdToBrimPointsMap m_brim_ear_points;
|
||||
/*IdToSlaSupportPointsMap m_sla_support_points;
|
||||
IdToSlaDrainHolesMap m_sla_drain_holes;*/
|
||||
PathToEmbossShapeFileMap m_path_to_emboss_shape_files;
|
||||
std::string m_curr_metadata_name;
|
||||
std::string m_curr_characters;
|
||||
std::string m_name;
|
||||
@@ -1019,6 +1068,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// add backup & restore logic
|
||||
bool _load_model_from_file(std::string filename, Model& model, PlateDataPtrs& plate_data_list, std::vector<Preset*>& project_presets, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions, Import3mfProgressFn proFn = nullptr,
|
||||
QDTProject* project = nullptr, int plate_id = 0);
|
||||
bool _is_svg_shape_file(const std::string &filename) const;
|
||||
bool _extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)>, bool restore = false);
|
||||
bool _extract_xml_from_archive(mz_zip_archive& archive, std::string const & path, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
|
||||
bool _extract_xml_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, XML_StartElementHandler start_handler, XML_EndElementHandler end_handler);
|
||||
@@ -1028,6 +1078,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
|
||||
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_brim_ear_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
|
||||
void _extract_custom_gcode_per_print_z_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
|
||||
@@ -1039,6 +1090,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
|
||||
void _extract_auxiliary_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
|
||||
void _extract_file_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||
void _extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat);
|
||||
|
||||
// handlers to parse the .model file
|
||||
void _handle_start_model_xml_element(const char* name, const char** attributes);
|
||||
@@ -1094,6 +1146,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
bool _handle_start_metadata(const char** attributes, unsigned int num_attributes);
|
||||
bool _handle_end_metadata();
|
||||
|
||||
bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes);
|
||||
|
||||
bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
|
||||
|
||||
void _apply_transform(ModelInstance& instance, const Transform3d& transform);
|
||||
@@ -1225,6 +1279,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
m_objects_metadata.clear();
|
||||
m_layer_heights_profiles.clear();
|
||||
m_layer_config_ranges.clear();
|
||||
m_brim_ear_points.clear();
|
||||
//m_sla_support_points.clear();
|
||||
m_curr_metadata_name.clear();
|
||||
m_curr_characters.clear();
|
||||
@@ -1720,6 +1775,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
// extract slic3r layer config ranges file
|
||||
_extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
|
||||
}
|
||||
else if (boost::algorithm::iequals(name, BRIM_EAR_POINTS_FILE)) {
|
||||
// extract slic3r config file
|
||||
_extract_brim_ear_points_from_archive(archive, stat);
|
||||
}
|
||||
//QDS: disable SLA related files currently
|
||||
/*else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE)) {
|
||||
// extract sla support points file
|
||||
@@ -1769,6 +1828,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
add_error("Archive does not contain a valid model config");
|
||||
return false;
|
||||
}
|
||||
} else if (_is_svg_shape_file(name)) {
|
||||
_extract_embossed_svg_shape_file(name, archive, stat);
|
||||
}
|
||||
else if (!dont_load_config && boost::algorithm::iequals(name, SLICE_INFO_CONFIG_FILE)) {
|
||||
m_parsing_slice_info = true;
|
||||
@@ -1900,6 +1961,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
if (obj_layer_config_ranges != m_layer_config_ranges.end())
|
||||
model_object->layer_config_ranges = std::move(obj_layer_config_ranges->second);
|
||||
|
||||
IdToBrimPointsMap::iterator obj_brim_points = m_brim_ear_points.find(object.second + 1);
|
||||
if (obj_brim_points != m_brim_ear_points.end())
|
||||
model_object->brim_points = std::move(obj_brim_points->second);
|
||||
|
||||
// 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);
|
||||
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
|
||||
@@ -2167,6 +2232,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Importer::_is_svg_shape_file(const std::string &name) const {
|
||||
return boost::starts_with(name, MODEL_FOLDER) && boost::ends_with(name, ".svg");
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Importer::_extract_from_archive(mz_zip_archive& archive, std::string const & path, std::function<bool (mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)> extract, bool restore)
|
||||
{
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
||||
@@ -2710,6 +2779,78 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _QDS_3MF_Importer::_extract_brim_ear_points_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_to_mem(&archive, stat.m_file_index, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||
if (res == 0) {
|
||||
add_error("Error while reading brim ear 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 qds_3mf.hpp
|
||||
int version = 0;
|
||||
std::string key("brim_points_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;
|
||||
}
|
||||
|
||||
IdToBrimPointsMap::iterator object_item = m_brim_ear_points.find(object_id);
|
||||
if (object_item != m_brim_ear_points.end()) {
|
||||
add_error("Found duplicated brim ear points");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> object_data_points;
|
||||
boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
|
||||
|
||||
std::vector<BrimPoint> brim_ear_points;
|
||||
if (version == 0) {
|
||||
for (unsigned int i=0; i<object_data_points.size(); i+=4)
|
||||
brim_ear_points.emplace_back(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())),
|
||||
float(std::atof(object_data_points[i+3].c_str())));
|
||||
}
|
||||
|
||||
if (!brim_ear_points.empty())
|
||||
m_brim_ear_points.insert({ object_id, brim_ear_points });
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
void _QDS_3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
||||
{
|
||||
@@ -2878,6 +3019,30 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
}
|
||||
}*/
|
||||
|
||||
void _QDS_3MF_Importer::_extract_embossed_svg_shape_file(const std::string &filename, mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
|
||||
{
|
||||
assert(m_path_to_emboss_shape_files.find(filename) == m_path_to_emboss_shape_files.end());
|
||||
auto file = std::make_unique<std::string>(stat.m_uncomp_size, '\0');
|
||||
mz_bool res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, (void *) file->data(), stat.m_uncomp_size, 0);
|
||||
if (res == 0) {
|
||||
add_error("Error while reading svg shape for emboss");
|
||||
return;
|
||||
}
|
||||
|
||||
// store for case svg is loaded before volume
|
||||
m_path_to_emboss_shape_files[filename] = std::move(file);
|
||||
|
||||
// find embossed volume, for case svg is loaded after volume
|
||||
for (const ModelObject *object : m_model->objects)
|
||||
for (ModelVolume *volume : object->volumes) {
|
||||
std::optional<EmbossShape> &es = volume->emboss_shape;
|
||||
if (!es.has_value()) continue;
|
||||
std::optional<EmbossShape::SvgFile> &svg = es->svg_file;
|
||||
if (!svg.has_value()) continue;
|
||||
if (filename.compare(svg->path_in_3mf) == 0) svg->file_data = m_path_to_emboss_shape_files[filename];
|
||||
}
|
||||
}
|
||||
|
||||
void _QDS_3MF_Importer::_extract_custom_gcode_per_print_z_from_archive(::mz_zip_archive &archive, const mz_zip_archive_file_stat &stat)
|
||||
{
|
||||
//QDS: add plate tree related logic
|
||||
@@ -3088,7 +3253,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
res = _handle_start_assemble_item(attributes, num_attributes);
|
||||
else if (::strcmp(TEXT_INFO_TAG, name) == 0)
|
||||
res = _handle_start_text_info_item(attributes, num_attributes);
|
||||
|
||||
else if (::strcmp(SHAPE_TAG, name) == 0)
|
||||
res = _handle_start_shape_configuration(attributes, num_attributes);
|
||||
if (!res)
|
||||
_stop_xml_parser();
|
||||
}
|
||||
@@ -3641,6 +3807,40 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Definition of read/write method for EmbossShape
|
||||
static void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive);
|
||||
static std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes);
|
||||
|
||||
bool _QDS_3MF_Importer::_handle_start_shape_configuration(const char **attributes, unsigned int num_attributes)
|
||||
{
|
||||
IdToMetadataMap::iterator object = m_objects_metadata.find(m_curr_config.object_id);
|
||||
if (object == m_objects_metadata.end()) {
|
||||
add_error("Can not assign volume mesh to a valid object");
|
||||
return false;
|
||||
}
|
||||
auto &volumes = object->second.volumes;
|
||||
if (volumes.empty()) {
|
||||
add_error("Can not assign mesh to a valid volume");
|
||||
return false;
|
||||
}
|
||||
ObjectMetadata::VolumeMetadata &volume = volumes.back();
|
||||
volume.shape_configuration = read_emboss_shape(attributes, num_attributes);
|
||||
if (!volume.shape_configuration.has_value()) return false;
|
||||
|
||||
// Fill svg file content into shape_configuration
|
||||
std::optional<EmbossShape::SvgFile> &svg = volume.shape_configuration->svg_file;
|
||||
if (!svg.has_value()) return true; // do not contain svg file
|
||||
|
||||
const std::string &path = svg->path_in_3mf;
|
||||
if (path.empty()) return true; // do not contain svg file
|
||||
|
||||
auto it = m_path_to_emboss_shape_files.find(path);
|
||||
if (it == m_path_to_emboss_shape_files.end()) return true; // svg file is not loaded yet
|
||||
|
||||
svg->file_data = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
|
||||
{
|
||||
static const unsigned int MAX_RECURSIONS = 10;
|
||||
@@ -4205,7 +4405,6 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
}
|
||||
|
||||
ObjectMetadata::VolumeMetadata &volume = object->second.volumes[m_curr_config.volume_id];
|
||||
|
||||
TextInfo text_info;
|
||||
text_info.m_text = xml_unescape(qds_get_attribute_value_string(attributes, num_attributes, TEXT_ATTR));
|
||||
text_info.m_font_name = qds_get_attribute_value_string(attributes, num_attributes, FONT_NAME_ATTR);
|
||||
@@ -4293,9 +4492,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
} else if (boost::starts_with(type, "http://schemas.openxmlformats.org/") && boost::ends_with(type, "thumbnail")) {
|
||||
if (boost::algorithm::ends_with(path, ".png"))
|
||||
m_thumbnail_path = path;
|
||||
} else if (boost::starts_with(type, "http://schemas.qidilab.com/") && boost::ends_with(type, "cover-thumbnail-middle")) {
|
||||
} else if (boost::starts_with(type, "http://schemas.qiditech.com/") && boost::ends_with(type, "cover-thumbnail-middle")) {
|
||||
m_thumbnail_middle = path;
|
||||
} else if (boost::starts_with(type, "http://schemas.qidilab.com/") && boost::ends_with(type, "cover-thumbnail-small")) {
|
||||
} else if (boost::starts_with(type, "http://schemas.qiditech.com/") && boost::ends_with(type, "cover-thumbnail-small")) {
|
||||
m_thumbnail_small = path;
|
||||
}
|
||||
return true;
|
||||
@@ -4510,7 +4709,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
}
|
||||
|
||||
volume->set_type(volume_data->part_type);
|
||||
|
||||
if (auto &es = volume_data->shape_configuration; es.has_value())
|
||||
volume->emboss_shape = std::move(es);
|
||||
if (!volume_data->text_info.m_text.empty())
|
||||
volume->set_text_info(volume_data->text_info);
|
||||
|
||||
@@ -5279,7 +5479,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
bool save_model_to_file(StoreParams& store_params);
|
||||
// add backup logic
|
||||
bool save_object_mesh(const std::string& temp_path, ModelObject const & object, int obj_id);
|
||||
|
||||
static void add_transformation(std::stringstream &stream, const Transform3d &tr);
|
||||
private:
|
||||
//QDS: add plate data related logic
|
||||
bool _save_model_to_file(const std::string& filename,
|
||||
@@ -5317,6 +5517,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const;
|
||||
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_brim_ear_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);
|
||||
@@ -5725,6 +5926,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_add_brim_ear_points_file_to_archive(archive, model)) {
|
||||
close_zip_writer(&archive);
|
||||
return false;
|
||||
}
|
||||
|
||||
// QDS progress point
|
||||
/*BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format("export 3mf EXPORT_STAGE_ADD_SUPPORT\n");
|
||||
if (proFn) {
|
||||
@@ -6076,18 +6282,18 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
|
||||
if (data._3mf_printer_thumbnail_middle.empty()) {
|
||||
stream << " <Relationship Target=\"/Metadata/plate_1.png"
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
} else {
|
||||
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
}
|
||||
|
||||
if (data._3mf_printer_thumbnail_small.empty()) {
|
||||
stream << "<Relationship Target=\"/Metadata/plate_1_small.png"
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
} else {
|
||||
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -6098,11 +6304,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
|
||||
thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
|
||||
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-middle\"/>\n";
|
||||
|
||||
thumbnail_file_str = (boost::format("Metadata/plate_%1%_small.png") % (export_plate_idx + 1)).str();
|
||||
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qidilab.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
<< "\" Id=\"rel-5\" Type=\"http://schemas.qiditech.com/package/2021/cover-thumbnail-small\"/>\n";
|
||||
}
|
||||
}
|
||||
else if (targets.empty()) {
|
||||
@@ -6182,7 +6388,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
std::stringstream stream;
|
||||
reset_stream(stream);
|
||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:QIDIStudio=\"http://schemas.qidilab.com/package/2021\"";
|
||||
stream << "<" << MODEL_TAG << " unit=\"millimeter\" xml:lang=\"en-US\" xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\" xmlns:QIDIStudio=\"http://schemas.qiditech.com/package/2021\"";
|
||||
if (m_production_ext)
|
||||
stream << " xmlns:p=\"http://schemas.microsoft.com/3dmanufacturing/production/2015/06\" requiredextensions=\"p\"";
|
||||
stream << ">\n";
|
||||
@@ -6259,6 +6465,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
metadata_item_map[QDT_MAKERLAB_VERSION_TAG] = xml_escape(model.mk_version);
|
||||
BOOST_LOG_TRIVIAL(info) << "saved mk_version " << model.mk_version;
|
||||
}
|
||||
|
||||
/*for ml*/
|
||||
if (model.mk_name.empty() && !model.makerlab_name.empty()) {
|
||||
metadata_item_map[QDT_MAKERLAB_NAME] = model.makerlab_name;
|
||||
metadata_item_map[QDT_MAKERLAB_REGION] = model.makerlab_region;
|
||||
metadata_item_map[QDT_MAKERLAB_ID] = model.makerlab_id;
|
||||
}
|
||||
|
||||
if (!model.md_name.empty()) {
|
||||
for (unsigned int i = 0; i < model.md_name.size(); i++)
|
||||
{
|
||||
@@ -6768,6 +6982,17 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
return flush(output_buffer, true);
|
||||
}
|
||||
|
||||
void _QDS_3MF_Exporter::add_transformation(std::stringstream &stream, const Transform3d &tr)
|
||||
{
|
||||
for (unsigned c = 0; c < 4; ++c) {
|
||||
for (unsigned r = 0; r < 3; ++r) {
|
||||
stream << tr(r, c);
|
||||
if (r != 2 || c != 3)
|
||||
stream << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Exporter::_add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items) const
|
||||
{
|
||||
// This happens for empty projects
|
||||
@@ -6788,13 +7013,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
if (!item.path.empty())
|
||||
stream << "\" " << PPATH_ATTR << "=\"" << xml_escape(item.path);
|
||||
stream << "\" " << TRANSFORM_ATTR << "=\"";
|
||||
for (unsigned c = 0; c < 4; ++c) {
|
||||
for (unsigned r = 0; r < 3; ++r) {
|
||||
stream << item.transform(r, c);
|
||||
if (r != 2 || c != 3)
|
||||
stream << " ";
|
||||
}
|
||||
}
|
||||
add_transformation(stream, item.transform);
|
||||
stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\"/>\n";
|
||||
}
|
||||
|
||||
@@ -6838,6 +7057,40 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Exporter::_add_brim_ear_points_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||
{
|
||||
std::string out = "";
|
||||
char buffer[1024];
|
||||
|
||||
unsigned int count = 0;
|
||||
for (const ModelObject* object : model.objects) {
|
||||
++count;
|
||||
const BrimPoints& brim_points = object->brim_points;
|
||||
if (!brim_points.empty()) {
|
||||
sprintf(buffer, "object_id=%d|", count);
|
||||
out += buffer;
|
||||
|
||||
// Store the layer height profile as a single space separated list.
|
||||
for (size_t i = 0; i < brim_points.size(); ++i) {
|
||||
sprintf(buffer, (i==0 ? "%f %f %f %f" : " %f %f %f %f"), brim_points[i].pos(0), brim_points[i].pos(1), brim_points[i].pos(2), brim_points[i].head_front_radius);
|
||||
out += buffer;
|
||||
}
|
||||
out += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (!out.empty()) {
|
||||
// Adds version header at the beginning:
|
||||
out = std::string("brim_points_format_version=") + std::to_string(brim_points_format_version) + std::string("\n") + out;
|
||||
|
||||
if (!mz_zip_writer_add_mem(&archive, BRIM_EAR_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
|
||||
add_error("Unable to add brim ear points file to archive");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _QDS_3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||
{
|
||||
std::string out = "";
|
||||
@@ -7188,6 +7441,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
stream << " <" << METADATA_TAG << " "<< KEY_ATTR << "=\"" << key << "\" " << VALUE_ATTR << "=\"" << volume->config.opt_serialize(key) << "\"/>\n";
|
||||
}
|
||||
|
||||
if (const std::optional<EmbossShape> &es = volume->emboss_shape; es.has_value())
|
||||
to_xml(stream, *es, *volume, archive);
|
||||
|
||||
const TextInfo &text_info = volume->get_text_info();
|
||||
if (!text_info.m_text.empty())
|
||||
_add_text_info_to_archive(stream, text_info);
|
||||
@@ -7307,7 +7563,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
|
||||
if (!m_skip_model && instance_size > 0)
|
||||
{
|
||||
for (unsigned int j = 0; j < instance_size; ++j)
|
||||
for (int j = 0; j < instance_size; ++j)
|
||||
{
|
||||
stream << " <" << INSTANCE_TAG << ">\n";
|
||||
int obj_id = plate_data->objects_and_instances[j].first;
|
||||
@@ -7352,7 +7608,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||
|
||||
// write model rels
|
||||
if (save_gcode)
|
||||
_add_relationships_file_to_archive(archive, QDS_MODEL_CONFIG_RELS_FILE, gcode_paths, {"http://schemas.qidilab.com/package/2021/gcode"}, Slic3r::PackingTemporaryData(), export_plate_idx);
|
||||
_add_relationships_file_to_archive(archive, QDS_MODEL_CONFIG_RELS_FILE, gcode_paths, {"http://schemas.qiditech.com/package/2021/gcode"}, Slic3r::PackingTemporaryData(), export_plate_idx);
|
||||
|
||||
if (!m_skip_model) {
|
||||
//QDS: store assemble related info
|
||||
@@ -8290,4 +8546,148 @@ SaveObjectGaurd::~SaveObjectGaurd()
|
||||
_QDS_Backup_Manager::get().pop_object_gaurd();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Conversion with bidirectional map
|
||||
// F .. first, S .. second
|
||||
template<typename F, typename S> F bimap_cvt(const boost::bimap<F, S> &bmap, S s, const F &def_value)
|
||||
{
|
||||
const auto &map = bmap.right;
|
||||
auto found_item = map.find(s);
|
||||
|
||||
// only for back and forward compatibility
|
||||
assert(found_item != map.end());
|
||||
if (found_item == map.end()) return def_value;
|
||||
|
||||
return found_item->second;
|
||||
}
|
||||
|
||||
template<typename F, typename S> S bimap_cvt(const boost::bimap<F, S> &bmap, F f, const S &def_value)
|
||||
{
|
||||
const auto &map = bmap.left;
|
||||
auto found_item = map.find(f);
|
||||
|
||||
// only for back and forward compatibility
|
||||
assert(found_item != map.end());
|
||||
if (found_item == map.end()) return def_value;
|
||||
|
||||
return found_item->second;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
Transform3d create_fix(const std::optional<Transform3d> &prev, const ModelVolume &volume)
|
||||
{
|
||||
// IMPROVE: check if volume was modified (translated, rotated OR scaled)
|
||||
// when no change do not calculate transformation only store original fix matrix
|
||||
|
||||
// Create transformation used after load actual stored volume
|
||||
// Orca: do not bake volume transformation into meshes
|
||||
// const Transform3d &actual_trmat = volume.get_matrix();
|
||||
const Transform3d &actual_trmat = Transform3d::Identity();
|
||||
|
||||
const auto &vertices = volume.mesh().its.vertices;
|
||||
Vec3d min = actual_trmat * vertices.front().cast<double>();
|
||||
Vec3d max = min;
|
||||
for (const Vec3f &v : vertices) {
|
||||
Vec3d vd = actual_trmat * v.cast<double>();
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (min[i] > vd[i]) min[i] = vd[i];
|
||||
if (max[i] < vd[i]) max[i] = vd[i];
|
||||
}
|
||||
}
|
||||
Vec3d center = (max + min) / 2;
|
||||
Transform3d post_trmat = Transform3d::Identity();
|
||||
post_trmat.translate(center);
|
||||
|
||||
Transform3d fix_trmat = actual_trmat.inverse() * post_trmat;
|
||||
if (!prev.has_value()) return fix_trmat;
|
||||
|
||||
// check whether fix somehow differ previous
|
||||
if (fix_trmat.isApprox(Transform3d::Identity(), 1e-5)) return *prev;
|
||||
|
||||
return *prev * fix_trmat;
|
||||
}
|
||||
|
||||
bool to_xml(std::stringstream &stream, const EmbossShape::SvgFile &svg, const ModelVolume &volume, mz_zip_archive &archive)
|
||||
{
|
||||
if (svg.path_in_3mf.empty())
|
||||
return true; // EmbossedText OR unwanted store .svg file into .3mf (protection of copyRight)
|
||||
|
||||
if (!svg.path.empty())
|
||||
stream << SVG_FILE_PATH_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path) << "\" ";
|
||||
stream << SVG_FILE_PATH_IN_3MF_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(svg.path_in_3mf) << "\" ";
|
||||
|
||||
std::shared_ptr<std::string> file_data = svg.file_data;
|
||||
assert(file_data != nullptr);
|
||||
if (file_data == nullptr && !svg.path.empty()) file_data = read_from_disk(svg.path);
|
||||
if (file_data == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Can't write svg file no filedata";
|
||||
return false;
|
||||
}
|
||||
const std::string &file_data_str = *file_data;
|
||||
|
||||
return mz_zip_writer_add_mem(&archive, svg.path_in_3mf.c_str(), (const void *) file_data_str.c_str(), file_data_str.size(), MZ_DEFAULT_COMPRESSION);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive)
|
||||
{
|
||||
stream << " <" << SHAPE_TAG << " ";
|
||||
if (es.svg_file.has_value())
|
||||
if (!to_xml(stream, *es.svg_file, volume, archive)) BOOST_LOG_TRIVIAL(warning) << "Can't write svg file defiden embossed shape into 3mf";
|
||||
|
||||
stream << SHAPE_SCALE_ATTR << "=\"" << es.scale << "\" ";
|
||||
|
||||
if (!es.final_shape.is_healed) stream << UNHEALED_ATTR << "=\"" << 1 << "\" ";
|
||||
|
||||
// projection
|
||||
const EmbossProjection &p = es.projection;
|
||||
stream << DEPTH_ATTR << "=\"" << p.depth << "\" ";
|
||||
if (p.use_surface) stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
|
||||
|
||||
// FIX of baked transformation
|
||||
Transform3d fix = create_fix(es.fix_3mf_tr, volume);
|
||||
stream << TRANSFORM_ATTR << "=\"";
|
||||
_QDS_3MF_Exporter::add_transformation(stream, fix);
|
||||
stream << "\" ";
|
||||
|
||||
stream << "/>\n"; // end SHAPE_TAG
|
||||
}
|
||||
|
||||
std::optional<EmbossShape> read_emboss_shape(const char **attributes, unsigned int num_attributes)
|
||||
{
|
||||
double scale = qds_get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
|
||||
int unhealed = qds_get_attribute_value_int(attributes, num_attributes, UNHEALED_ATTR);
|
||||
bool is_healed = unhealed != 1;
|
||||
|
||||
EmbossProjection projection;
|
||||
projection.depth = qds_get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
|
||||
if (is_approx(projection.depth, 0.)) projection.depth = 10.;
|
||||
|
||||
int use_surface = qds_get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
|
||||
if (use_surface == 1) projection.use_surface = true;
|
||||
|
||||
std::optional<Transform3d> fix_tr_mat;
|
||||
std::string fix_tr_mat_str = qds_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
|
||||
if (!fix_tr_mat_str.empty()) { fix_tr_mat = qds_get_transform_from_3mf_specs_string(fix_tr_mat_str); }
|
||||
|
||||
std::string file_path = qds_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR);
|
||||
std::string file_path_3mf = qds_get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_IN_3MF_ATTR);
|
||||
|
||||
// MayBe: store also shapes to not store svg
|
||||
// But be carefull curve will be lost -> scale will not change sampling
|
||||
// shapes could be loaded from SVG
|
||||
ExPolygonsWithIds shapes;
|
||||
// final shape could be calculated from shapes
|
||||
HealedExPolygons final_shape;
|
||||
final_shape.is_healed = is_healed;
|
||||
|
||||
EmbossShape::SvgFile svg{file_path, file_path_3mf};
|
||||
return EmbossShape{std::move(shapes), std::move(final_shape), scale, std::move(projection), std::move(fix_tr_mat), std::move(svg)};
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
Reference in New Issue
Block a user