Set svg file data as optional in emboss shape (text do not contain it)

This commit is contained in:
Filip Sykala - NTB T15p 2023-11-01 18:23:28 +01:00
parent 424fc6aa43
commit 894e88a503
6 changed files with 105 additions and 57 deletions

View File

@ -110,16 +110,19 @@ struct EmbossShape
// Note: image is only cache it is not neccessary to store
// Store file data as plain string
ar(path, path_in_3mf, *file_data);
assert(file_data != nullptr);
ar(path, path_in_3mf, (file_data != nullptr) ? *file_data : std::string(""));
}
template<class Archive> void load(Archive &ar) {
// for restore shared pointer on file data
std::string file_data_str;
ar(path, path_in_3mf, file_data_str);
if (!file_data_str.empty())
file_data = std::make_unique<std::string>(file_data_str);
}
};
SvgFile svg_file;
// When embossing shape is made by svg file this is source data
std::optional<SvgFile> svg_file;
// flag whether during cration of union expolygon final shape was fully correct
// correct mean without selfintersection and duplicate(double) points
@ -128,6 +131,7 @@ struct EmbossShape
// undo / redo stack recovery
template<class Archive> void save(Archive &ar) const
{
// final_shape is not neccessary to store - it is only cache
ar(shapes_with_ids, scale, projection, is_healed, svg_file);
cereal::save(ar, fix_3mf_tr);
}

View File

