PRUSA 2.7.0

This commit is contained in:
sunsets
2023-12-27 18:02:35 +08:00
parent b33112327f
commit 0a3c63dcb1
488 changed files with 92371 additions and 29443 deletions

View File

@@ -36,6 +36,10 @@ namespace pt = boost::property_tree;
#include "miniz_extension.hpp"
#include "TextConfiguration.hpp"
#include "EmbossShape.hpp"
#include "ExPolygonSerialize.hpp"
#include "NSVGUtils.hpp"
#include <fast_float/fast_float.h>
@@ -157,12 +161,11 @@ static constexpr const char *FONT_DESCRIPTOR_TYPE_ATTR = "font_descriptor_type";
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 *DEPTH_ATTR = "depth";
static constexpr const char *USE_SURFACE_ATTR = "use_surface";
static constexpr const char *BOLDNESS_ATTR = "boldness";
static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *DISTANCE_ATTR = "distance";
static constexpr const char *ANGLE_ATTR = "angle";
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";
@@ -170,6 +173,15 @@ 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";
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";
const unsigned int VALID_OBJECT_TYPES_COUNT = 1;
const char* VALID_OBJECT_TYPES[] =
{
@@ -416,6 +428,7 @@ namespace Slic3r {
MetadataList metadata;
RepairedMeshErrors mesh_stats;
std::optional<TextConfiguration> text_configuration;
std::optional<EmbossShape> shape_configuration;
VolumeMetadata(unsigned int first_triangle_id, unsigned int last_triangle_id)
: first_triangle_id(first_triangle_id)
, last_triangle_id(last_triangle_id)
@@ -454,6 +467,7 @@ namespace Slic3r {
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>>;
// Version of the 3mf file
unsigned int m_version;
bool m_check_version;
@@ -483,6 +497,7 @@ namespace Slic3r {
IdToLayerConfigRangesMap m_layer_config_ranges;
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;
@@ -509,6 +524,7 @@ namespace Slic3r {
}
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions);
bool _is_svg_shape_file(const std::string &filename) const;
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
@@ -520,6 +536,7 @@ namespace Slic3r {
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, ConfigSubstitutionContext& subs_context, const std::string& archive_filename);
bool _extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model);
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);
@@ -570,6 +587,7 @@ namespace Slic3r {
bool _handle_end_metadata();
bool _handle_start_text_configuration(const char** attributes, unsigned int num_attributes);
bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes);
bool _create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
@@ -747,6 +765,9 @@ namespace Slic3r {
return false;
}
}
else if (_is_svg_shape_file(name)) {
_extract_embossed_svg_shape_file(name, archive, stat);
}
}
}
@@ -921,6 +942,9 @@ namespace Slic3r {
return true;
}
bool _3MF_Importer::_is_svg_shape_file(const std::string &name) const {
return boost::starts_with(name, MODEL_FOLDER) && boost::ends_with(name, ".svg");
}
bool _3MF_Importer::_extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
{
if (stat.m_uncomp_size == 0) {
@@ -1353,6 +1377,31 @@ namespace Slic3r {
}
}
void _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];
}
}
bool _3MF_Importer::_extract_model_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, Model& model)
{
if (stat.m_uncomp_size == 0) {
@@ -1552,6 +1601,8 @@ namespace Slic3r {
res = _handle_start_config_volume_mesh(attributes, num_attributes);
else if (::strcmp(METADATA_TAG, name) == 0)
res = _handle_start_config_metadata(attributes, num_attributes);
else if (::strcmp(SHAPE_TAG, name) == 0)
res = _handle_start_shape_configuration(attributes, num_attributes);
else if (::strcmp(TEXT_TAG, name) == 0)
res = _handle_start_text_configuration(attributes, num_attributes);
@@ -1905,7 +1956,14 @@ namespace Slic3r {
public:
TextConfigurationSerialization() = delete;
static const boost::bimap<EmbossStyle::Type, std::string_view> type_to_name;
using TypeToName = boost::bimap<EmbossStyle::Type, std::string_view>;
static const TypeToName type_to_name;
using HorizontalAlignToName = boost::bimap<FontProp::HorizontalAlign, std::string_view>;
static const HorizontalAlignToName horizontal_align_to_name;
using VerticalAlignToName = boost::bimap<FontProp::VerticalAlign, std::string_view>;
static const VerticalAlignToName vertical_align_to_name;
static EmbossStyle::Type get_type(std::string_view type) {
const auto& to_type = TextConfigurationSerialization::type_to_name.right;
@@ -1924,8 +1982,8 @@ namespace Slic3r {
}
static void to_xml(std::stringstream &stream, const TextConfiguration &tc);
static void create_fix_and_store(std::stringstream &stream, TextConfiguration tc, const ModelVolume& volume);
static std::optional<TextConfiguration> read(const char **attributes, unsigned int num_attributes);
static EmbossShape read_old(const char **attributes, unsigned int num_attributes);
};
bool _3MF_Importer::_handle_start_text_configuration(const char **attributes, unsigned int num_attributes)
@@ -1941,7 +1999,54 @@ namespace Slic3r {
}
ObjectMetadata::VolumeMetadata& volume = object->second.volumes.back();
volume.text_configuration = TextConfigurationSerialization::read(attributes, num_attributes);
return volume.text_configuration.has_value();
if (!volume.text_configuration.has_value())
return false;
// Is 3mf version with shapes?
if (volume.shape_configuration.has_value())
return true;
// Back compatibility for 3mf version without shapes
volume.shape_configuration = TextConfigurationSerialization::read_old(attributes, num_attributes);
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 _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 _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
@@ -2224,8 +2329,9 @@ namespace Slic3r {
volume->supported_facets.shrink_to_fit();
volume->seam_facets.shrink_to_fit();
volume->mmu_segmentation_facets.shrink_to_fit();
auto &tc = volume_data.text_configuration;
if (tc.has_value()) {
if (auto &es = volume_data.shape_configuration; es.has_value())
volume->emboss_shape = std::move(es);
if (auto &tc = volume_data.text_configuration; tc.has_value())
volume->text_configuration = std::move(tc);
//// Transformation before store to 3mf
@@ -2239,7 +2345,6 @@ namespace Slic3r {
//volume->text_configuration->fix_3mf_tr =
// pre_trmat.inverse() *
// volume->get_transformation().get_matrix();
}
// apply the remaining volume's metadata
for (const Metadata& metadata : volume_data.metadata) {
@@ -2371,6 +2476,7 @@ namespace Slic3r {
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data, bool zip64);
static void add_transformation(std::stringstream &stream, const Transform3d &tr);
private:
void _publish(Model &model);
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
@@ -3315,10 +3421,13 @@ namespace Slic3r {
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << 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);
// stores volume's text data
const auto &tc = volume->text_configuration;
if (tc.has_value())
TextConfigurationSerialization::create_fix_and_store(stream, *tc, *volume);
if (const std::optional<TextConfiguration> &tc = volume->text_configuration;
tc.has_value())
TextConfigurationSerialization::to_xml(stream, *tc);
// stores mesh's statistics
const RepairedMeshErrors& stats = volume->mesh().stats().repaired_errors;
@@ -3489,27 +3598,71 @@ bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config,
return res;
}
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
/// <summary>
/// TextConfiguration serialization
/// </summary>
using TypeToName = boost::bimap<EmbossStyle::Type, std::string_view>;
const TypeToName TextConfigurationSerialization::type_to_name =
const TextConfigurationSerialization::TypeToName TextConfigurationSerialization::type_to_name =
boost::assign::list_of<TypeToName::relation>
(EmbossStyle::Type::file_path, "file_name")
(EmbossStyle::Type::wx_win_font_descr, "wxFontDescriptor_Windows")
(EmbossStyle::Type::wx_lin_font_descr, "wxFontDescriptor_Linux")
(EmbossStyle::Type::wx_mac_font_descr, "wxFontDescriptor_MacOsX");
const TextConfigurationSerialization::HorizontalAlignToName TextConfigurationSerialization::horizontal_align_to_name =
boost::assign::list_of<HorizontalAlignToName::relation>
(FontProp::HorizontalAlign::left, "left")
(FontProp::HorizontalAlign::center, "center")
(FontProp::HorizontalAlign::right, "right");
const TextConfigurationSerialization::VerticalAlignToName TextConfigurationSerialization::vertical_align_to_name =
boost::assign::list_of<VerticalAlignToName::relation>
(FontProp::VerticalAlign::top, "top")
(FontProp::VerticalAlign::center, "middle")
(FontProp::VerticalAlign::bottom, "bottom");
void TextConfigurationSerialization::to_xml(std::stringstream &stream, const TextConfiguration &tc)
{
stream << " <" << TEXT_TAG << " ";
stream << TEXT_DATA_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(tc.text) << "\" ";
// font item
const EmbossStyle &fi = tc.style;
stream << STYLE_NAME_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(fi.name) << "\" ";
stream << FONT_DESCRIPTOR_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(fi.path) << "\" ";
stream << FONT_DESCRIPTOR_TYPE_ATTR << "=\"" << TextConfigurationSerialization::get_name(fi.type) << "\" ";
const EmbossStyle &style = tc.style;
stream << STYLE_NAME_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(style.name) << "\" ";
stream << FONT_DESCRIPTOR_ATTR << "=\"" << xml_escape_double_quotes_attribute_value(style.path) << "\" ";
constexpr std::string_view dafault_type{"undefined"};
std::string_view style_type = bimap_cvt(type_to_name, style.type, dafault_type);
stream << FONT_DESCRIPTOR_TYPE_ATTR << "=\"" << style_type << "\" ";
// font property
const FontProp &fp = tc.style.prop;
@@ -3519,17 +3672,14 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
stream << LINE_GAP_ATTR << "=\"" << *fp.line_gap << "\" ";
stream << LINE_HEIGHT_ATTR << "=\"" << fp.size_in_mm << "\" ";
stream << DEPTH_ATTR << "=\"" << fp.emboss << "\" ";
if (fp.use_surface)
stream << USE_SURFACE_ATTR << "=\"" << 1 << "\" ";
if (fp.boldness.has_value())
stream << BOLDNESS_ATTR << "=\"" << *fp.boldness << "\" ";
if (fp.skew.has_value())
stream << SKEW_ATTR << "=\"" << *fp.skew << "\" ";
if (fp.distance.has_value())
stream << DISTANCE_ATTR << "=\"" << *fp.distance << "\" ";
if (fp.angle.has_value())
stream << ANGLE_ATTR << "=\"" << *fp.angle << "\" ";
if (fp.per_glyph)
stream << PER_GLYPH_ATTR << "=\"" << 1 << "\" ";
stream << HORIZONTAL_ALIGN_ATTR << "=\"" << bimap_cvt(horizontal_align_to_name, fp.align.first, dafault_type) << "\" ";
stream << VERTICAL_ALIGN_ATTR << "=\"" << bimap_cvt(vertical_align_to_name, fp.align.second, dafault_type) << "\" ";
if (fp.collection_number.has_value())
stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
// font descriptor
@@ -3542,50 +3692,44 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
if (fp.weight.has_value())
stream << FONT_WEIGHT_ATTR << "=\"" << *fp.weight << "\" ";
// FIX of baked transformation
assert(tc.fix_3mf_tr.has_value());
stream << TRANSFORM_ATTR << "=\"";
_3MF_Exporter::add_transformation(stream, *tc.fix_3mf_tr);
stream << "\" ";
stream << "/>\n"; // end TEXT_TAG
}
namespace {
void TextConfigurationSerialization::create_fix_and_store(
std::stringstream &stream, TextConfiguration tc, const ModelVolume &volume)
{
const auto& vertices = volume.mesh().its.vertices;
assert(!vertices.empty());
if (vertices.empty()) {
to_xml(stream, tc);
return;
FontProp::HorizontalAlign read_horizontal_align(const char **attributes, unsigned int num_attributes, const TextConfigurationSerialization::HorizontalAlignToName& horizontal_align_to_name){
std::string horizontal_align_str = get_attribute_value_string(attributes, num_attributes, HORIZONTAL_ALIGN_ATTR);
// FIX of baked transformation
if (horizontal_align_str.empty())
return FontProp::HorizontalAlign::center;
if (horizontal_align_str.length() == 1) {
int horizontal_align_int = 0;
if(boost::spirit::qi::parse(horizontal_align_str.c_str(), horizontal_align_str.c_str() + 1, boost::spirit::qi::int_, horizontal_align_int))
return static_cast<FontProp::HorizontalAlign>(horizontal_align_int);
}
return bimap_cvt(horizontal_align_to_name, std::string_view(horizontal_align_str), FontProp::HorizontalAlign::center);
}
// IMPROVE: check if volume was modified (translated, rotated OR scaled)
FontProp::VerticalAlign read_vertical_align(const char **attributes, unsigned int num_attributes, const TextConfigurationSerialization::VerticalAlignToName& vertical_align_to_name){
std::string vertical_align_str = get_attribute_value_string(attributes, num_attributes, VERTICAL_ALIGN_ATTR);
// when no change do not calculate transformation only store original fix matrix
// Create transformation used after load actual stored volume
const Transform3d &actual_trmat = volume.get_transformation().get_matrix();
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);
if (vertical_align_str.empty())
return FontProp::VerticalAlign::center;
Transform3d fix_trmat = actual_trmat.inverse() * post_trmat;
if (!tc.fix_3mf_tr.has_value()) {
tc.fix_3mf_tr = fix_trmat;
} else if (!fix_trmat.isApprox(Transform3d::Identity(), 1e-5)) {
tc.fix_3mf_tr = *tc.fix_3mf_tr * fix_trmat;
// Back compatibility
// PS 2.6.1 store indices(0|1|2) instead of text for align
if (vertical_align_str.length() == 1) {
int vertical_align_int = 0;
if(boost::spirit::qi::parse(vertical_align_str.c_str(), vertical_align_str.c_str() + 1, boost::spirit::qi::int_, vertical_align_int))
return static_cast<FontProp::VerticalAlign>(vertical_align_int);
}
return bimap_cvt(vertical_align_to_name, std::string_view(vertical_align_str), FontProp::VerticalAlign::center);
}
to_xml(stream, tc);
}
std::optional<TextConfiguration> TextConfigurationSerialization::read(const char **attributes, unsigned int num_attributes)
@@ -3601,19 +3745,16 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
float skew = get_attribute_value_float(attributes, num_attributes, SKEW_ATTR);
if (std::fabs(skew) > std::numeric_limits<float>::epsilon())
fp.skew = skew;
float distance = get_attribute_value_float(attributes, num_attributes, DISTANCE_ATTR);
if (std::fabs(distance) > std::numeric_limits<float>::epsilon())
fp.distance = distance;
int use_surface = get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
if (use_surface == 1) fp.use_surface = true;
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits<float>::epsilon())
fp.angle = angle;
int per_glyph = get_attribute_value_int(attributes, num_attributes, PER_GLYPH_ATTR);
if (per_glyph == 1) fp.per_glyph = true;
fp.align = FontProp::Align(
read_horizontal_align(attributes, num_attributes, horizontal_align_to_name),
read_vertical_align(attributes, num_attributes, vertical_align_to_name));
int collection_number = get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
if (collection_number > 0) fp.collection_number = static_cast<unsigned int>(collection_number);
fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
std::string family = get_attribute_value_string(attributes, num_attributes, FONT_FAMILY_ATTR);
if (!family.empty()) fp.family = family;
@@ -3627,10 +3768,133 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
std::string style_name = get_attribute_value_string(attributes, num_attributes, STYLE_NAME_ATTR);
std::string font_descriptor = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_ATTR);
std::string type_str = get_attribute_value_string(attributes, num_attributes, FONT_DESCRIPTOR_TYPE_ATTR);
EmbossStyle::Type type = TextConfigurationSerialization::get_type(type_str);
EmbossStyle fi{ style_name, std::move(font_descriptor), type, std::move(fp) };
EmbossStyle::Type type = bimap_cvt(type_to_name, std::string_view{type_str}, EmbossStyle::Type::undefined);
std::string text = get_attribute_value_string(attributes, num_attributes, TEXT_DATA_ATTR);
EmbossStyle es{style_name, std::move(font_descriptor), type, std::move(fp)};
return TextConfiguration{std::move(es), std::move(text)};
}
EmbossShape TextConfigurationSerialization::read_old(const char **attributes, unsigned int num_attributes)
{
EmbossShape es;
std::string fix_tr_mat_str = get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
if (!fix_tr_mat_str.empty())
es.fix_3mf_tr = get_transform_from_3mf_specs_string(fix_tr_mat_str);
if (get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR) == 1)
es.projection.use_surface = true;
es.projection.depth = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
int use_surface = get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
if (use_surface == 1)
es.projection.use_surface = true;
return es;
}
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
const Transform3d &actual_trmat = volume.get_matrix();
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 << "=\"";
_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 = get_attribute_value_float(attributes, num_attributes, SHAPE_SCALE_ATTR);
int unhealed = get_attribute_value_int(attributes, num_attributes, UNHEALED_ATTR);
bool is_healed = unhealed != 1;
EmbossProjection projection;
projection.depth = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);
if (is_approx(projection.depth, 0.))
projection.depth = 10.;
int use_surface = 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 = get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR);
@@ -3638,7 +3902,19 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
fix_tr_mat = get_transform_from_3mf_specs_string(fix_tr_mat_str);
}
return TextConfiguration{std::move(fi), std::move(text), std::move(fix_tr_mat)};
std::string file_path = get_attribute_value_string(attributes, num_attributes, SVG_FILE_PATH_ATTR);
std::string file_path_3mf = 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)};
}

