diff --git a/resources/icons/exclamation_manifold.svg b/resources/icons/exclamation_manifold.svg new file mode 100644 index 000000000..cd8ba5954 --- /dev/null +++ b/resources/icons/exclamation_manifold.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/resources/icons/white/exclamation_manifold.svg b/resources/icons/white/exclamation_manifold.svg new file mode 100644 index 000000000..a18590167 --- /dev/null +++ b/resources/icons/white/exclamation_manifold.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index 177d8d708..f3a1d5988 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -139,6 +139,9 @@ void AppConfig::set_defaults() if (get("default_action_on_select_preset").empty()) set("default_action_on_select_preset", "none"); // , "transfer", "discard" or "save" + if (get("default_action_on_new_project").empty()) + set("default_action_on_new_project", "none"); // , "keep(transfer)", "discard" or "save" + if (get("color_mapinulation_panel").empty()) set("color_mapinulation_panel", "0"); diff --git a/src/libslic3r/BlacklistedLibraryCheck.cpp b/src/libslic3r/BlacklistedLibraryCheck.cpp index 76f675c70..938f54249 100644 --- a/src/libslic3r/BlacklistedLibraryCheck.cpp +++ b/src/libslic3r/BlacklistedLibraryCheck.cpp @@ -12,7 +12,7 @@ namespace Slic3r { #ifdef WIN32 //only dll name with .dll suffix - currently case sensitive -const std::vector BlacklistedLibraryCheck::blacklist({ L"NahimicOSD.dll", L"SS2OSD.dll" }); +const std::vector BlacklistedLibraryCheck::blacklist({ L"NahimicOSD.dll", L"SS2OSD.dll", L"amhook.dll", L"AMHook.dll" }); bool BlacklistedLibraryCheck::get_blacklisted(std::vector& names) { diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index a1dd638ca..e8f87a6e3 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -126,6 +126,45 @@ ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) return PolyTreeToExPolygons(std::move(polytree)); } +#if 0 +// Global test. +bool has_duplicate_points(const ClipperLib::PolyTree &polytree) +{ + struct Helper { + static void collect_points_recursive(const ClipperLib::PolyNode &polynode, ClipperLib::Path &out) { + // For each hole of the current expolygon: + out.insert(out.end(), polynode.Contour.begin(), polynode.Contour.end()); + for (int i = 0; i < polynode.ChildCount(); ++ i) + collect_points_recursive(*polynode.Childs[i], out); + } + }; + ClipperLib::Path pts; + for (int i = 0; i < polytree.ChildCount(); ++ i) + Helper::collect_points_recursive(*polytree.Childs[i], pts); + return has_duplicate_points(std::move(pts)); +} +#else +// Local test inside each of the contours. +bool has_duplicate_points(const ClipperLib::PolyTree &polytree) +{ + struct Helper { + static bool has_duplicate_points_recursive(const ClipperLib::PolyNode &polynode) { + if (has_duplicate_points(polynode.Contour)) + return true; + for (int i = 0; i < polynode.ChildCount(); ++ i) + if (has_duplicate_points_recursive(*polynode.Childs[i])) + return true; + return false; + } + }; + ClipperLib::Path pts; + for (int i = 0; i < polytree.ChildCount(); ++ i) + if (Helper::has_duplicate_points_recursive(*polytree.Childs[i])) + return true; + return false; +} +#endif + // Offset outside by 10um, one by one. template static ClipperLib::Paths safety_offset(PathsProvider &&paths) diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index ab58a43aa..2d4780d0e 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -740,7 +740,11 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo } // Load the config keys from the given string. -static inline size_t load_from_gcode_string_legacy(ConfigBase &config, const char *str, ConfigSubstitutionContext &substitutions) +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT +size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions) +#else +static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions) +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT { if (str == nullptr) return 0; diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 6439e4632..dd121c90a 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -2015,6 +2015,10 @@ public: // Set all the nullable values to nils. void null_nullables(); +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions); +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + private: // Set a configuration value from a string. bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append); diff --git a/src/libslic3r/ExPolygon.cpp b/src/libslic3r/ExPolygon.cpp index 4a40c02c3..bfe0479fe 100644 --- a/src/libslic3r/ExPolygon.cpp +++ b/src/libslic3r/ExPolygon.cpp @@ -114,10 +114,11 @@ bool ExPolygon::contains(const Polylines &polylines) const bool ExPolygon::contains(const Point &point) const { - if (!this->contour.contains(point)) return false; - for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) { - if (it->contains(point)) return false; - } + if (! this->contour.contains(point)) + return false; + for (const Polygon &hole : this->holes) + if (hole.contains(point)) + return false; return true; } @@ -367,6 +368,57 @@ extern std::vector get_extents_vector(const ExPolygons &polygons) return out; } +bool has_duplicate_points(const ExPolygon &expoly) +{ +#if 1 + // Check globally. + size_t cnt = expoly.contour.points.size(); + for (const Polygon &hole : expoly.holes) + cnt += hole.points.size(); + std::vector allpts; + allpts.reserve(cnt); + allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end()); + for (const Polygon &hole : expoly.holes) + allpts.insert(allpts.end(), hole.points.begin(), hole.points.end()); + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + if (has_duplicate_points(expoly.contour)) + return true; + for (const Polygon &hole : expoly.holes) + if (has_duplicate_points(hole)) + return true; + return false; +#endif +} + +bool has_duplicate_points(const ExPolygons &expolys) +{ +#if 1 + // Check globally. + size_t cnt = 0; + for (const ExPolygon &expoly : expolys) { + cnt += expoly.contour.points.size(); + for (const Polygon &hole : expoly.holes) + cnt += hole.points.size(); + } + std::vector allpts; + allpts.reserve(cnt); + for (const ExPolygon &expoly : expolys) { + allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end()); + for (const Polygon &hole : expoly.holes) + allpts.insert(allpts.end(), hole.points.begin(), hole.points.end()); + } + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + for (const ExPolygon &expoly : expolys) + if (has_duplicate_points(expoly)) + return true; + return false; +#endif +} + bool remove_sticks(ExPolygon &poly) { return remove_sticks(poly.contour) || remove_sticks(poly.holes); diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 464310ac0..6f3884673 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -351,20 +351,24 @@ inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double toleranc return out; } -extern BoundingBox get_extents(const ExPolygon &expolygon); -extern BoundingBox get_extents(const ExPolygons &expolygons); -extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); -extern BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle); -extern std::vector get_extents_vector(const ExPolygons &polygons); +BoundingBox get_extents(const ExPolygon &expolygon); +BoundingBox get_extents(const ExPolygons &expolygons); +BoundingBox get_extents_rotated(const ExPolygon &poly, double angle); +BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle); +std::vector get_extents_vector(const ExPolygons &polygons); -extern bool remove_sticks(ExPolygon &poly); -extern void keep_largest_contour_only(ExPolygons &polygons); +// Test for duplicate points. The points are copied, sorted and checked for duplicates globally. +bool has_duplicate_points(const ExPolygon &expoly); +bool has_duplicate_points(const ExPolygons &expolys); + +bool remove_sticks(ExPolygon &poly); +void keep_largest_contour_only(ExPolygons &polygons); inline double area(const ExPolygon &poly) { return poly.area(); } inline double area(const ExPolygons &polys) { double s = 0.; for (auto &p : polys) s += p.area(); return s; } // Removes all expolygons smaller than min_area and also removes all holes smaller than min_area -extern bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area); +bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area); } // namespace Slic3r diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 90fa9bfae..1ca20bcba 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -1890,6 +1890,7 @@ namespace Slic3r { unsigned int geo_tri_count = (unsigned int)geometry.triangles.size(); unsigned int renamed_volumes_count = 0; + int processed_vertices_max_id = 0; for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) { if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) { @@ -1911,13 +1912,31 @@ namespace Slic3r { // splits volume out of imported geometry std::vector faces(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1); const size_t triangles_count = faces.size(); - for (Vec3i face : faces) - for (unsigned int tri_id : face) - if (tri_id < 0 || tri_id >= geometry.vertices.size()) { + + int min_id = faces.front()[0]; + int max_id = faces.front()[0]; + for (const Vec3i& face : faces) { + for (const int tri_id : face) { + if (tri_id < 0 || tri_id >= int(geometry.vertices.size())) { add_error("Found invalid vertex id"); return false; } - TriangleMesh triangle_mesh(std::move(geometry.vertices), std::move(faces)); + min_id = std::min(min_id, tri_id); + max_id = std::max(max_id, tri_id); + } + } + + // rebase indices to the current vertices list + for (Vec3i& face : faces) { + for (int& tri_id : face) { + tri_id -= min_id; + } + } + + processed_vertices_max_id = 1 + std::max(processed_vertices_max_id, max_id); + + std::vector vertices(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1); + TriangleMesh triangle_mesh(std::move(vertices), std::move(faces)); if (m_version == 0) { // if the 3mf was not produced by PrusaSlicer and there is only one instance, diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index 9392485f6..f0807df51 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -598,7 +598,7 @@ void AMFParserContext::endElement(const char * /* name */) case NODE_TYPE_VERTEX: assert(m_object); // Parse the vertex data - m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[1].c_str()))); + m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[2].c_str()))); m_value[0].clear(); m_value[1].clear(); m_value[2].clear(); diff --git a/src/libslic3r/Format/OBJ.cpp b/src/libslic3r/Format/OBJ.cpp index 54c373ce3..3b05bb574 100644 --- a/src/libslic3r/Format/OBJ.cpp +++ b/src/libslic3r/Format/OBJ.cpp @@ -73,7 +73,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr) break; } else { assert(cnt < 4); - if (vertex.coordIdx < 0 || vertex.coordIdx >= its.vertices.size()) { + if (vertex.coordIdx < 0 || vertex.coordIdx >= int(its.vertices.size())) { BOOST_LOG_TRIVIAL(error) << "load_obj: failed to parse " << path << ". The file contains invalid vertex index."; return false; } diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index e2ef801f2..4ddc584ba 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -203,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg) if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h || !opt_mirror_x || !opt_mirror_y || !opt_orient) - throw Slic3r::FileIOError("Invalid SL1 / SL1S file"); + throw MissingProfileError("Invalid SL1 / SL1S file"); RasterParams rstp; @@ -229,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg) auto *opt_init_layerh = cfg.option("initial_layer_height"); if (!opt_layerh || !opt_init_layerh) - throw Slic3r::FileIOError("Invalid SL1 / SL1S file"); + throw MissingProfileError("Invalid SL1 / SL1S file"); return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()}; } @@ -293,24 +293,34 @@ ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrint return out.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable); } +// If the profile is missing from the archive (older PS versions did not have +// it), profile_out's initial value will be used as fallback. profile_out will be empty on +// function return if the archive did not contain any profile. ConfigSubstitutions import_sla_archive( const std::string & zipfname, Vec2i windowsize, indexed_triangle_set & out, - DynamicPrintConfig & profile, + DynamicPrintConfig & profile_out, std::function progr) { // Ensure minimum window size for marching squares windowsize.x() = std::max(2, windowsize.x()); windowsize.y() = std::max(2, windowsize.y()); - ArchiveData arch = extract_sla_archive(zipfname, "thumbnail"); - ConfigSubstitutions config_substitutions = profile.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable); + std::string exclude_entries{"thumbnail"}; + ArchiveData arch = extract_sla_archive(zipfname, exclude_entries); + DynamicPrintConfig profile_in, profile_use; + ConfigSubstitutions config_substitutions = profile_in.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable); - RasterParams rstp = get_raster_params(profile); + // If the archive contains an empty profile, use the one that was passed as output argument + // then replace it with the readed profile to report that it was empty. + profile_use = profile_in.empty() ? profile_out : profile_in; + profile_out = profile_in; + + RasterParams rstp = get_raster_params(profile_use); rstp.win = {windowsize.y(), windowsize.x()}; - SliceParams slicp = get_slice_params(profile); + SliceParams slicp = get_slice_params(profile_use); std::vector slices = extract_slices_from_sla_archive(arch, rstp, progr); diff --git a/src/libslic3r/Format/SL1.hpp b/src/libslic3r/Format/SL1.hpp index 2c7e1edc1..7f4356b12 100644 --- a/src/libslic3r/Format/SL1.hpp +++ b/src/libslic3r/Format/SL1.hpp @@ -8,7 +8,7 @@ namespace Slic3r { -class SL1Archive: public SLAPrinter { +class SL1Archive: public SLAArchive { SLAPrinterConfig m_cfg; protected: @@ -57,6 +57,8 @@ inline ConfigSubstitutions import_sla_archive( return import_sla_archive(zipfname, windowsize, out, profile, progr); } +class MissingProfileError : public RuntimeError { using RuntimeError::RuntimeError; }; + } // namespace Slic3r::sla #endif // ARCHIVETRAITS_HPP diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bff894558..ff0a7c027 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -784,7 +784,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re } BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info(); - m_processor.finalize(); + // Post-process the G-code to update time stamps. + m_processor.finalize(true); // DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics); DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics); if (result != nullptr) { diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 4e731c8b4..2397a17ff 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -2,6 +2,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Print.hpp" #include "libslic3r/LocalesUtils.hpp" +#include "libslic3r/format.hpp" #include "GCodeProcessor.hpp" #include @@ -746,6 +747,9 @@ const std::vector> GCodeProces { EProducer::PrusaSlicer, "generated by PrusaSlicer" }, { EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" }, { EProducer::Slic3r, "generated by Slic3r" }, +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + { EProducer::SuperSlicer, "generated by SuperSlicer" }, +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT { EProducer::Cura, "Cura_SteamEngine" }, { EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" }, { EProducer::CraftWare, "CraftWare" }, @@ -1189,6 +1193,8 @@ static inline const char* remove_eols(const char *begin, const char *end) { return end; } +// Load a G-code into a stand-alone G-code viewer. +// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback). void GCodeProcessor::process_file(const std::string& filename, std::function cancel_callback) { CNumericLocalesSetter locales_setter; @@ -1225,6 +1231,10 @@ void GCodeProcessor::process_file(const std::string& filename, std::functionprocess_gcode_line(line, true); }); - this->finalize(); + // Don't post-process the G-code to update time stamps. + this->finalize(false); } void GCodeProcessor::initialize(const std::string& filename) @@ -1269,7 +1280,7 @@ void GCodeProcessor::process_buffer(const std::string &buffer) }); } -void GCodeProcessor::finalize() +void GCodeProcessor::finalize(bool post_process) { // update width/height of wipe moves for (MoveVertex& move : m_result.moves) { @@ -1299,7 +1310,8 @@ void GCodeProcessor::finalize() m_width_compare.output(); #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends); + if (post_process) + m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends); #if ENABLE_GCODE_VIEWER_STATISTICS m_result.time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_start_time).count(); #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -1356,6 +1368,41 @@ std::vector> GCodeProcessor::get_roles_time(Prin return ret; } +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT +ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule) +{ + // for reference, see: ConfigBase::load_from_gcode_file() + + boost::nowide::ifstream ifs(filename); + + auto header_end_pos = ifs.tellg(); + ConfigSubstitutionContext substitutions_ctxt(compatibility_rule); + size_t key_value_pairs = 0; + + ifs.seekg(0, ifs.end); + auto file_length = ifs.tellg(); + auto data_length = std::min(65535, file_length - header_end_pos); + ifs.seekg(file_length - data_length, ifs.beg); + std::vector data(size_t(data_length) + 1, 0); + ifs.read(data.data(), data_length); + ifs.close(); + key_value_pairs = ConfigBase::load_from_gcode_string_legacy(config, data.data(), substitutions_ctxt); + + if (key_value_pairs < 80) + throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", filename, key_value_pairs)); + + return std::move(substitutions_ctxt.substitutions); +} + +void GCodeProcessor::apply_config_superslicer(const std::string& filename) +{ + DynamicPrintConfig config; + config.apply(FullPrintConfig::defaults()); + load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent); + apply_config(config); +} +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + std::vector GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const { return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? @@ -1845,6 +1892,9 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment) { case EProducer::Slic3rPE: case EProducer::Slic3r: +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + case EProducer::SuperSlicer: +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); } case EProducer::Cura: { return process_cura_tags(comment); } case EProducer::Simplify3D: { return process_simplify3d_tags(comment); } @@ -2674,15 +2724,15 @@ void GCodeProcessor::process_G28(const GCodeReader::GCodeLine& line) std::string_view cmd = line.cmd(); std::string new_line_raw = { cmd.data(), cmd.size() }; bool found = false; - if (line.has_x()) { + if (line.has('X')) { new_line_raw += " X0"; found = true; } - if (line.has_y()) { + if (line.has('Y')) { new_line_raw += " Y0"; found = true; } - if (line.has_z()) { + if (line.has('Z')) { new_line_raw += " Z0"; found = true; } @@ -2818,16 +2868,16 @@ void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line) // see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md // Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082 - if (line.has_x()) + if (line.has('X')) m_origin[X] = 0.0f; - if (line.has_y()) + if (line.has('Y')) m_origin[Y] = 0.0f; - if (line.has_z()) + if (line.has('Z')) m_origin[Z] = 0.0f; - if (line.has_e()) + if (line.has('E')) m_origin[E] = 0.0f; } @@ -2988,7 +3038,7 @@ void GCodeProcessor::process_M402(const GCodeReader::GCodeLine& line) // https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp // void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed) - bool has_xyz = !(line.has_x() || line.has_y() || line.has_z()); + bool has_xyz = !(line.has('X') || line.has('Y') || line.has('Z')); float p = FLT_MAX; for (unsigned char a = X; a <= Z; ++a) { diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index 5af040307..fce888233 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -543,6 +543,9 @@ namespace Slic3r { PrusaSlicer, Slic3rPE, Slic3r, +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + SuperSlicer, +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT Cura, Simplify3D, CraftWare, @@ -579,14 +582,14 @@ namespace Slic3r { const Result& get_result() const { return m_result; } Result&& extract_result() { return std::move(m_result); } - // Process the gcode contained in the file with the given filename + // Load a G-code into a stand-alone G-code viewer. // throws CanceledException through print->throw_if_canceled() (sent by the caller as callback). void process_file(const std::string& filename, std::function cancel_callback = nullptr); // Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion. void initialize(const std::string& filename); void process_buffer(const std::string& buffer); - void finalize(); + void finalize(bool post_process); float get_time(PrintEstimatedStatistics::ETimeMode mode) const; std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const; @@ -599,6 +602,9 @@ namespace Slic3r { private: void apply_config(const DynamicPrintConfig& config); void apply_config_simplify3d(const std::string& filename); +#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT + void apply_config_superslicer(const std::string& filename); +#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled); // Process tags embedded into comments diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp index 657f47f0e..7b106463a 100644 --- a/src/libslic3r/GCodeReader.cpp +++ b/src/libslic3r/GCodeReader.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 5001a956c..7bc28f904 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1619,6 +1619,7 @@ TriangleMeshStats ModelObject::get_object_stl_stats() const const TriangleMeshStats& stats = volume->mesh().stats(); // initialize full_stats (for repaired errors) + full_stats.open_edges += stats.open_edges; full_stats.degenerate_facets += stats.degenerate_facets; full_stats.edges_fixed += stats.edges_fixed; full_stats.facets_removed += stats.facets_removed; diff --git a/src/libslic3r/Point.cpp b/src/libslic3r/Point.cpp index 7f351d259..b1f3a74bb 100644 --- a/src/libslic3r/Point.cpp +++ b/src/libslic3r/Point.cpp @@ -179,6 +179,15 @@ Point Point::projection_onto(const Line &line) const return ((line.a - *this).cast().squaredNorm() < (line.b - *this).cast().squaredNorm()) ? line.a : line.b; } +bool has_duplicate_points(std::vector &&pts) +{ + std::sort(pts.begin(), pts.end()); + for (size_t i = 1; i < pts.size(); ++ i) + if (pts[i - 1] == pts[i]) + return true; + return false; +} + BoundingBox get_extents(const Points &pts) { return BoundingBox(pts); diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 21eb48c2e..499ab073d 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -211,8 +211,34 @@ inline Point lerp(const Point &a, const Point &b, double t) return ((1. - t) * a.cast() + t * b.cast()).cast(); } -extern BoundingBox get_extents(const Points &pts); -extern BoundingBox get_extents(const std::vector &pts); +BoundingBox get_extents(const Points &pts); +BoundingBox get_extents(const std::vector &pts); + +// Test for duplicate points in a vector of points. +// The points are copied, sorted and checked for duplicates globally. +bool has_duplicate_points(std::vector &&pts); +inline bool has_duplicate_points(const std::vector &pts) +{ + std::vector cpy = pts; + return has_duplicate_points(std::move(cpy)); +} + +// Test for duplicate points in a vector of points. +// Only successive points are checked for equality. +inline bool has_duplicate_successive_points(const std::vector &pts) +{ + for (size_t i = 1; i < pts.size(); ++ i) + if (pts[i - 1] == pts[i]) + return true; + return false; +} + +// Test for duplicate points in a vector of points. +// Only successive points are checked for equality. Additionally, first and last points are compared for equality. +inline bool has_duplicate_successive_points_closed(const std::vector &pts) +{ + return has_duplicate_successive_points(pts) || (pts.size() >= 2 && pts.front() == pts.back()); +} namespace int128 { // Exact orientation predicate, diff --git a/src/libslic3r/Polygon.cpp b/src/libslic3r/Polygon.cpp index 5b180afca..42a6cc209 100644 --- a/src/libslic3r/Polygon.cpp +++ b/src/libslic3r/Polygon.cpp @@ -334,6 +334,27 @@ extern std::vector get_extents_vector(const Polygons &polygons) return out; } +bool has_duplicate_points(const Polygons &polys) +{ +#if 1 + // Check globally. + size_t cnt = 0; + for (const Polygon &poly : polys) + cnt += poly.points.size(); + std::vector allpts; + allpts.reserve(cnt); + for (const Polygon &poly : polys) + allpts.insert(allpts.end(), poly.points.begin(), poly.points.end()); + return has_duplicate_points(std::move(allpts)); +#else + // Check per contour. + for (const Polygon &poly : polys) + if (has_duplicate_points(poly)) + return true; + return false; +#endif +} + static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3) { Point v1 = p2 - p1; diff --git a/src/libslic3r/Polygon.hpp b/src/libslic3r/Polygon.hpp index 3c46a564b..29800a31d 100644 --- a/src/libslic3r/Polygon.hpp +++ b/src/libslic3r/Polygon.hpp @@ -78,11 +78,16 @@ public: inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; } inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; } -extern BoundingBox get_extents(const Polygon &poly); -extern BoundingBox get_extents(const Polygons &polygons); -extern BoundingBox get_extents_rotated(const Polygon &poly, double angle); -extern BoundingBox get_extents_rotated(const Polygons &polygons, double angle); -extern std::vector get_extents_vector(const Polygons &polygons); +BoundingBox get_extents(const Polygon &poly); +BoundingBox get_extents(const Polygons &polygons); +BoundingBox get_extents_rotated(const Polygon &poly, double angle); +BoundingBox get_extents_rotated(const Polygons &polygons, double angle); +std::vector get_extents_vector(const Polygons &polygons); + +// Test for duplicate points. The points are copied, sorted and checked for duplicates globally. +inline bool has_duplicate_points(Polygon &&poly) { return has_duplicate_points(std::move(poly.points)); } +inline bool has_duplicate_points(const Polygon &poly) { return has_duplicate_points(poly.points); } +bool has_duplicate_points(const Polygons &polys); inline double total_length(const Polygons &polylines) { double total = 0; @@ -102,19 +107,19 @@ inline double area(const Polygons &polys) } // Remove sticks (tentacles with zero area) from the polygon. -extern bool remove_sticks(Polygon &poly); -extern bool remove_sticks(Polygons &polys); +bool remove_sticks(Polygon &poly); +bool remove_sticks(Polygons &polys); // Remove polygons with less than 3 edges. -extern bool remove_degenerate(Polygons &polys); -extern bool remove_small(Polygons &polys, double min_area); -extern void remove_collinear(Polygon &poly); -extern void remove_collinear(Polygons &polys); +bool remove_degenerate(Polygons &polys); +bool remove_small(Polygons &polys, double min_area); +void remove_collinear(Polygon &poly); +void remove_collinear(Polygons &polys); // Append a vector of polygons at the end of another vector of polygons. -inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } +inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); } -inline void polygons_append(Polygons &dst, Polygons &&src) +inline void polygons_append(Polygons &dst, Polygons &&src) { if (dst.empty()) { dst = std::move(src); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index f5c8235ed..09cd38468 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -1097,14 +1097,6 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil return m_idx_selected; } -// Save the preset under a new name. If the name is different from the old one, -// a new preset is stored into the list of presets. -// All presets are marked as not modified and the new preset is activated. -//void PresetCollection::save_current_preset(const std::string &new_name); - -// Delete the current preset, activate the first visible preset. -//void PresetCollection::delete_current_preset(); - // Update a dirty flag of the current preset // Return true if the dirty flag changed. bool PresetCollection::update_dirty() diff --git a/src/libslic3r/PresetBundle.hpp b/src/libslic3r/PresetBundle.hpp index c22599e38..e5e49fb47 100644 --- a/src/libslic3r/PresetBundle.hpp +++ b/src/libslic3r/PresetBundle.hpp @@ -143,7 +143,7 @@ public: const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const; - // Save current preset of a required type under a new name. If the name is different from the old one, + // Save current preset of a provided type under a new name. If the name is different from the old one, // Unselected option would be reverted to the beginning values void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector& unselected_options); diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index c4b6b7cce..7de74035b 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -60,6 +60,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str DynamicConfig cfg; if (config_override != nullptr) cfg = *config_override; + cfg.set_key_value("version", new ConfigOptionString(std::string(SLIC3R_VERSION))); PlaceholderParser::update_timestamp(cfg); this->update_object_placeholders(cfg, default_ext); if (! filename_base.empty()) { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index d9a4f2670..74ef27bd7 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1447,7 +1447,7 @@ void PrintObject::bridge_over_infill() Polygons to_bridge_pp = internal_solid; // iterate through lower layers spanned by bridge_flow - double bottom_z = layer->print_z - bridge_flow.height(); + double bottom_z = layer->print_z - bridge_flow.height() - EPSILON; for (int i = int(layer_it - m_layers.begin()) - 1; i >= 0; --i) { const Layer* lower_layer = m_layers[i]; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index a09f5ea98..004f7d555 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -670,7 +670,7 @@ std::string SLAPrint::validate(std::string*) const return ""; } -void SLAPrint::set_printer(SLAPrinter *arch) +void SLAPrint::set_printer(SLAArchive *arch) { invalidate_step(slapsRasterize); m_printer = arch; @@ -1047,15 +1047,15 @@ Vec3d SLAPrint::relative_correction() const Vec3d corr(1., 1., 1.); if(printer_config().relative_correction.values.size() >= 2) { - corr(X) = printer_config().relative_correction.values[0]; - corr(Y) = printer_config().relative_correction.values[0]; - corr(Z) = printer_config().relative_correction.values.back(); + corr.x() = printer_config().relative_correction.values[0]; + corr.y() = corr.x(); + corr.z() = printer_config().relative_correction.values[1]; } if(material_config().material_correction.values.size() >= 2) { - corr(X) *= material_config().material_correction.values[0]; - corr(Y) *= material_config().material_correction.values[0]; - corr(Z) *= material_config().material_correction.values.back(); + corr.x() *= material_config().material_correction.values[0]; + corr.y() = corr.x(); + corr.z() *= material_config().material_correction.values[1]; } return corr; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index e11926c7e..deaabbe19 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -387,7 +387,7 @@ struct SLAPrintStatistics } }; -class SLAPrinter { +class SLAArchive { protected: std::vector m_layers; @@ -395,7 +395,7 @@ protected: virtual sla::RasterEncoder get_encoder() const = 0; public: - virtual ~SLAPrinter() = default; + virtual ~SLAArchive() = default; virtual void apply(const SLAPrinterConfig &cfg) = 0; @@ -526,7 +526,7 @@ public: // TODO: use this structure for the preview in the future. const std::vector& print_layers() const { return m_printer_input; } - void set_printer(SLAPrinter *archiver); + void set_printer(SLAArchive *archiver); private: @@ -548,7 +548,7 @@ private: std::vector m_printer_input; // The archive object which collects the raster images after slicing - SLAPrinter *m_printer = nullptr; + SLAArchive *m_printer = nullptr; // Estimated print time, material consumed. SLAPrintStatistics m_print_statistics; diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index f727d334d..280936418 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -721,9 +721,9 @@ public: #ifdef SUPPORT_USE_AGG_RASTERIZER m_bbox = bbox; // Oversample the grid to avoid leaking of supports through or around the object walls. - int oversampling = std::min(8, int(scale_(m_support_spacing) / (scale_(params.extrusion_width) + 100))); - m_pixel_size = scale_(m_support_spacing / oversampling); - assert(scale_(params.extrusion_width) + 20 < m_pixel_size); + int extrusion_width_scaled = scale_(params.extrusion_width); + int oversampling = std::clamp(int(scale_(m_support_spacing) / (extrusion_width_scaled + 100)), 1, 8); + m_pixel_size = std::max(extrusion_width_scaled + 21, scale_(m_support_spacing / oversampling)); // Add one empty column / row boundaries. m_bbox.offset(m_pixel_size); // Grid size fitting the support polygons plus one pixel boundary around the polygons. @@ -1599,7 +1599,8 @@ static inline std::tuple detect_overhangs( static inline std::pair new_contact_layer( const PrintConfig &print_config, const PrintObjectConfig &object_config, - const SlicingParameters &slicing_params, + const SlicingParameters &slicing_params, + const coordf_t support_layer_height_min, const Layer &layer, std::deque &layer_storage, tbb::spin_mutex &layer_storage_mutex) @@ -1629,7 +1630,8 @@ static inline std::pair 1 ? slicing_params.raft_interface_top_z + support_layer_height_min + EPSILON : slicing_params.first_print_layer_height - EPSILON; + if (print_z < min_print_z) { // This contact layer is below the first layer height, therefore not printable. Don't support this surface. return std::pair(nullptr, nullptr); } else if (print_z < slicing_params.first_print_layer_height + EPSILON) { @@ -1650,7 +1652,7 @@ static inline std::pairregion().bridging_height_avg(print_config); bridging_height /= coordf_t(layer.regions().size()); coordf_t bridging_print_z = layer.print_z - bridging_height - slicing_params.gap_support_object; - if (bridging_print_z >= slicing_params.first_print_layer_height - EPSILON) { + if (bridging_print_z >= min_print_z) { // Not below the first layer height means this layer is printable. if (print_z < slicing_params.first_print_layer_height + EPSILON) { // Align the layer with the 1st layer height. @@ -1664,8 +1666,7 @@ static inline std::pairbottom_z = 0; bridging_layer->height = slicing_params.first_print_layer_height; - } - else { + } else { // Don't know the height yet. bridging_layer->bottom_z = bridging_print_z; bridging_layer->height = 0; @@ -1917,7 +1918,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // Now apply the contact areas to the layer where they need to be made. if (! contact_polygons.empty()) { - auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, layer, layer_storage, layer_storage_mutex); + auto [new_layer, bridging_layer] = new_contact_layer(*m_print_config, *m_object_config, m_slicing_params, m_support_params.support_layer_height_min, layer, layer_storage, layer_storage_mutex); if (new_layer) { fill_contact_layer(*new_layer, layer_id, m_slicing_params, *m_object_config, slices_margin, overhang_polygons, contact_polygons, enforcer_polygons, lower_layer_polygons, @@ -2600,8 +2601,6 @@ void PrintObjectSupportMaterial::generate_base_layers( // No top contacts -> no intermediate layers will be produced. return; - // coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing); - BOOST_LOG_TRIVIAL(debug) << "PrintObjectSupportMaterial::generate_base_layers() in parallel - start"; tbb::parallel_for( tbb::blocked_range(0, intermediate_layers.size()), @@ -2696,6 +2695,7 @@ void PrintObjectSupportMaterial::generate_base_layers( layer_intermediate.layer_type = sltBase; #if 0 + // coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing); // Fillet the base polygons and trim them again with the top, interface and contact layers. $base->{$i} = diff( offset2( @@ -3784,7 +3784,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Prepare fillers. SupportMaterialPattern support_pattern = m_object_config->support_material_pattern; bool with_sheath = m_object_config->support_material_with_sheath; - InfillPattern infill_pattern = (support_pattern == smpHoneycomb ? ipHoneycomb : ipSupportBase); + InfillPattern infill_pattern = support_pattern == smpHoneycomb ? ipHoneycomb : (support_density < 1.05 ? ipRectilinear : ipSupportBase); std::vector angles; angles.push_back(base_angle); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index eb2f6cfc1..c096dfcf6 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -60,8 +60,19 @@ #define ENABLE_FIX_PREVIEW_OPTIONS_Z (1 && ENABLE_SEAMS_USING_MODELS && ENABLE_2_4_0_ALPHA2) // Enable replacing a missing file during reload from disk command #define ENABLE_RELOAD_FROM_DISK_REPLACE_FILE (1 && ENABLE_2_4_0_ALPHA2) +// Enable fixing the synchronization of seams with the horizontal slider in preview +#define ENABLE_FIX_SEAMS_SYNCH (1 && ENABLE_2_4_0_ALPHA2) + + +//==================== +// 2.4.0.alpha3 techs +//==================== +#define ENABLE_2_4_0_ALPHA3 1 + +// Enable fixing loading of gcode files generated with SuperSlicer in GCodeViewer +#define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3) // Enable the fix for the detection of the out of bed state for sinking objects -#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA2) +#define ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION (1 && ENABLE_2_4_0_ALPHA3) // Enable detection of out of bed using the bed perimeter and other improvements #define ENABLE_OUT_OF_BED_DETECTION_IMPROVEMENTS (1 && ENABLE_FIX_SINKING_OBJECT_OUT_OF_BED_DETECTION) diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 3427b8cbb..6386591ae 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -191,7 +192,7 @@ bool TriangleMesh::ReadSTLFile(const char* input_file, bool repair) auto facets_w_1_bad_edge = stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge; auto facets_w_2_bad_edge = stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge; auto facets_w_3_bad_edge = stl.stats.number_of_facets - stl.stats.connected_facets_1_edge; - m_stats.open_edges = facets_w_1_bad_edge + facets_w_2_bad_edge * 2 + facets_w_3_bad_edge * 3; + m_stats.open_edges = stl.stats.backwards_edges + facets_w_1_bad_edge + facets_w_2_bad_edge * 2 + facets_w_3_bad_edge * 3; m_stats.edges_fixed = stl.stats.edges_fixed; m_stats.degenerate_facets = stl.stats.degenerate_facets; @@ -532,7 +533,9 @@ TriangleMesh TriangleMesh::convex_hull_3d() const } } - return TriangleMesh { std::move(dst_vertices), std::move(dst_facets) }; + TriangleMesh mesh{ std::move(dst_vertices), std::move(dst_facets) }; + assert(mesh.stats().manifold()); + return mesh; } std::vector TriangleMesh::slice(const std::vector &z) const diff --git a/src/platform/msw/PrusaSlicer-gcodeviewer.rc.in b/src/platform/msw/PrusaSlicer-gcodeviewer.rc.in index eed737cb7..518f6b7b6 100644 --- a/src/platform/msw/PrusaSlicer-gcodeviewer.rc.in +++ b/src/platform/msw/PrusaSlicer-gcodeviewer.rc.in @@ -12,7 +12,7 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@ VALUE "ProductName", "@SLIC3R_APP_NAME@ G-code Viewer" VALUE "ProductVersion", "@SLIC3R_BUILD_ID@" VALUE "InternalName", "@SLIC3R_APP_NAME@ G-code Viewer" - VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranellucci" + VALUE "LegalCopyright", "Copyright \251 2016-2021 Prusa Research, \251 2011-2018 Alessandro Ranellucci" VALUE "OriginalFilename", "prusa-gcodeviewer.exe" } } diff --git a/src/platform/msw/PrusaSlicer.rc.in b/src/platform/msw/PrusaSlicer.rc.in index a4520c6d7..d7f860204 100644 --- a/src/platform/msw/PrusaSlicer.rc.in +++ b/src/platform/msw/PrusaSlicer.rc.in @@ -12,7 +12,7 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@ VALUE "ProductName", "@SLIC3R_APP_NAME@" VALUE "ProductVersion", "@SLIC3R_BUILD_ID@" VALUE "InternalName", "@SLIC3R_APP_NAME@" - VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranellucci" + VALUE "LegalCopyright", "Copyright \251 2016-2021 Prusa Research, \251 2011-2018 Alessandro Ranellucci" VALUE "OriginalFilename", "prusa-slicer.exe" } } diff --git a/src/platform/osx/Info.plist.in b/src/platform/osx/Info.plist.in index 46858bb29..f1de1d24b 100644 --- a/src/platform/osx/Info.plist.in +++ b/src/platform/osx/Info.plist.in @@ -5,7 +5,7 @@ CFBundleExecutable @SLIC3R_APP_KEY@ CFBundleGetInfoString - @SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2020 Prusa Reseach + @SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2021 Prusa Reseach CFBundleIconFile PrusaSlicer.icns CFBundleName diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 2aae9270d..a6b99a08b 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -275,7 +275,7 @@ AboutDialog::AboutDialog() "" "" "" - "%4% © 2016-2020 Prusa Research.
" + "%4% © 2016-2021 Prusa Research.
" "%5% © 2011-2018 Alessandro Ranellucci.
" "Slic3r %6% " "%7%." diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 3f388f485..ee6e3d5ab 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -41,6 +41,7 @@ #include "format.hpp" #include "MsgDialog.hpp" #include "libslic3r/libslic3r.h" +#include "UnsavedChangesDialog.hpp" #if defined(__linux__) && defined(__WXGTK3__) #define wxLinux_gtk3 true @@ -741,10 +742,10 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector* are not compatible with some installed printers."); + wxString first_line = format_wxstr(_L("%1% marked with * are not compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials")); wxString text; if (all_printers) { - wxString second_line = _L("All installed printers are compatible with the selected filament."); + wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material")); text = wxString::Format( "" "