@ -1404,8 +1404,11 @@ namespace Slic3r {
std::optional<EmbossShape> &es = volume->emboss_shape;
if (!es.has_value())
continue;
if (filename.compare(es->svg_file.path_in_3mf) == 0)
es->svg_file.file_data = m_path_to_emboss_shape_files[filename];
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];
}
}
@ -2040,16 +2043,19 @@ namespace Slic3r {
return false;
// Fill svg file content into shape_configuration
EmbossShape::SvgFile &svg = volume.shape_configuration->svg_file;
const std::string &path = svg.path_in_3mf;
if (path.empty()) // do not contain svg file
return true;
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;
svg->file_data = it->second;
return true;
}
@ -3860,7 +3866,8 @@ bool to_xml(std::stringstream &stream, const EmbossShape::SvgFile &svg, const Mo
void to_xml(std::stringstream &stream, const EmbossShape &es, const ModelVolume &volume, mz_zip_archive &archive)
{
stream << " <" << SHAPE_TAG << " ";
if(!to_xml(stream, es.svg_file, volume, archive))
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 << "\" ";

View File

@ -1110,11 +1110,12 @@ std::string create_stroke_warning(const NSVGshape &shape) {
/// <returns>Vector of warnings with same size as EmbossShape::shapes_with_ids
/// or Empty when no warnings -> for fast checking that every thing is all right(more common case) </returns>
std::vector<std::string> create_shape_warnings(const EmbossShape &shape, float scale){
assert(shape.svg_file.image != nullptr);
if (shape.svg_file.image == nullptr)
const std::shared_ptr<NSVGimage>& image_ptr = shape.svg_file->image;
assert(image_ptr != nullptr);
if (image_ptr == nullptr)
return {std::string{"Uninitialized SVG image"}};
const NSVGimage &image = *shape.svg_file.image;
const NSVGimage &image = *image_ptr;
std::vector<std::string> result;
auto add_warning = [&result, &image](size_t index, const std::string &message) {
if (result.empty())
@ -1199,7 +1200,7 @@ void GLGizmoSVG::set_volume_by_selection()
calculate_scale(); // must be before calculation of tesselation
EmbossShape &es = *volume->emboss_shape;
EmbossShape::SvgFile &svg_file = es.svg_file;
EmbossShape::SvgFile &svg_file = *es.svg_file;
if (svg_file.image == nullptr) {
if (init_image(svg_file) == nullptr)
return reset_volume();
@ -1340,7 +1341,17 @@ void GLGizmoSVG::draw_window()
return;
}
assert(m_volume->emboss_shape->svg_file.file_data != nullptr);
assert(m_volume->emboss_shape->svg_file.has_value());
if (!m_volume->emboss_shape->svg_file.has_value()){
ImGui::Text("Missing svg file in embossed shape");
return;
}
assert(m_volume->emboss_shape->svg_file->file_data != nullptr);
if (m_volume->emboss_shape->svg_file->file_data == nullptr){
ImGui::Text("Missing data of svg file");
return;
}
draw_preview();
draw_filename();
@ -1358,13 +1369,7 @@ void GLGizmoSVG::draw_window()
draw_distance();
draw_rotation();
draw_mirroring();
if (ImGui::Button(_u8L("Face the camera").c_str())) {
const Camera &cam = wxGetApp().plater()->get_camera();
auto wanted_up_limit = (m_keep_up) ? std::optional<double>(UP_LIMIT) : std::optional<double>{};
if (face_selected_volume_to_camera(cam, m_parent, wanted_up_limit))
volume_transformation_changed();
}
draw_face_the_camera();
ImGui::Unindent(m_gui_cfg->icon_width);
@ -1374,6 +1379,20 @@ void GLGizmoSVG::draw_window()
}
}
void GLGizmoSVG::draw_face_the_camera(){
// multi instance has to have same rotation only world z rotation is allowed
bool disabled = m_parent.get_selection().is_single_full_instance();
m_imgui->disabled_begin(disabled);
if (ImGui::Button(_u8L("Face the camera").c_str())) {
const Camera &cam = wxGetApp().plater()->get_camera();
auto wanted_up_limit = (m_keep_up) ? std::optional<double>(UP_LIMIT) : std::optional<double>{};
if (face_selected_volume_to_camera(cam, m_parent, wanted_up_limit))
volume_transformation_changed();
}
m_imgui->disabled_end();
}
void GLGizmoSVG::draw_preview(){
// init texture when not initialized yet.
// drag&drop is out of rendering scope so texture must be created on this place
@ -1427,12 +1446,13 @@ void GLGizmoSVG::draw_preview(){
void GLGizmoSVG::draw_filename(){
const EmbossShape &es = *m_volume->emboss_shape;
const EmbossShape::SvgFile &svg = *es.svg_file;
if (m_filename_preview.empty()){
// create filename preview
if (!es.svg_file.path.empty()) {
m_filename_preview = get_file_name(es.svg_file.path);
} else if (!es.svg_file.path_in_3mf.empty()) {
m_filename_preview = get_file_name(es.svg_file.path_in_3mf);
if (!svg.path.empty()) {
m_filename_preview = get_file_name(svg.path);
} else if (!svg.path_in_3mf.empty()) {
m_filename_preview = get_file_name(svg.path_in_3mf);
}
if (m_filename_preview.empty()){
@ -1469,19 +1489,19 @@ void GLGizmoSVG::draw_filename(){
is_hovered |= ImGui::IsItemHovered();
if (is_hovered) {
std::string tooltip = GUI::format(_L("SVG file path is \"%1%\""), es.svg_file.path);
std::string tooltip = GUI::format(_L("SVG file path is \"%1%\""), svg.path);
ImGui::SetTooltip("%s", tooltip.c_str());
}
bool file_changed = false;
// Re-Load button
bool can_reload = !m_volume_shape.svg_file.path.empty();
bool can_reload = !m_volume_shape.svg_file->path.empty();
if (can_reload) {
ImGui::SameLine();
if (clickable(get_icon(m_icons, IconType::refresh), get_icon(m_icons, IconType::refresh_hover))) {
if (!boost::filesystem::exists(m_volume_shape.svg_file.path)) {
m_volume_shape.svg_file.path.clear();
if (!boost::filesystem::exists(m_volume_shape.svg_file->path)) {
m_volume_shape.svg_file->path.clear();
} else {
file_changed = true;
}
@ -1501,14 +1521,14 @@ void GLGizmoSVG::draw_filename(){
if (!new_path.empty()) {
file_changed = true;
m_volume_shape.svg_file = {}; // clear data
m_volume_shape.svg_file.path = new_path;
m_volume_shape.svg_file->path = new_path;
}
} else if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", _u8L("Change to another .svg file").c_str());
}
std::string forget_path = _u8L("Forget the file path");
if (m_volume->emboss_shape->svg_file.path.empty()){
if (m_volume->emboss_shape->svg_file->path.empty()){
draw(get_icon(m_icons, IconType::bake_inactive));
ImGui::SameLine();
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, forget_path.c_str());
@ -1517,8 +1537,8 @@ void GLGizmoSVG::draw_filename(){
ImGui::SameLine();
if (ImGui::Selectable(forget_path.c_str())) {
// set .svg_file.path_in_3mf to remember file name
m_volume->emboss_shape->svg_file.path.clear();
m_volume_shape.svg_file.path.clear();
m_volume->emboss_shape->svg_file->path.clear();
m_volume_shape.svg_file->path.clear();
// TRN - Preview of filename after clear local filepath.
m_filename_preview = _u8L("No-name SVG");
} else if (ImGui::IsItemHovered()) {
@ -1563,7 +1583,7 @@ void GLGizmoSVG::draw_filename(){
GUI::FileType file_type = FT_SVG;
wxString wildcard = file_wildcards(file_type);
wxString dlg_title = _L("Save SVG file");
const EmbossShape::SvgFile& svg = m_volume_shape.svg_file;
const EmbossShape::SvgFile& svg = *m_volume_shape.svg_file;
wxString dlg_file = from_u8(get_file_name(((!svg.path.empty()) ? svg.path : svg.path_in_3mf))) + ".svg";
wxFileDialog dlg(parent, dlg_title, last_used_directory, dlg_file, wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dlg.ShowModal() == wxID_OK ){
@ -1578,8 +1598,8 @@ void GLGizmoSVG::draw_filename(){
// change source file
m_filename_preview.clear();
m_volume_shape.svg_file.path = path;
m_volume_shape.svg_file.path_in_3mf.clear(); // possible change name
m_volume_shape.svg_file->path = path;
m_volume_shape.svg_file->path_in_3mf.clear(); // possible change name
m_volume->emboss_shape->svg_file = m_volume_shape.svg_file; // copy - write changes into volume
} else {
BOOST_LOG_TRIVIAL(error) << "Opening file: \"" << path << "\" Failed";
@ -1613,7 +1633,7 @@ void GLGizmoSVG::draw_filename(){
if (file_changed) {
float scale = get_scale_for_tolerance();
double tes_tol = get_tesselation_tolerance(scale);
EmbossShape es_ = select_shape(m_volume_shape.svg_file.path, tes_tol);
EmbossShape es_ = select_shape(m_volume_shape.svg_file->path, tes_tol);
m_volume_shape.svg_file = std::move(es_.svg_file);
m_volume_shape.shapes_with_ids = std::move(es_.shapes_with_ids);
m_shape_warnings = create_shape_warnings(m_volume_shape, scale);
@ -1780,11 +1800,12 @@ void GLGizmoSVG::draw_size()
// should be the almost same
calculate_scale();
NSVGimage *img = m_volume_shape.svg_file.image.get();
NSVGimage *img = m_volume_shape.svg_file->image.get();
assert(img != NULL);
if (img != NULL){
NSVGLineParams params{get_tesselation_tolerance(get_scale_for_tolerance())};
m_volume_shape.shapes_with_ids = create_shape_with_ids(*img, params);
m_volume_shape.final_shape.clear();
process();
}
}
@ -2054,7 +2075,7 @@ std::string get_file_name(const std::string &file_path)
std::string volume_name(const EmbossShape &shape)
{
std::string file_name = get_file_name(shape.svg_file.path);
std::string file_name = get_file_name(shape.svg_file->path);
if (!file_name.empty())
return file_name;
return "SVG shape";
@ -2176,41 +2197,43 @@ EmbossShape select_shape(std::string_view filepath, double tesselation_tolerance
shape.projection.depth = 10.;
shape.projection.use_surface = false;
EmbossShape::SvgFile svg;
if (filepath.empty()) {
// When empty open file dialog
shape.svg_file.path = choose_svg_file();
if (shape.svg_file.path.empty())
svg.path = choose_svg_file();
if (svg.path.empty())
return {}; // file was not selected
} else {
shape.svg_file.path = filepath; // copy
svg.path = filepath; // copy
}
boost::filesystem::path path(shape.svg_file.path);
boost::filesystem::path path(svg.path);
if (!boost::filesystem::exists(path)) {
show_error(nullptr, GUI::format(_u8L("File does NOT exist (%1%)."), shape.svg_file.path));
show_error(nullptr, GUI::format(_u8L("File does NOT exist (%1%)."), svg.path));
return {};
}
if (!boost::algorithm::iends_with(shape.svg_file.path, ".svg")) {
show_error(nullptr, GUI::format(_u8L("Filename has to end with \".svg\" but you selected %1%"), shape.svg_file.path));
if (!boost::algorithm::iends_with(svg.path, ".svg")) {
show_error(nullptr, GUI::format(_u8L("Filename has to end with \".svg\" but you selected %1%"), svg.path));
return {};
}
if(init_image(shape.svg_file) == nullptr) {
show_error(nullptr, GUI::format(_u8L("Nano SVG parser can't load from file (%1%)."), shape.svg_file.path));
if(init_image(svg) == nullptr) {
show_error(nullptr, GUI::format(_u8L("Nano SVG parser can't load from file (%1%)."), svg.path));
return {};
}
// Set default and unchanging scale
NSVGLineParams params{tesselation_tolerance};
shape.shapes_with_ids = create_shape_with_ids(*shape.svg_file.image, params);
shape.shapes_with_ids = create_shape_with_ids(*svg.image, params);
// Must contain some shapes !!!
if (shape.shapes_with_ids.empty()) {
show_error(nullptr, GUI::format(_u8L("SVG file does NOT contain a single path to be embossed (%1%)."), shape.svg_file.path));
show_error(nullptr, GUI::format(_u8L("SVG file does NOT contain a single path to be embossed (%1%)."), svg.path));
return {};
}
shape.svg_file = std::move(svg);
return shape;
}

View File

@ -123,6 +123,7 @@ private:
void draw_distance();
void draw_rotation();
void draw_mirroring();
void draw_face_the_camera();
void draw_model_type();
// process mouse event

View File

@ -7003,7 +7003,11 @@ void publish(Model &model) {
if (volume->text_configuration.has_value())
continue; // text dosen't have svg path
SvgFile* svg = &volume->emboss_shape->svg_file;
assert(volume->emboss_shape->svg_file.has_value());
if (!volume->emboss_shape->svg_file.has_value())
continue;
SvgFile* svg = &(*volume->emboss_shape->svg_file);
if (svg->path_in_3mf.empty())
exist_new = true;
svgfiles.push_back(svg);

View File

@ -567,10 +567,17 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]")
emboss.projection.depth = 5.;
emboss.projection.use_surface = true;
emboss.fix_3mf_tr = Transform3d::Identity();
emboss.svg_file.path = "Everything starts somewhere, though many physicists disagree.\
emboss.svg_file = EmbossShape::SvgFile{};
emboss.svg_file->path = "Everything starts somewhere, though many physicists disagree.\
But people have always been dimly aware of the problem with the start of things.\
They wonder how the snowplough driver gets to work,\
or how the makers of dictionaries look up the spelling of words.";
emboss.svg_file->path_in_3mf = "Všechno někde začíná, i když mnoho fyziků nesouhlasí.\
Ale lidé si vždy jen matně uvědomovali problém se začátkem věcí.\
Zajímalo je, jak se řidič sněžného pluhu dostane do práce\
nebo jak tvůrci slovníků vyhledávají pravopis slov.";
emboss.svg_file->file_data = std::make_unique<std::string>("cite: Terry Pratchett");
std::stringstream ss; // any stream can be used
{
cereal::BinaryOutputArchive oarchive(ss); // Create an output archive
@ -586,6 +593,8 @@ TEST_CASE("UndoRedo EmbossShape serialization", "[Emboss]")
CHECK(emboss.scale == emboss_loaded.scale);
CHECK(emboss.projection.depth == emboss_loaded.projection.depth);
CHECK(emboss.projection.use_surface == emboss_loaded.projection.use_surface);
CHECK(emboss.svg_file->path == emboss_loaded.svg_file->path);
CHECK(emboss.svg_file->path_in_3mf == emboss_loaded.svg_file->path_in_3mf);
}