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(
""
"