View File

@@ -104,21 +104,21 @@ typedef struct anycubicsla_format_header
{
char tag[12];
std::uint32_t payload_size;
std::float_t pixel_size_um;
std::float_t layer_height_mm;
std::float_t exposure_time_s;
std::float_t delay_before_exposure_s;
std::float_t bottom_exposure_time_s;
std::float_t bottom_layer_count;
std::float_t lift_distance_mm;
std::float_t lift_speed_mms;
std::float_t retract_speed_mms;
std::float_t volume_ml;
float pixel_size_um;
float layer_height_mm;
float exposure_time_s;
float delay_before_exposure_s;
float bottom_exposure_time_s;
float bottom_layer_count;
float lift_distance_mm;
float lift_speed_mms;
float retract_speed_mms;
float volume_ml;
std::uint32_t antialiasing;
std::uint32_t res_x;
std::uint32_t res_y;
std::float_t weight_g;
std::float_t price;
float weight_g;
float price;
std::uint32_t price_currency;
std::uint32_t per_layer_override; // ? unknown meaning ?
std::uint32_t print_time_s;
@@ -149,19 +149,19 @@ typedef struct anycubicsla_format_layer
{
std::uint32_t image_offset;
std::uint32_t image_size;
std::float_t lift_distance_mm;
std::float_t lift_speed_mms;
std::float_t exposure_time_s;
std::float_t layer_height_mm;
std::float_t layer44; // unkown - usually 0
std::float_t layer48; // unkown - usually 0
float lift_distance_mm;
float lift_speed_mms;
float exposure_time_s;
float layer_height_mm;
float layer44; // unkown - usually 0
float layer48; // unkown - usually 0
} anycubicsla_format_layer;
typedef struct anycubicsla_format_misc
{
std::float_t bottom_layer_height_mm;
std::float_t bottom_lift_distance_mm;
std::float_t bottom_lift_speed_mms;
float bottom_layer_height_mm;
float bottom_lift_distance_mm;
float bottom_lift_speed_mms;
} anycubicsla_format_misc;
@@ -192,9 +192,9 @@ private:
namespace {
std::float_t get_cfg_value_f(const DynamicConfig &cfg,
float get_cfg_value_f(const DynamicConfig &cfg,
const std::string &key,
const std::float_t &def = 0.f)
const float &def = 0.f)
{
if (cfg.has(key)) {
if (auto opt = cfg.option(key))
@@ -276,10 +276,10 @@ void fill_header(anycubicsla_format_header &h,
{
CNumericLocalesSetter locales_setter;
std::float_t bottle_weight_g;
std::float_t bottle_volume_ml;
std::float_t bottle_cost;
std::float_t material_density;
float bottle_weight_g;
float bottle_volume_ml;
float bottle_cost;
float material_density;
auto &cfg = print.full_print_config();
auto mat_opt = cfg.option("material_notes");
std::string mnotes = mat_opt? cfg.option("material_notes")->serialize() : "";
@@ -416,7 +416,7 @@ static void anycubicsla_write_int32(std::ofstream &out, std::uint32_t val)
out.write((const char *) &i3, 1);
out.write((const char *) &i4, 1);
}
static void anycubicsla_write_float(std::ofstream &out, std::float_t val)
static void anycubicsla_write_float(std::ofstream &out, float val)
{
std::uint32_t *f = (std::uint32_t *) &val;
anycubicsla_write_int32(out, *f);

View File

@@ -0,0 +1,97 @@
#include "../libslic3r.h"
#include "../Model.hpp"
#include "../TriangleMesh.hpp"
#include "../NSVGUtils.hpp"
#include "../Emboss.hpp"
#include <boost/log/trivial.hpp>
namespace {
std::string get_file_name(const std::string &file_path)
{
if (file_path.empty())
return file_path;
size_t pos_last_delimiter = file_path.find_last_of("/\\");
if (pos_last_delimiter == std::string::npos) {
// should not happend that in path is not delimiter
assert(false);
pos_last_delimiter = 0;
}
size_t pos_point = file_path.find_last_of('.');
if (pos_point == std::string::npos || pos_point < pos_last_delimiter // last point is inside of directory path
) {
// there is no extension
assert(false);
pos_point = file_path.size();
}
size_t offset = pos_last_delimiter + 1; // result should not contain last delimiter ( +1 )
size_t count = pos_point - pos_last_delimiter - 1; // result should not contain extension point ( -1 )
return file_path.substr(offset, count);
}
}
namespace Slic3r {
bool load_svg(const std::string &input_file, Model &output_model)
{
EmbossShape::SvgFile svg_file{input_file};
const NSVGimage* image = init_image(svg_file);
if (image == nullptr) {
BOOST_LOG_TRIVIAL(error) << "SVG file(\"" << input_file << "\") couldn't be parsed by nano svg.";
return false;
}
double tesselation_tolerance = 1e10;
NSVGLineParams params(tesselation_tolerance);
ExPolygonsWithIds shapes = create_shape_with_ids(*image, params);
if (shapes.empty()) {
BOOST_LOG_TRIVIAL(error) << "SVG file(\"" << input_file << "\") do not contain embossedabled shape.";
return false; // No shapes in svg
}
double depth_in_mm = 10.; // in mm
bool use_surface = false;
EmbossProjection emboss_projection{depth_in_mm, use_surface};
EmbossShape emboss_shape;
emboss_shape.shapes_with_ids = std::move(shapes);
emboss_shape.projection = std::move(emboss_projection);
emboss_shape.svg_file = std::move(svg_file);
// unify to one expolygons
// EmbossJob.cpp --> ExPolygons create_shape(DataBase &input, Fnc was_canceled) {
ExPolygons union_shape = union_with_delta(emboss_shape, Emboss::UNION_DELTA, Emboss::UNION_MAX_ITERATIN);
// create projection
double scale = emboss_shape.scale;
double depth = emboss_shape.projection.depth / scale;
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
Transform3d tr{Eigen::Scaling(scale)};
Emboss::ProjectTransform project(std::move(projectZ), tr);
// convert 2d shape to 3d triangles
indexed_triangle_set its = Emboss::polygons2model(union_shape, project);
TriangleMesh triangl_mesh(std::move(its));
// add mesh to model
ModelObject *object = output_model.add_object();
assert(object != nullptr);
if (object == nullptr)
return false;
object->name = get_file_name(input_file);
ModelVolume* volume = object->add_volume(std::move(triangl_mesh));
assert(volume != nullptr);
if (volume == nullptr) {
output_model.delete_object(object);
return false;
}
volume->name = object->name; // copy
volume->emboss_shape = std::move(emboss_shape);
object->invalidate_bounding_box();
return true;
}
}; // namespace Slic3r

View File

@@ -0,0 +1,14 @@
#ifndef slic3r_Format_SVG_hpp_
#define slic3r_Format_SVG_hpp_
#include <string>
namespace Slic3r {
class Model;
// Load an SVG file as embossed shape into a provided model.
bool load_svg(const std::string &input_file, Model &output_model);
}; // namespace Slic3r
#endif /* slic3r_Format_SVG_hpp_ */

View File

@@ -7,9 +7,20 @@
#include "objparser.hpp"
#include "libslic3r/LocalesUtils.hpp"
#include "fast_float/fast_float.h"
namespace ObjParser {
static double strtod_clocale(const char* str, char const** str_end)
{
double val = 0.;
auto [pend, ec] = fast_float::from_chars(str, *str_end, val);
if (pend != str && ec != std::errc::result_out_of_range)
*str_end = pend; // success
else
*str_end = str;
return val;
}
static bool obj_parseline(const char *line, ObjData &data)
{
#define EATWS() while (*line == ' ' || *line == '\t') ++ line
@@ -41,15 +52,15 @@ static bool obj_parseline(const char *line, ObjData &data)
if (c2 != ' ' && c2 != '\t')
return false;
EATWS();
char *endptr = 0;
double u = strtod(line, &endptr);
const char *endptr = 0;
double u = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
return false;
line = endptr;
EATWS();
double v = 0;
if (*line != 0) {
v = strtod(line, &endptr);
v = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
@@ -57,7 +68,7 @@ static bool obj_parseline(const char *line, ObjData &data)
}
double w = 0;
if (*line != 0) {
w = strtod(line, &endptr);
w = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
@@ -78,18 +89,18 @@ static bool obj_parseline(const char *line, ObjData &data)
if (c2 != ' ' && c2 != '\t')
return false;
EATWS();
char *endptr = 0;
double x = strtod(line, &endptr);
const char *endptr = 0;
double x = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
double y = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
double z = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
@@ -108,20 +119,20 @@ static bool obj_parseline(const char *line, ObjData &data)
if (c2 != ' ' && c2 != '\t')
return false;
EATWS();
char *endptr = 0;
double u = strtod(line, &endptr);
const char *endptr = 0;
double u = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
double v = strtod(line, &endptr);
double v = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
double w = 0;
if (*line != 0) {
w = strtod(line, &endptr);
w = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
@@ -140,25 +151,25 @@ static bool obj_parseline(const char *line, ObjData &data)
if (c2 != ' ' && c2 != '\t')
return false;
EATWS();
char *endptr = 0;
double x = strtod(line, &endptr);
const char *endptr = 0;
double x = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
return false;
line = endptr;
EATWS();
double y = strtod(line, &endptr);
double y = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t'))
return false;
line = endptr;
EATWS();
double z = strtod(line, &endptr);
double z = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;
EATWS();
double w = 1.0;
if (*line != 0) {
w = strtod(line, &endptr);
w = strtod_clocale(line, &endptr);
if (endptr == 0 || (*endptr != ' ' && *endptr != '\t' && *endptr != 0))
return false;
line = endptr;