From 314df2d8054d62f9a2b992a49ce1e449f771da41 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 11:25:50 +0200 Subject: [PATCH 01/11] debugging function debug_output_path() moved to utils.cpp/hpp and it now prints to console the default path when called for the first time. Fixed compilation of debugging output in SupportMaterial. --- src/libslic3r/SupportMaterial.cpp | 105 +++++++++++++++--------------- src/libslic3r/Utils.hpp | 5 ++ src/libslic3r/libslic3r.h | 12 ---- src/libslic3r/utils.cpp | 17 +++++ 4 files changed, 75 insertions(+), 64 deletions(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index e2d7bf19951..c9794a6c88b 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -37,6 +37,7 @@ #define DEBUG #define _DEBUG #undef NDEBUG + #include "utils.hpp" #include "SVG.hpp" #endif @@ -429,7 +430,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) for (const MyLayer *layer : top_contacts) Slic3r::SVG::export_expolygons( debug_out_path("support-top-contacts-%d-%lf.svg", iRun, layer->print_z), - union_ex(layer->polygons, false)); + union_ex(layer->polygons)); #endif /* SLIC3R_DEBUG */ BOOST_LOG_TRIVIAL(info) << "Support generator - Creating bottom contacts"; @@ -447,7 +448,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) for (size_t layer_id = 0; layer_id < object.layers().size(); ++ layer_id) Slic3r::SVG::export_expolygons( debug_out_path("support-areas-%d-%lf.svg", iRun, object.layers()[layer_id]->print_z), - union_ex(layer_support_areas[layer_id], false)); + union_ex(layer_support_areas[layer_id])); #endif /* SLIC3R_DEBUG */ BOOST_LOG_TRIVIAL(info) << "Support generator - Creating intermediate layers - indices"; @@ -466,7 +467,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) for (const MyLayer *layer : top_contacts) Slic3r::SVG::export_expolygons( debug_out_path("support-top-contacts-trimmed-by-object-%d-%lf.svg", iRun, layer->print_z), - union_ex(layer->polygons, false)); + union_ex(layer->polygons)); #endif BOOST_LOG_TRIVIAL(info) << "Support generator - Creating base layers"; @@ -478,7 +479,7 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) for (MyLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++ it) Slic3r::SVG::export_expolygons( debug_out_path("support-base-layers-%d-%lf.svg", iRun, (*it)->print_z), - union_ex((*it)->polygons, false)); + union_ex((*it)->polygons)); #endif /* SLIC3R_DEBUG */ BOOST_LOG_TRIVIAL(info) << "Support generator - Trimming top contacts by bottom contacts"; @@ -507,11 +508,11 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) for (const MyLayer *l : interface_layers) Slic3r::SVG::export_expolygons( debug_out_path("support-interface-layers-%d-%lf.svg", iRun, l->print_z), - union_ex(l->polygons, false)); + union_ex(l->polygons)); for (const MyLayer *l : base_interface_layers) Slic3r::SVG::export_expolygons( debug_out_path("support-base-interface-layers-%d-%lf.svg", iRun, l->print_z), - union_ex(l->polygons, false)); + union_ex(l->polygons)); #endif // SLIC3R_DEBUG /* @@ -1308,9 +1309,9 @@ namespace SupportMaterialInternal { #ifdef SLIC3R_DEBUG static int iRun = 0; SVG::export_expolygons(debug_out_path("support-top-contacts-remove-bridges-run%d.svg", iRun ++), - { { { union_ex(offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS), false) }, { "unsupported_bridge_edges", "orange", 0.5f } }, - { { union_ex(contact_polygons, false) }, { "contact_polygons", "blue", 0.5f } }, - { { union_ex(bridges, false) }, { "bridges", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(offset(layerm->unsupported_bridge_edges, scale_(SUPPORT_MATERIAL_MARGIN), SUPPORT_SURFACES_OFFSET_PARAMETERS)) }, { "unsupported_bridge_edges", "orange", 0.5f } }, + { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, + { { union_ex(bridges) }, { "bridges", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ } } @@ -1494,7 +1495,7 @@ static inline std::tuple detect_overhangs( iRun, layer_id, std::find_if(layer.regions().begin(), layer.regions().end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions().begin()), get_extents(diff_polygons)); - Slic3r::ExPolygons expolys = union_ex(diff_polygons, false); + Slic3r::ExPolygons expolys = union_ex(diff_polygons); svg.draw(expolys); } #endif /* SLIC3R_DEBUG */ @@ -1512,7 +1513,7 @@ static inline std::tuple detect_overhangs( iRun, layer_id, std::find_if(layer.regions().begin(), layer.regions().end(), [layerm](const LayerRegion* other){return other == layerm;}) - layer.regions().begin(), layer.print_z), - union_ex(diff_polygons, false)); + union_ex(diff_polygons)); #endif /* SLIC3R_DEBUG */ //FIXME the overhang_polygons are used to construct the support towers as well. @@ -1572,10 +1573,10 @@ static inline std::tuple detect_overhangs( offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-top-contacts-enforcers-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), - { { layer.lslices, { "layer.lslices", "gray", 0.2f } }, - { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "green", 0.5f } }, - { enforcers_united, { "enforcers", "blue", 0.5f } }, - { { union_ex(enforcer_polygons, true) }, { "new_contacts", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { layer.lslices, { "layer.lslices", "gray", 0.2f } }, + { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "green", 0.5f } }, + { enforcers_united, { "enforcers", "blue", 0.5f } }, + { { union_safety_offset_ex(enforcer_polygons) }, { "new_contacts", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ polygons_append(overhang_polygons, enforcer_polygons); polygons_append(contact_polygons, diff(enforcer_polygons, slices_margin.all_polygons.empty() ? slices_margin.polygons : slices_margin.all_polygons)); @@ -1739,18 +1740,18 @@ static inline void fill_contact_layer( ); #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), - { { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "gray", 0.2f } }, - { { union_ex(*new_layer.contact_polygons, false) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, - { { union_ex(slices_margin.polygons, false) }, { "slices_margin_cached", "blue", 0.5f } }, - { { union_ex(dense_interface_polygons, false) }, { "dense_interface_polygons", "green", 0.5f } }, - { { union_ex(new_layer.polygons, true) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "gray", 0.2f } }, + { { union_ex(*new_layer.contact_polygons) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, + { { union_ex(slices_margin.polygons) }, { "slices_margin_cached", "blue", 0.5f } }, + { { union_ex(dense_interface_polygons) }, { "dense_interface_polygons", "green", 0.5f } }, + { { union_safety_offset_ex(new_layer.polygons) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); //support_grid_pattern.serialize(debug_out_path("support-top-contacts-final-run%d-layer%d-z%f.bin", iRun, layer_id, layer.print_z)); SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), - { { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "gray", 0.2f } }, - { { union_ex(*new_layer.contact_polygons, false) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, - { { union_ex(contact_polygons, false) }, { "contact_polygons", "blue", 0.5f } }, - { { union_ex(dense_interface_polygons, false) }, { "dense_interface_polygons", "green", 0.5f } }, - { { union_ex(new_layer.polygons, true) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "gray", 0.2f } }, + { { union_ex(*new_layer.contact_polygons) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, + { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, + { { union_ex(dense_interface_polygons) }, { "dense_interface_polygons", "green", 0.5f } }, + { { union_safety_offset_ex(new_layer.polygons) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ } } @@ -1796,11 +1797,11 @@ static inline void fill_contact_layer( #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), - { { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "gray", 0.2f } }, - { { union_ex(*new_layer.contact_polygons, false) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, - { { union_ex(contact_polygons, false) }, { "contact_polygons", "blue", 0.5f } }, - { { union_ex(overhang_polygons, false) }, { "overhang_polygons", "green", 0.5f } }, - { { union_ex(new_layer.polygons, true) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "gray", 0.2f } }, + { { union_ex(*new_layer.contact_polygons) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, + { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, + { { union_ex(overhang_polygons) }, { "overhang_polygons", "green", 0.5f } }, + { { union_safety_offset_ex(new_layer.polygons) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ // Even after the contact layer was expanded into a grid, some of the contact islands may be too tiny to be extruded. @@ -1964,10 +1965,10 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts( Polygons top = collect_region_slices_by_type(layer, stTop); #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-bottom-layers-raw-%d-%lf.svg", iRun, layer.print_z), - { { { union_ex(top, false) }, { "top", "blue", 0.5f } }, - { { union_ex(supports_projected, true) }, { "overhangs", "magenta", 0.5f } }, - { layer.lslices, { "layer.lslices", "green", 0.5f } }, - { { union_ex(polygons_new, true) }, { "polygons_new", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(top) }, { "top", "blue", 0.5f } }, + { { union_safety_offset_ex(supports_projected) }, { "overhangs", "magenta", 0.5f } }, + { layer.lslices, { "layer.lslices", "green", 0.5f } }, + { { union_safety_offset_ex(polygons_new) }, { "polygons_new", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ // Now find whether any projection of the contact surfaces above layer.print_z not yet supported by any @@ -2037,7 +2038,7 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts( #ifdef SLIC3R_DEBUG Slic3r::SVG::export_expolygons( debug_out_path("support-bottom-contacts-%d-%lf.svg", iRun, layer_new.print_z), - union_ex(layer_new.polygons, false)); + union_ex(layer_new.polygons)); #endif /* SLIC3R_DEBUG */ // Trim the already created base layers above the current layer intersecting with the new bottom contacts layer. @@ -2050,14 +2051,14 @@ static inline PrintObjectSupportMaterial::MyLayer* detect_bottom_contacts( if (! layer_support_areas[layer_id_above].empty()) { #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-support-areas-raw-before-trimming-%d-with-%f-%lf.svg", iRun, layer.print_z, layer_above.print_z), - { { { union_ex(touching, false) }, { "touching", "blue", 0.5f } }, - { { union_ex(layer_support_areas[layer_id_above], true) }, { "above", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(touching) }, { "touching", "blue", 0.5f } }, + { { union_safety_offset_ex(layer_support_areas[layer_id_above]) }, { "above", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ layer_support_areas[layer_id_above] = diff(layer_support_areas[layer_id_above], touching); #ifdef SLIC3R_DEBUG Slic3r::SVG::export_expolygons( debug_out_path("support-support-areas-raw-after-trimming-%d-with-%f-%lf.svg", iRun, layer.print_z, layer_above.print_z), - union_ex(layer_support_areas[layer_id_above], false)); + union_ex(layer_support_areas[layer_id_above])); #endif /* SLIC3R_DEBUG */ } } @@ -2080,8 +2081,8 @@ static inline std::pair project_support_to_grid(const Layer #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-support-areas-%s-raw-%d-%lf.svg", debug_name, iRun, layer.print_z), - { { { union_ex(trimming, false) }, { "trimming", "blue", 0.5f } }, - { { union_ex(overhangs_projection, true) }, { "overhangs_projection", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(trimming) }, { "trimming", "blue", 0.5f } }, + { { union_safety_offset_ex(overhangs_projection) }, { "overhangs_projection", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ remove_sticks(overhangs_projection); @@ -2089,8 +2090,8 @@ static inline std::pair project_support_to_grid(const Layer #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-support-areas-%s-raw-cleaned-%d-%lf.svg", debug_name, iRun, layer.print_z), - { { { union_ex(trimming, false) }, { "trimming", "blue", 0.5f } }, - { { union_ex(overhangs_projection, false) }, { "overhangs_projection", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(trimming) }, { "trimming", "blue", 0.5f } }, + { { union_ex(overhangs_projection) }, { "overhangs_projection", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ SupportGridPattern support_grid_pattern(&overhangs_projection, &trimming, grid_params); @@ -2113,7 +2114,7 @@ static inline std::pair project_support_to_grid(const Layer #ifdef SLIC3R_DEBUG Slic3r::SVG::export_expolygons( debug_out_path("support-layer_support_area-gridded-%s-%d-%lf.svg", debug_name, iRun, layer.print_z), - union_ex(out.first, false)); + union_ex(out.first)); #endif /* SLIC3R_DEBUG */ }); @@ -2131,13 +2132,13 @@ static inline std::pair project_support_to_grid(const Layer #ifdef SLIC3R_DEBUG Slic3r::SVG::export_expolygons( debug_out_path("support-projection_new-gridded-%d-%lf.svg", iRun, layer.print_z), - union_ex(out.second, false)); + union_ex(out.second)); #endif /* SLIC3R_DEBUG */ #ifdef SLIC3R_DEBUG SVG::export_expolygons(debug_out_path("support-projection_new-gridded-%d-%lf.svg", iRun, layer.print_z), - { { { union_ex(trimming, false) }, { "trimming", "gray", 0.5f } }, - { { union_ex(overhangs_projection, true) }, { "overhangs_projection", "blue", 0.5f } }, - { { union_ex(out.second, true) }, { "projection_new", "red", "black", "", scaled(0.1f), 0.5f } } }); + { { { union_ex(trimming) }, { "trimming", "gray", 0.5f } }, + { { union_safety_offset_ex(overhangs_projection) }, { "overhangs_projection", "blue", 0.5f } }, + { { union_safety_offset_ex(out.second) }, { "projection_new", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ }); @@ -2667,10 +2668,10 @@ void PrintObjectSupportMaterial::generate_base_layers( BoundingBox bbox = get_extents(polygons_new); bbox.merge(get_extents(polygons_trimming)); ::Slic3r::SVG svg(debug_out_path("support-intermediate-layers-raw-%d-%lf.svg", iRun, layer_intermediate.print_z), bbox); - svg.draw(union_ex(polygons_new, false), "blue", 0.5f); - svg.draw(to_polylines(polygons_new), "blue"); - svg.draw(union_ex(polygons_trimming, true), "red", 0.5f); - svg.draw(to_polylines(polygons_trimming), "red"); + svg.draw(union_ex(polygons_new), "blue", 0.5f); + svg.draw(to_polylines(polygons_new), "blue"); + svg.draw(union_safety_offset_ex(polygons_trimming), "red", 0.5f); + svg.draw(to_polylines(polygons_trimming), "red"); } #endif /* SLIC3R_DEBUG */ @@ -2706,7 +2707,7 @@ void PrintObjectSupportMaterial::generate_base_layers( for (MyLayersPtr::const_iterator it = intermediate_layers.begin(); it != intermediate_layers.end(); ++it) ::Slic3r::SVG::export_expolygons( debug_out_path("support-intermediate-layers-untrimmed-%d-%lf.svg", iRun, (*it)->print_z), - union_ex((*it)->polygons, false)); + union_ex((*it)->polygons)); ++ iRun; #endif /* SLIC3R_DEBUG */ diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 1b02e033105..a01e63166b6 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -58,6 +58,11 @@ void set_data_dir(const std::string &path); // Return a full path to the GUI resource files. const std::string& data_dir(); +// Format an output path for debugging purposes. +// Writes out the output path prefix to the console for the first time the function is called, +// so the user knows where to search for the debugging output. +std::string debug_out_path(const char *name, ...); + // A special type for strings encoded in the local Windows 8-bit code page. // This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded. typedef std::string local_encoded_string; diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 8d8d15df9dc..a2943618938 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -65,18 +65,6 @@ static constexpr double EXTERNAL_INFILL_MARGIN = 3.; #define SCALED_EPSILON scale_(EPSILON) -#define SLIC3R_DEBUG_OUT_PATH_PREFIX "out/" - -inline std::string debug_out_path(const char *name, ...) -{ - char buffer[2048]; - va_list args; - va_start(args, name); - std::vsprintf(buffer, name, args); - va_end(args); - return std::string(SLIC3R_DEBUG_OUT_PATH_PREFIX) + std::string(buffer); -} - #ifndef UNUSED #define UNUSED(x) (void)(x) #endif /* UNUSED */ diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 29f955e9242..78125079adb 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -207,6 +207,23 @@ std::string custom_shapes_dir() return (boost::filesystem::path(g_data_dir) / "shapes").string(); } +static std::atomic debug_out_path_called(false); + +std::string debug_out_path(const char *name, ...) +{ + static constexpr const char *SLIC3R_DEBUG_OUT_PATH_PREFIX = "out/"; + if (! debug_out_path_called.exchange(true)) { + std::string path = boost::filesystem::system_complete(SLIC3R_DEBUG_OUT_PATH_PREFIX).string(); + printf("Debugging output files will be written to %s\n", path.c_str()); + } + char buffer[2048]; + va_list args; + va_start(args, name); + std::vsprintf(buffer, name, args); + va_end(args); + return std::string(SLIC3R_DEBUG_OUT_PATH_PREFIX) + std::string(buffer); +} + #ifdef _WIN32 // The following helpers are borrowed from the LLVM project https://github.com/llvm namespace WindowsSupport From b0a4b817a33c7b2a4aa8934a17078c43f4dbf99c Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 11:30:37 +0200 Subject: [PATCH 02/11] Slight optimization of GLGizmoSimplify::process(): Moved a static variable from inside a lambda outside as the static inner variable initialization & access has to be made thread safe. --- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index d4e14c6f4fc..b9e5d111b0d 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -283,11 +283,11 @@ void GLGizmoSimplify::process() } }; - std::function statusfn = [this](int percent) { + int64_t last = 0; + std::function statusfn = [this, &last](int percent) { m_progress = percent; // check max 4fps - static int64_t last = 0; int64_t now = m_parent.timestamp_now(); if ((now - last) < 250) return; last = now; From fa38b56022db32a00b42fbe3f200baf5ca09a8ca Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 27 Aug 2021 12:10:25 +0200 Subject: [PATCH 03/11] Slightly reworded the 'Empty layers detected' warning, it mentions the layers between which the problem occurs, not just the upper one (which may be unclear). --- src/libslic3r/GCode.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 254f1d4fd95..85e6f810b7c 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -13,6 +13,7 @@ #include "ClipperUtils.hpp" #include "libslic3r.h" #include "LocalesUtils.hpp" +#include "libslic3r/format.hpp" #include #include @@ -512,7 +513,8 @@ std::vector GCode::collect_layers_to_print(const PrintObjec bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions()) || (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions()); - // Check that there are extrusions on the very first layer. + // Check that there are extrusions on the very first layer. The case with empty + // first layer may result in skirt/brim in the air and maybe other issues. if (layers_to_print.size() == 1u) { if (!has_extrusions) throw Slic3r::SlicingError(_(L("There is an object with no extrusions in the first layer.")) + "\n" + @@ -534,11 +536,12 @@ std::vector GCode::collect_layers_to_print(const PrintObjec if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON) { const_cast(object.print())->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, - _(L("Empty layers detected. Make sure the object is printable.")) + "\n" + - _(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " + - std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is " - "usually caused by negligibly small extrusions or by a faulty model. Try to repair " - "the model or change its orientation on the bed."))); + Slic3r::format(_(L("Empty layer detected between heights %1% and %2%. Make sure the object is printable.")), + (last_extrusion_layer ? last_extrusion_layer->print_z() : 0.), + layers_to_print.back().print_z()) + + "\n" + Slic3r::format(_(L("Object name: %1%")), object.model_object()->name) + "\n\n" + + _(L("This is usually caused by negligibly small extrusions or by a faulty model. " + "Try to repair the model or change its orientation on the bed."))); } // Remember last layer with extrusions. From 97cfd358367d16739df4ac751bcdfe49f25b393b Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 27 Aug 2021 14:01:29 +0200 Subject: [PATCH 04/11] Added missing include (gcc 8.4) --- src/libslic3r/utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 78125079adb..c330f34b2b6 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -1,6 +1,7 @@ #include "Utils.hpp" #include "I18N.hpp" +#include #include #include #include From 53112e07b4dc8d6aa3041bb8593e57b8374426b2 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 15:02:43 +0200 Subject: [PATCH 05/11] Fixed Perl bindings --- xs/xsp/XS.xsp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/xs/xsp/XS.xsp b/xs/xsp/XS.xsp index 083d21d3882..68ea282bc0f 100644 --- a/xs/xsp/XS.xsp +++ b/xs/xsp/XS.xsp @@ -23,12 +23,6 @@ BUILD() RETVAL = newSVpv(SLIC3R_BUILD_ID, 0); OUTPUT: RETVAL -SV* -DEBUG_OUT_PATH_PREFIX() - CODE: - RETVAL = newSVpv(SLIC3R_DEBUG_OUT_PATH_PREFIX, 0); - OUTPUT: RETVAL - SV* FORK_NAME() CODE: From 982a2438df078e668efb8c4b98dcadf88ffdf361 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 15:04:25 +0200 Subject: [PATCH 06/11] Fixed leakage of paint-on supports through thin objects. This is a bug introduced during 2.4.0 refactoring. Fixes To much support #6067 --- src/libslic3r/SupportMaterial.cpp | 46 +++++++++++++++++++------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index c9794a6c88b..2e4a4795439 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1417,13 +1417,35 @@ static inline std::tuple detect_overhangs( // Generate overhang / contact_polygons for non-raft layers. const Layer &lower_layer = *layer.lower_layer; const bool has_enforcer = ! annotations.enforcers_layers.empty() && ! annotations.enforcers_layers[layer_id].empty(); - float fw = 0; + + // Cache support trimming polygons derived from lower layer polygons, possible merged with "on build plate only" trimming polygons. + auto slices_margin_update = + [&slices_margin, &lower_layer, &lower_layer_polygons, buildplate_only, has_enforcer, &annotations, layer_id] + (float slices_margin_offset, float no_interface_offset) { + if (slices_margin.offset != slices_margin_offset) { + slices_margin.offset = slices_margin_offset; + slices_margin.polygons = (slices_margin_offset == 0.f) ? + lower_layer_polygons : + offset2(lower_layer.lslices, -no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); + if (buildplate_only && !annotations.buildplate_covered[layer_id].empty()) { + if (has_enforcer) + // Make a backup of trimming polygons before enforcing "on build plate only". + slices_margin.all_polygons = slices_margin.polygons; + // Trim the inflated contact surfaces by the top surfaces as well. + slices_margin.polygons = union_(slices_margin.polygons, annotations.buildplate_covered[layer_id]); + } + } + }; + + float fw = 0; + float lower_layer_offset = 0; + float no_interface_offset = 0; for (LayerRegion *layerm : layer.regions()) { // Extrusion width accounts for the roundings of the extrudates. // It is the maximum widh of the extrudate. fw = float(layerm->flow(frExternalPerimeter).scaled_width()); no_interface_offset = (no_interface_offset == 0.f) ? fw : std::min(no_interface_offset, fw); - float lower_layer_offset = + lower_layer_offset = (layer_id < (size_t)object_config.support_material_enforce_layers.value) ? // Enforce a full possible support, ignore the overhang angle. 0.f : @@ -1530,20 +1552,7 @@ static inline std::tuple detect_overhangs( //FIXME one should trim with the layer span colliding with the support layer, this layer // may be lower than lower_layer, so the support area needed may need to be actually bigger! // For the same reason, the non-bridging support area may be smaller than the bridging support area! - float slices_margin_offset = std::min(lower_layer_offset, float(scale_(gap_xy))); - if (slices_margin.offset != slices_margin_offset) { - slices_margin.offset = slices_margin_offset; - slices_margin.polygons = (slices_margin_offset == 0.f) ? - lower_layer_polygons : - offset2(lower_layer.lslices, - no_interface_offset * 0.5f, slices_margin_offset + no_interface_offset * 0.5f, SUPPORT_SURFACES_OFFSET_PARAMETERS); - if (buildplate_only && ! annotations.buildplate_covered[layer_id].empty()) { - if (has_enforcer) - // Make a backup of trimming polygons before enforcing "on build plate only". - slices_margin.all_polygons = slices_margin.polygons; - // Trim the inflated contact surfaces by the top surfaces as well. - slices_margin.polygons = union_(slices_margin.polygons, annotations.buildplate_covered[layer_id]); - } - } + slices_margin_update(std::min(lower_layer_offset, float(scale_(gap_xy))), no_interface_offset); // Offset the contact polygons outside. #if 0 for (size_t i = 0; i < NUM_MARGIN_STEPS; ++ i) { @@ -1579,6 +1588,7 @@ static inline std::tuple detect_overhangs( { { union_safety_offset_ex(enforcer_polygons) }, { "new_contacts", "red", "black", "", scaled(0.1f), 0.5f } } }); #endif /* SLIC3R_DEBUG */ polygons_append(overhang_polygons, enforcer_polygons); + slices_margin_update(std::min(lower_layer_offset, float(scale_(gap_xy))), no_interface_offset); polygons_append(contact_polygons, diff(enforcer_polygons, slices_margin.all_polygons.empty() ? slices_margin.polygons : slices_margin.all_polygons)); } } @@ -1739,14 +1749,14 @@ static inline void fill_contact_layer( #endif // SLIC3R_DEBUG ); #ifdef SLIC3R_DEBUG - SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), + SVG::export_expolygons(debug_out_path("support-top-contacts-final1-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), { { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "gray", 0.2f } }, { { union_ex(*new_layer.contact_polygons) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, { { union_ex(slices_margin.polygons) }, { "slices_margin_cached", "blue", 0.5f } }, { { union_ex(dense_interface_polygons) }, { "dense_interface_polygons", "green", 0.5f } }, { { union_safety_offset_ex(new_layer.polygons) }, { "new_layer.polygons", "red", "black", "", scaled(0.1f), 0.5f } } }); //support_grid_pattern.serialize(debug_out_path("support-top-contacts-final-run%d-layer%d-z%f.bin", iRun, layer_id, layer.print_z)); - SVG::export_expolygons(debug_out_path("support-top-contacts-final0-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), + SVG::export_expolygons(debug_out_path("support-top-contacts-final2-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), { { { union_ex(lower_layer_polygons) }, { "lower_layer_polygons", "gray", 0.2f } }, { { union_ex(*new_layer.contact_polygons) }, { "new_layer.contact_polygons", "yellow", 0.5f } }, { { union_ex(contact_polygons) }, { "contact_polygons", "blue", 0.5f } }, From 352d0bb21dd08effeee332421b50af58d894c8b1 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 15:05:08 +0200 Subject: [PATCH 07/11] Faster and hopefully more reliable projection of paint-on support blockers and enforcers on a sliced mesh. --- src/libslic3r/PrintObject.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ee09e0f5b79..d8d26baa613 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2294,9 +2294,13 @@ void PrintObject::project_and_append_custom_facets( ? mv->seam_facets.get_facets_strict(*mv, type) : mv->supported_facets.get_facets_strict(*mv, type); if (! custom_facets.indices.empty()) +#if 0 project_triangles_to_slabs(this->layers(), custom_facets, (this->trafo_centered() * mv->get_matrix()).cast(), seam, out); +#else + slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &out, [](){}); +#endif } } From 97dc182d27a9e77a5ca70b5709f774503bbec72c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 27 Aug 2021 19:46:44 +0200 Subject: [PATCH 08/11] Fixed shifted clippimg plane triangulation on scaled meshes, fighting z-fighting has to be done in world coords. --- src/slic3r/GUI/MeshUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index ba83bdbff78..75232c93015 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -106,7 +106,6 @@ void MeshClipper::recalculate_triangles() Transform3d tr = Transform3d::Identity(); tr.rotate(q); tr = m_trafo.get_matrix() * tr; - height_mesh += 0.001f; // to avoid z-fighting if (m_limiting_plane != ClippingPlane::ClipsNothing()) { @@ -165,6 +164,8 @@ void MeshClipper::recalculate_triangles() m_triangles2d = triangulate_expolygons_2f(expolys, m_trafo.get_matrix().matrix().determinant() < 0.); + tr.pretranslate(0.001 * m_plane.get_normal().normalized()); // to avoid z-fighting + m_vertex_array.release_geometry(); for (auto it=m_triangles2d.cbegin(); it != m_triangles2d.cend(); it=it+3) { m_vertex_array.push_geometry(tr * Vec3d((*(it+0))(0), (*(it+0))(1), height_mesh), up); From aae7e5f2a7c7865a307be8e12b79f3a9165008f5 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 27 Aug 2021 21:04:11 +0200 Subject: [PATCH 09/11] Fix of paint on supports don't work for object that has been scaled up #6718 The triangle-ray intersection function used a hard coded epsilon, which did not work for triangle meshes, that were either too small or too large. Newly the epsilon may be provided to the AABBTreeIndirect search functions externally and IndexedMesh calculates a suitable epsilon on demand from an average triangle mesh edge length. --- src/libslic3r/AABBTreeIndirect.hpp | 125 ++++++++++++++++++++--------- src/libslic3r/SLA/IndexedMesh.cpp | 26 +++--- src/libslic3r/SLA/IndexedMesh.hpp | 8 +- src/libslic3r/TriangleMesh.cpp | 15 ++++ src/libslic3r/TriangleMesh.hpp | 1 + src/slic3r/GUI/MeshUtils.hpp | 2 +- 6 files changed, 127 insertions(+), 50 deletions(-) diff --git a/src/libslic3r/AABBTreeIndirect.hpp b/src/libslic3r/AABBTreeIndirect.hpp index 76aa36194e2..217166f8c73 100644 --- a/src/libslic3r/AABBTreeIndirect.hpp +++ b/src/libslic3r/AABBTreeIndirect.hpp @@ -15,11 +15,6 @@ #include "Utils.hpp" // for next_highest_power_of_2() -extern "C" -{ -// Ray-Triangle Intersection Test Routines by Tomas Moller, May 2000 -#include -} // Definition of the ray intersection hit structure. #include @@ -231,6 +226,9 @@ namespace detail { const VectorType origin; const VectorType dir; const VectorType invdir; + + // epsilon for ray-triangle intersection, see intersect_triangle1() + const double eps; }; template @@ -283,44 +281,91 @@ namespace detail { return tmin < t1 && tmax > t0; } + // The following intersect_triangle() is derived from raytri.c routine intersect_triangle1() + // Ray-Triangle Intersection Test Routines + // Different optimizations of my and Ben Trumbore's + // code from journals of graphics tools (JGT) + // http://www.acm.org/jgt/ + // by Tomas Moller, May 2000 template - std::enable_if_t::value && std::is_same::value, bool> - intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v) { - return intersect_triangle1(const_cast(origin.data()), const_cast(dir.data()), - const_cast(v0.data()), const_cast(v1.data()), const_cast(v2.data()), - &t, &u, &v); + std::enable_if_t::value&& std::is_same::value, bool> + intersect_triangle(const V &orig, const V &dir, const W &vert0, const W &vert1, const W &vert2, double &t, double &u, double &v, double eps) + { + // find vectors for two edges sharing vert0 + const V edge1 = vert1 - vert0; + const V edge2 = vert2 - vert0; + // begin calculating determinant - also used to calculate U parameter + const V pvec = dir.cross(edge2); + // if determinant is near zero, ray lies in plane of triangle + const double det = edge1.dot(pvec); + V qvec; + + if (det > eps) { + // calculate distance from vert0 to ray origin + V tvec = orig - vert0; + // calculate U parameter and test bounds + u = tvec.dot(pvec); + if (u < 0.0 || u > det) + return false; + // prepare to test V parameter + qvec = tvec.cross(edge1); + // calculate V parameter and test bounds + v = dir.dot(qvec); + if (v < 0.0 || u + v > det) + return false; + } else if (det < -eps) { + // calculate distance from vert0 to ray origin + V tvec = orig - vert0; + // calculate U parameter and test bounds + u = tvec.dot(pvec); + if (u > 0.0 || u < det) + return false; + // prepare to test V parameter + qvec = tvec.cross(edge1); + // calculate V parameter and test bounds + v = dir.dot(qvec); + if (v > 0.0 || u + v < det) + return false; + } else + // ray is parallel to the plane of the triangle + return false; + + double inv_det = 1.0 / det; + // calculate t, ray intersects triangle + t = edge2.dot(qvec) * inv_det; + u *= inv_det; + v *= inv_det; + return true; } template std::enable_if_t::value && !std::is_same::value, bool> - intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v) { - using Vector = Eigen::Matrix; - Vector w0 = v0.template cast(); - Vector w1 = v1.template cast(); - Vector w2 = v2.template cast(); - return intersect_triangle1(const_cast(origin.data()), const_cast(dir.data()), - w0.data(), w1.data(), w2.data(), &t, &u, &v); + intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v, double eps) { + return intersect_triangle(origin, dir, v0.template cast(), v1.template cast(), v2.template cast(), t, u, v, eps); } template std::enable_if_t::value && std::is_same::value, bool> - intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v) { - using Vector = Eigen::Matrix; - Vector o = origin.template cast(); - Vector d = dir.template cast(); - return intersect_triangle1(o.data(), d.data(), const_cast(v0.data()), const_cast(v1.data()), const_cast(v2.data()), &t, &u, &v); + intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v, double eps) { + return intersect_triangle(origin.template cast(), dir.template cast(), v0, v1, v2, t, u, v, eps); } template std::enable_if_t::value && ! std::is_same::value, bool> - intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v) { - using Vector = Eigen::Matrix; - Vector o = origin.template cast(); - Vector d = dir.template cast(); - Vector w0 = v0.template cast(); - Vector w1 = v1.template cast(); - Vector w2 = v2.template cast(); - return intersect_triangle1(o.data(), d.data(), w0.data(), w1.data(), w2.data(), &t, &u, &v); + intersect_triangle(const V &origin, const V &dir, const W &v0, const W &v1, const W &v2, double &t, double &u, double &v, double eps) { + return intersect_triangle(origin.template cast(), dir.template cast(), v0.template cast(), v1.template cast(), v2.template cast(), t, u, v, eps); + } + + template + double intersect_triangle_epsilon(const Tree &tree) { + double eps = 0.000001; + if (! tree.empty()) { + const typename Tree::BoundingBox &bbox = tree.nodes().front().bbox; + double l = (bbox.max() - bbox.min()).cwiseMax(); + if (l > 0) + eps /= (l * l); + } + return eps; } template @@ -343,7 +388,7 @@ namespace detail { if (intersect_triangle( ray_intersector.origin, ray_intersector.dir, ray_intersector.vertices[face(0)], ray_intersector.vertices[face(1)], ray_intersector.vertices[face(2)], - t, u, v) + t, u, v, ray_intersector.eps) && t > 0.) { hit = igl::Hit { int(node.idx), -1, float(u), float(v), float(t) }; return true; @@ -388,7 +433,7 @@ namespace detail { if (intersect_triangle( ray_intersector.origin, ray_intersector.dir, ray_intersector.vertices[face(0)], ray_intersector.vertices[face(1)], ray_intersector.vertices[face(2)], - t, u, v) + t, u, v, ray_intersector.eps) && t > 0.) { ray_intersector.hits.emplace_back(igl::Hit{ int(node.idx), -1, float(u), float(v), float(t) }); } @@ -623,12 +668,15 @@ inline bool intersect_ray_first_hit( // Direction of the ray. const VectorType &dir, // First intersection of the ray with the indexed triangle set. - igl::Hit &hit) + igl::Hit &hit, + // Epsilon for the ray-triangle intersection, it should be proportional to an average triangle edge length. + const double eps = 0.000001) { using Scalar = typename VectorType::Scalar; - auto ray_intersector = detail::RayIntersector { + auto ray_intersector = detail::RayIntersector { vertices, faces, tree, - origin, dir, VectorType(dir.cwiseInverse()) + origin, dir, VectorType(dir.cwiseInverse()), + eps }; return ! tree.empty() && detail::intersect_ray_recursive_first_hit( ray_intersector, size_t(0), std::numeric_limits::infinity(), hit); @@ -652,11 +700,14 @@ inline bool intersect_ray_all_hits( // Direction of the ray. const VectorType &dir, // All intersections of the ray with the indexed triangle set, sorted by parameter t. - std::vector &hits) + std::vector &hits, + // Epsilon for the ray-triangle intersection, it should be proportional to an average triangle edge length. + const double eps = 0.000001) { auto ray_intersector = detail::RayIntersectorHits { { vertices, faces, {tree}, - origin, dir, VectorType(dir.cwiseInverse()) } + origin, dir, VectorType(dir.cwiseInverse()), + eps } }; if (! tree.empty()) { ray_intersector.hits.reserve(8); diff --git a/src/libslic3r/SLA/IndexedMesh.cpp b/src/libslic3r/SLA/IndexedMesh.cpp index 887ef1555d7..07c4203ab22 100644 --- a/src/libslic3r/SLA/IndexedMesh.cpp +++ b/src/libslic3r/SLA/IndexedMesh.cpp @@ -17,10 +17,18 @@ namespace sla { class IndexedMesh::AABBImpl { private: AABBTreeIndirect::Tree3f m_tree; + double m_triangle_ray_epsilon; public: - void init(const indexed_triangle_set &its) + void init(const indexed_triangle_set &its, bool calculate_epsilon) { + m_triangle_ray_epsilon = 0.000001; + if (calculate_epsilon) { + // Calculate epsilon from average triangle edge length. + double l = its_average_edge_length(its); + if (l > 0) + m_triangle_ray_epsilon = 0.000001 * l * l; + } m_tree = AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set( its.vertices, its.indices); } @@ -31,7 +39,7 @@ public: igl::Hit & hit) { AABBTreeIndirect::intersect_ray_first_hit(its.vertices, its.indices, - m_tree, s, dir, hit); + m_tree, s, dir, hit, m_triangle_ray_epsilon); } void intersect_ray(const indexed_triangle_set &its, @@ -40,7 +48,7 @@ public: std::vector & hits) { AABBTreeIndirect::intersect_ray_all_hits(its.vertices, its.indices, - m_tree, s, dir, hits); + m_tree, s, dir, hits, m_triangle_ray_epsilon); } double squared_distance(const indexed_triangle_set & its, @@ -60,25 +68,25 @@ public: } }; -template void IndexedMesh::init(const M &mesh) +template void IndexedMesh::init(const M &mesh, bool calculate_epsilon) { BoundingBoxf3 bb = bounding_box(mesh); m_ground_level += bb.min(Z); // Build the AABB accelaration tree - m_aabb->init(*m_tm); + m_aabb->init(*m_tm, calculate_epsilon); } -IndexedMesh::IndexedMesh(const indexed_triangle_set& tmesh) +IndexedMesh::IndexedMesh(const indexed_triangle_set& tmesh, bool calculate_epsilon) : m_aabb(new AABBImpl()), m_tm(&tmesh) { - init(tmesh); + init(tmesh, calculate_epsilon); } -IndexedMesh::IndexedMesh(const TriangleMesh &mesh) +IndexedMesh::IndexedMesh(const TriangleMesh &mesh, bool calculate_epsilon) : m_aabb(new AABBImpl()), m_tm(&mesh.its) { - init(mesh); + init(mesh, calculate_epsilon); } IndexedMesh::~IndexedMesh() {} diff --git a/src/libslic3r/SLA/IndexedMesh.hpp b/src/libslic3r/SLA/IndexedMesh.hpp index 25ab75b8360..9348a97c9bd 100644 --- a/src/libslic3r/SLA/IndexedMesh.hpp +++ b/src/libslic3r/SLA/IndexedMesh.hpp @@ -42,12 +42,14 @@ class IndexedMesh { std::vector m_holes; #endif - template void init(const M &mesh); + template void init(const M &mesh, bool calculate_epsilon); public: - explicit IndexedMesh(const indexed_triangle_set&); - explicit IndexedMesh(const TriangleMesh &mesh); + // calculate_epsilon ... calculate epsilon for triangle-ray intersection from an average triangle edge length. + // If set to false, a default epsilon is used, which works for "reasonable" meshes. + explicit IndexedMesh(const indexed_triangle_set &tmesh, bool calculate_epsilon = false); + explicit IndexedMesh(const TriangleMesh &mesh, bool calculate_epsilon = false); IndexedMesh(const IndexedMesh& other); IndexedMesh& operator=(const IndexedMesh&); diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index d4baabc977a..fa8f8bce64e 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -1275,6 +1275,21 @@ float its_volume(const indexed_triangle_set &its) return volume; } +float its_average_edge_length(const indexed_triangle_set &its) +{ + if (its.indices.empty()) + return 0.f; + + double edge_length = 0.f; + for (size_t i = 0; i < its.indices.size(); ++ i) { + const its_triangle v = its_triangle_vertices(its, i); + edge_length += (v[1] - v[0]).cast().norm() + + (v[2] - v[0]).cast().norm() + + (v[1] - v[2]).cast().norm(); + } + return float(edge_length / (3 * its.indices.size())); +} + std::vector its_split(const indexed_triangle_set &its) { return its_split<>(its); diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index b7a1bebb150..c463af5a22e 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -199,6 +199,7 @@ inline stl_normal its_unnormalized_normal(const indexed_triangle_set &its, } float its_volume(const indexed_triangle_set &its); +float its_average_edge_length(const indexed_triangle_set &its); void its_merge(indexed_triangle_set &A, const indexed_triangle_set &B); void its_merge(indexed_triangle_set &A, const std::vector &triangles); diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index ec6c337c06e..65c32611688 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -112,7 +112,7 @@ public: // The class references extern TriangleMesh, which must stay alive // during MeshRaycaster existence. MeshRaycaster(const TriangleMesh& mesh) - : m_emesh(mesh) + : m_emesh(mesh, true) // calculate epsilon for triangle-ray intersection from an average edge length { m_normals.reserve(mesh.stl.facet_start.size()); for (const stl_facet& facet : mesh.stl.facet_start) From 37e4f36255997bce3710491370db7cdad85cabd4 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Sat, 28 Aug 2021 14:35:12 +0200 Subject: [PATCH 10/11] Desktop integration escaping path --- src/slic3r/GUI/DesktopIntegrationDialog.cpp | 98 +++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.cpp b/src/slic3r/GUI/DesktopIntegrationDialog.cpp index fb4a62f918c..d34d0730e1e 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.cpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.cpp @@ -22,6 +22,93 @@ namespace Slic3r { namespace GUI { namespace { + +// escaping of path string according to +// https://cgit.freedesktop.org/xdg/xdg-specs/tree/desktop-entry/desktop-entry-spec.xml +std::string escape_string(const std::string& str) +{ + // The buffer needs to be bigger if escaping <,>,& + std::vector out(str.size() * 2, 0); + char *outptr = out.data(); + for (size_t i = 0; i < str.size(); ++ i) { + char c = str[i]; + // must be escaped + if (c == '\"') { //double quote + (*outptr ++) = '\\'; + (*outptr ++) = '\"'; + } else if (c == '`') { // backtick character + (*outptr ++) = '\\'; + (*outptr ++) = '`'; + } else if (c == '$') { // dollar sign + (*outptr ++) = '\\'; + (*outptr ++) = '$'; + } else if (c == '\\') { // backslash character + (*outptr ++) = '\\'; + (*outptr ++) = '\\'; + // Reserved characters + // At Ubuntu, all these characters must NOT be escaped for desktop integration to work + /* + } else if (c == ' ') { // space + (*outptr ++) = '\\'; + (*outptr ++) = ' '; + } else if (c == '\t') { // tab + (*outptr ++) = '\\'; + (*outptr ++) = '\t'; + } else if (c == '\n') { // newline + (*outptr ++) = '\\'; + (*outptr ++) = '\n'; + } else if (c == '\'') { // single quote + (*outptr ++) = '\\'; + (*outptr ++) = '\''; + } else if (c == '>') { // greater-than sign + (*outptr ++) = '\\'; + (*outptr ++) = '&'; + (*outptr ++) = 'g'; + (*outptr ++) = 't'; + (*outptr ++) = ';'; + } else if (c == '<') { //less-than sign + (*outptr ++) = '\\'; + (*outptr ++) = '&'; + (*outptr ++) = 'l'; + (*outptr ++) = 't'; + (*outptr ++) = ';'; + } else if (c == '~') { // tilde + (*outptr ++) = '\\'; + (*outptr ++) = '~'; + } else if (c == '|') { // vertical bar + (*outptr ++) = '\\'; + (*outptr ++) = '|'; + } else if (c == '&') { // ampersand + (*outptr ++) = '\\'; + (*outptr ++) = '&'; + (*outptr ++) = 'a'; + (*outptr ++) = 'm'; + (*outptr ++) = 'p'; + (*outptr ++) = ';'; + } else if (c == ';') { // semicolon + (*outptr ++) = '\\'; + (*outptr ++) = ';'; + } else if (c == '*') { //asterisk + (*outptr ++) = '\\'; + (*outptr ++) = '*'; + } else if (c == '?') { // question mark + (*outptr ++) = '\\'; + (*outptr ++) = '?'; + } else if (c == '#') { // hash mark + (*outptr ++) = '\\'; + (*outptr ++) = '#'; + } else if (c == '(') { // parenthesis + (*outptr ++) = '\\'; + (*outptr ++) = '('; + } else if (c == ')') { + (*outptr ++) = '\\'; + (*outptr ++) = ')'; + */ + } else + (*outptr ++) = c; + } + return std::string(out.data(), outptr - out.data()); +} // Disects path strings stored in system variable divided by ':' and adds into vector void resolve_path_from_var(const std::string& var, std::vector& paths) { @@ -157,7 +244,8 @@ void DesktopIntegrationDialog::perform_desktop_integration() } // Escape ' characters in appimage, other special symbols will be esacaped in desktop file by 'excutable_path' - boost::replace_all(excutable_path, "'", "'\\''"); + //boost::replace_all(excutable_path, "'", "'\\''"); + excutable_path = escape_string(excutable_path); // Find directories icons and applications // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. @@ -243,14 +331,14 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=PrusaSlicer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer%2%\n" - "Exec=\'%3%\' %%F\n" + "Exec=\"%3%\" %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n" "Categories=Graphics;3DGraphics;Engineering;\n" "Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA\n" "StartupNotify=false\n" - "StartupWMClass=prusa-slicer", name_suffix, version_suffix, excutable_path); + "StartupWMClass=prusa-slicer\n", name_suffix, version_suffix, excutable_path); std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); if (create_desktop_file(path, desktop_file)){ @@ -310,13 +398,13 @@ void DesktopIntegrationDialog::perform_desktop_integration() "Name=Prusa Gcode Viewer%1%\n" "GenericName=3D Printing Software\n" "Icon=PrusaSlicer-gcodeviewer%2%\n" - "Exec=\'%3%\' --gcodeviwer %%F\n" + "Exec=\"%3%\" --gcodeviewer %%F\n" "Terminal=false\n" "Type=Application\n" "MimeType=text/x.gcode;\n" "Categories=Graphics;3DGraphics;\n" "Keywords=3D;Printing;Slicer;\n" - "StartupNotify=false", name_suffix, version_suffix, excutable_path); + "StartupNotify=false\n", name_suffix, version_suffix, excutable_path); std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix); if (create_desktop_file(desktop_path, desktop_file)) From f16eb95ea2a99d604a17c6bc2c76098a6bac1f47 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 30 Aug 2021 08:29:50 +0200 Subject: [PATCH 11/11] Revert of d701dfe436b353f4847b7a78605847f85e50e4eb --- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d4030d41f2f..b85219c0b4d 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1049,7 +1049,7 @@ void ObjectList::key_event(wxKeyEvent& event) || event.GetKeyCode() == WXK_BACK #endif //__WXOSX__ ) { - wxGetApp().plater()->remove_selected(); + remove(); } else if (event.GetKeyCode() == WXK_F5) wxGetApp().plater()->reload_all_from_disk();