Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--resources/profiles/Creality.ini1
-rw-r--r--resources/profiles/PrusaResearch.ini12
-rw-r--r--src/libnest2d/CMakeLists.txt2
-rw-r--r--src/libnest2d/include/libnest2d/placers/nfpplacer.hpp8
-rw-r--r--src/libslic3r/Config.hpp18
-rw-r--r--src/libslic3r/ExPolygon.hpp4
-rw-r--r--src/libslic3r/Extruder.hpp3
-rw-r--r--src/libslic3r/ExtrusionEntityCollection.cpp55
-rw-r--r--src/libslic3r/ExtrusionEntityCollection.hpp21
-rw-r--r--src/libslic3r/Flow.cpp4
-rw-r--r--src/libslic3r/Format/3mf.cpp29
-rw-r--r--src/libslic3r/Format/AMF.cpp26
-rw-r--r--src/libslic3r/GCode.cpp983
-rw-r--r--src/libslic3r/GCode.hpp42
-rw-r--r--src/libslic3r/GCode/Analyzer.cpp26
-rw-r--r--src/libslic3r/GCode/CoolingBuffer.cpp4
-rw-r--r--src/libslic3r/GCode/PreviewData.cpp147
-rw-r--r--src/libslic3r/GCode/PreviewData.hpp196
-rw-r--r--src/libslic3r/GCode/PrintExtents.cpp6
-rw-r--r--src/libslic3r/GCode/ToolOrdering.cpp217
-rw-r--r--src/libslic3r/GCode/ToolOrdering.hpp56
-rw-r--r--src/libslic3r/GCodeTimeEstimator.cpp4
-rw-r--r--src/libslic3r/GCodeWriter.cpp13
-rw-r--r--src/libslic3r/GCodeWriter.hpp7
-rw-r--r--src/libslic3r/Model.cpp32
-rw-r--r--src/libslic3r/Model.hpp39
-rw-r--r--src/libslic3r/Print.cpp115
-rw-r--r--src/libslic3r/Print.hpp60
-rw-r--r--src/libslic3r/Slicing.cpp12
-rw-r--r--src/libslic3r/Technologies.hpp18
-rw-r--r--src/libslic3r/libslic3r.h47
-rw-r--r--src/slic3r/GUI/3DBed.cpp18
-rw-r--r--src/slic3r/GUI/3DScene.cpp9
-rw-r--r--src/slic3r/GUI/AppConfig.cpp2
-rw-r--r--src/slic3r/GUI/BackgroundSlicingProcess.cpp8
-rw-r--r--src/slic3r/GUI/BackgroundSlicingProcess.hpp5
-rw-r--r--src/slic3r/GUI/BitmapCache.cpp44
-rw-r--r--src/slic3r/GUI/BitmapCache.hpp2
-rw-r--r--src/slic3r/GUI/ConfigWizard.cpp108
-rw-r--r--src/slic3r/GUI/ConfigWizard_private.hpp13
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp186
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp36
-rw-r--r--src/slic3r/GUI/GLTexture.cpp8
-rw-r--r--src/slic3r/GUI/GLToolbar.hpp2
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp72
-rw-r--r--src/slic3r/GUI/GUI_Preview.hpp3
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoMove.cpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoMove.hpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp2
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoScale.cpp4
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmosManager.cpp10
-rw-r--r--src/slic3r/GUI/Mouse3DController.cpp22
-rw-r--r--src/slic3r/GUI/Mouse3DController.hpp10
-rw-r--r--src/slic3r/GUI/Plater.cpp63
-rw-r--r--src/slic3r/GUI/Plater.hpp2
-rw-r--r--src/slic3r/GUI/Preset.cpp24
-rw-r--r--src/slic3r/GUI/Preset.hpp6
-rw-r--r--src/slic3r/GUI/PresetBundle.cpp2
-rw-r--r--src/slic3r/GUI/wxExtensions.cpp567
-rw-r--r--src/slic3r/GUI/wxExtensions.hpp118
62 files changed, 1943 insertions, 1619 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2bca5a71a..f31c0eac1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,6 +72,9 @@ if (MSVC)
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
# Generate symbols at every build target, even for the release.
add_compile_options(-bigobj -Zm520 /Zi)
+ # Disable STL4007: Many result_type typedefs and all argument_type, first_argument_type, and second_argument_type typedefs are deprecated in C++17.
+ #FIXME Remove this line after eigen library adapts to the new C++17 adaptor rules.
+ add_compile_options(-D_SILENCE_CXX17_ADAPTOR_TYPEDEFS_DEPRECATION_WARNING)
endif ()
if (MINGW)
diff --git a/resources/profiles/Creality.ini b/resources/profiles/Creality.ini
index e9cac0e82..181bb4f4e 100644
--- a/resources/profiles/Creality.ini
+++ b/resources/profiles/Creality.ini
@@ -20,6 +20,7 @@ variants = 0.4
technology = FFF
bed_model = ender3_bed.stl
bed_texture = ender3.svg
+default_materials = Creality PLA @ENDER3; Prusament PLA @ENDER3
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index 96b4369c5..4f5c0482b 100644
--- a/resources/profiles/PrusaResearch.ini
+++ b/resources/profiles/PrusaResearch.ini
@@ -24,6 +24,7 @@ technology = FFF
family = MINI
bed_model = mini_bed.stl
bed_texture = mini.svg
+default_materials = Prusament PLA; Prusament PETG @MINI
[printer_model:MK3S]
name = Original Prusa i3 MK3S
@@ -32,6 +33,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA; Prusament PETG
[printer_model:MK3]
name = Original Prusa i3 MK3
@@ -40,6 +42,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA; Prusament PETG
[printer_model:MK3SMMU2S]
name = Original Prusa i3 MK3S MMU2S
@@ -48,6 +51,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
[printer_model:MK3MMU2]
name = Original Prusa i3 MK3 MMU2
@@ -56,6 +60,7 @@ technology = FFF
family = MK3
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
[printer_model:MK2.5S]
name = Original Prusa i3 MK2.5S
@@ -64,6 +69,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA; Prusament PETG
[printer_model:MK2.5]
name = Original Prusa i3 MK2.5
@@ -72,6 +78,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA; Prusament PETG
[printer_model:MK2.5SMMU2S]
name = Original Prusa i3 MK2.5S MMU2S
@@ -80,6 +87,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
[printer_model:MK2.5MMU2]
name = Original Prusa i3 MK2.5 MMU2
@@ -88,6 +96,7 @@ technology = FFF
family = MK2.5
bed_model = mk3_bed.stl
bed_texture = mk3.svg
+default_materials = Prusament PLA @MMU2; Prusament PETG @MMU2
[printer_model:MK2S]
name = Original Prusa i3 MK2S
@@ -96,6 +105,7 @@ technology = FFF
family = MK2
bed_model = mk2_bed.stl
bed_texture = mk2.svg
+default_materials = Prusament PLA; Prusament PETG
[printer_model:MK2SMM]
name = Original Prusa i3 MK2S MMU1
@@ -104,6 +114,7 @@ technology = FFF
family = MK2
bed_model = mk2_bed.stl
bed_texture = mk2.svg
+default_materials = Prusament PLA; Prusament PETG @MMU1
[printer_model:SL1]
name = Original Prusa SL1
@@ -112,6 +123,7 @@ technology = SLA
family = SL1
bed_model = sl1_bed.stl
bed_texture = sl1.svg
+default_materials = Prusa Transparent Tough @0.05
# All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface.
diff --git a/src/libnest2d/CMakeLists.txt b/src/libnest2d/CMakeLists.txt
index 6484da3d0..592ab069c 100644
--- a/src/libnest2d/CMakeLists.txt
+++ b/src/libnest2d/CMakeLists.txt
@@ -24,7 +24,7 @@ set(LIBNEST2D_SRCFILES
src/libnest2d.cpp
)
-add_library(libnest2d ${LIBNEST2D_SRCFILES})
+add_library(libnest2d STATIC ${LIBNEST2D_SRCFILES})
target_include_directories(libnest2d PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(libnest2d PUBLIC clipper NLopt::nlopt TBB::tbb Boost::boost)
diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
index 003028758..e44e1dae1 100644
--- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
+++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp
@@ -1116,12 +1116,8 @@ private:
for(Item& item : items_) item.translate(d);
}
- void setInitialPosition(Item& item) {
- auto sh = item.rawShape();
- sl::translate(sh, item.translation());
- sl::rotate(sh, item.rotation());
-
- Box bb = sl::boundingBox(sh);
+ void setInitialPosition(Item& item) {
+ Box bb = item.boundingBox();
Vertex ci, cb;
auto bbin = sl::boundingBox(bin_);
diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp
index e7ecc2977..9b04ae026 100644
--- a/src/libslic3r/Config.hpp
+++ b/src/libslic3r/Config.hpp
@@ -500,7 +500,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- std::runtime_error("Deserializing nil into a non-nullable object");
+ throw std::runtime_error("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
double value;
@@ -525,9 +525,9 @@ protected:
if (NULLABLE)
ss << "nil";
else
- std::runtime_error("Serializing NaN");
+ throw std::runtime_error("Serializing NaN");
} else
- std::runtime_error("Serializing invalid number");
+ throw std::runtime_error("Serializing invalid number");
}
static bool vectors_equal(const std::vector<double> &v1, const std::vector<double> &v2) {
if (NULLABLE) {
@@ -646,7 +646,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- std::runtime_error("Deserializing nil into a non-nullable object");
+ throw std::runtime_error("Deserializing nil into a non-nullable object");
} else {
std::istringstream iss(item_str);
int value;
@@ -663,7 +663,7 @@ private:
if (NULLABLE)
ss << "nil";
else
- std::runtime_error("Serializing NaN");
+ throw std::runtime_error("Serializing NaN");
} else
ss << v;
}
@@ -1126,7 +1126,7 @@ public:
if (NULLABLE)
this->values.push_back(nil_value());
else
- std::runtime_error("Deserializing nil into a non-nullable object");
+ throw std::runtime_error("Deserializing nil into a non-nullable object");
} else
this->values.push_back(item_str.compare("1") == 0);
}
@@ -1139,7 +1139,7 @@ protected:
if (NULLABLE)
ss << "nil";
else
- std::runtime_error("Serializing NaN");
+ throw std::runtime_error("Serializing NaN");
} else
ss << (v ? "1" : "0");
}
@@ -1638,7 +1638,7 @@ class DynamicConfig : public virtual ConfigBase
public:
DynamicConfig() {}
DynamicConfig(const DynamicConfig &rhs) { *this = rhs; }
- DynamicConfig(DynamicConfig &&rhs) : options(std::move(rhs.options)) { rhs.options.clear(); }
+ DynamicConfig(DynamicConfig &&rhs) noexcept : options(std::move(rhs.options)) { rhs.options.clear(); }
explicit DynamicConfig(const ConfigBase &rhs, const t_config_option_keys &keys);
explicit DynamicConfig(const ConfigBase& rhs) : DynamicConfig(rhs, rhs.keys()) {}
virtual ~DynamicConfig() override { clear(); }
@@ -1656,7 +1656,7 @@ public:
// Move a content of one DynamicConfig to another DynamicConfig.
// If rhs.def() is not null, then it has to be equal to this->def().
- DynamicConfig& operator=(DynamicConfig &&rhs)
+ DynamicConfig& operator=(DynamicConfig &&rhs) noexcept
{
assert(this->def() == nullptr || this->def() == rhs.def());
this->clear();
diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp
index 4ee8974f4..7c0dfcce5 100644
--- a/src/libslic3r/ExPolygon.hpp
+++ b/src/libslic3r/ExPolygon.hpp
@@ -19,7 +19,7 @@ class ExPolygon
public:
ExPolygon() {}
ExPolygon(const ExPolygon &other) : contour(other.contour), holes(other.holes) {}
- ExPolygon(ExPolygon &&other) : contour(std::move(other.contour)), holes(std::move(other.holes)) {}
+ ExPolygon(ExPolygon &&other) noexcept : contour(std::move(other.contour)), holes(std::move(other.holes)) {}
explicit ExPolygon(const Polygon &contour) : contour(contour) {}
explicit ExPolygon(Polygon &&contour) : contour(std::move(contour)) {}
explicit ExPolygon(const Points &contour) : contour(contour) {}
@@ -32,7 +32,7 @@ public:
ExPolygon(std::initializer_list<Point> contour, std::initializer_list<Point> hole) : contour(contour), holes({ hole }) {}
ExPolygon& operator=(const ExPolygon &other) { contour = other.contour; holes = other.holes; return *this; }
- ExPolygon& operator=(ExPolygon &&other) { contour = std::move(other.contour); holes = std::move(other.holes); return *this; }
+ ExPolygon& operator=(ExPolygon &&other) noexcept { contour = std::move(other.contour); holes = std::move(other.holes); return *this; }
Polygon contour;
Polygons holes;
diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp
index df92bf84b..066a5f56d 100644
--- a/src/libslic3r/Extruder.hpp
+++ b/src/libslic3r/Extruder.hpp
@@ -48,9 +48,6 @@ public:
double retract_length_toolchange() const;
double retract_restart_extra_toolchange() const;
- // Constructor for a key object, to be used by the stdlib search functions.
- static Extruder key(unsigned int id) { return Extruder(id); }
-
private:
// Private constructor to create a key for a search in std::set.
Extruder(unsigned int id) : m_id(id) {}
diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp
index e1a9709d1..147a60d95 100644
--- a/src/libslic3r/ExtrusionEntityCollection.cpp
+++ b/src/libslic3r/ExtrusionEntityCollection.cpp
@@ -6,6 +6,26 @@
namespace Slic3r {
+void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
+{
+ if (role != erMixed) {
+ auto first = extrusion_entities.begin();
+ auto last = extrusion_entities.end();
+ auto result = first;
+ while (first != last) {
+ // The caller wants only paths with a specific extrusion role.
+ auto role2 = (*first)->role();
+ if (role != role2) {
+ // This extrusion entity does not match the role asked.
+ assert(role2 != erMixed);
+ *result = *first;
+ ++ result;
+ }
+ ++ first;
+ }
+ }
+}
+
ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths)
: no_sort(false)
{
@@ -74,31 +94,16 @@ void ExtrusionEntityCollection::remove(size_t i)
this->entities.erase(this->entities.begin() + i);
}
-ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const Point &start_near, ExtrusionRole role) const
-{
- ExtrusionEntityCollection out;
- if (this->no_sort) {
- out = *this;
- } else {
- if (role == erMixed)
- out = *this;
- else {
- for (const ExtrusionEntity *ee : this->entities) {
- if (role != erMixed) {
- // The caller wants only paths with a specific extrusion role.
- auto role2 = ee->role();
- if (role != role2) {
- // This extrusion entity does not match the role asked.
- assert(role2 != erMixed);
- continue;
- }
- }
- out.entities.emplace_back(ee->clone());
- }
- }
- chain_and_reorder_extrusion_entities(out.entities, &start_near);
- }
- return out;
+ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(const ExtrusionEntitiesPtr& extrusion_entities, const Point &start_near, ExtrusionRole role)
+{
+ // Return a filtered copy of the collection.
+ ExtrusionEntityCollection out;
+ out.entities = filter_by_extrusion_role(extrusion_entities, role);
+ // Clone the extrusion entities.
+ for (auto &ptr : out.entities)
+ ptr = ptr->clone();
+ chain_and_reorder_extrusion_entities(out.entities, &start_near);
+ return out;
}
void ExtrusionEntityCollection::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp
index 3084e5741..8aacb4d46 100644
--- a/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -6,6 +6,21 @@
namespace Slic3r {
+// Remove those items from extrusion_entities, that do not match role.
+// Do nothing if role is mixed.
+// Removed elements are NOT being deleted.
+void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role);
+
+// Return new vector of ExtrusionEntities* with only those items from input extrusion_entities, that match role.
+// Return all extrusion entities if role is mixed.
+// Returned extrusion entities are shared with the source vector, they are NOT cloned, they are considered to be owned by extrusion_entities.
+inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
+{
+ ExtrusionEntitiesPtr out { extrusion_entities };
+ filter_by_extrusion_role_in_place(out, role);
+ return out;
+}
+
class ExtrusionEntityCollection : public ExtrusionEntity
{
public:
@@ -65,7 +80,9 @@ public:
}
void replace(size_t i, const ExtrusionEntity &entity);
void remove(size_t i);
- ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const;
+ static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
+ ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const
+ { return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
void reverse();
const Point& first_point() const { return this->entities.front()->first_point(); }
const Point& last_point() const { return this->entities.back()->last_point(); }
@@ -105,6 +122,6 @@ public:
}
};
-}
+} // namespace Slic3r
#endif
diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp
index 6069677a1..2c5c64fe7 100644
--- a/src/libslic3r/Flow.cpp
+++ b/src/libslic3r/Flow.cpp
@@ -107,9 +107,9 @@ double Flow::mm3_per_mm() const
{
float res = this->bridge ?
// Area of a circle with dmr of this->width.
- (this->width * this->width) * 0.25 * PI :
+ float((this->width * this->width) * 0.25 * PI) :
// Rectangle with semicircles at the ends. ~ h (w - 0.215 h)
- this->height * (this->width - this->height * (1. - 0.25 * PI));
+ float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
//assert(res > 0.);
if (res <= 0.)
throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?");
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index cca90b463..14177ed88 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -1088,7 +1088,7 @@ namespace Slic3r {
return;
pt::ptree code_tree = main_tree.front().second;
- m_model->custom_gcode_per_print_z.clear();
+ m_model->custom_gcode_per_print_z.gcodes.clear();
for (const auto& code : code_tree)
{
@@ -1100,7 +1100,7 @@ namespace Slic3r {
int extruder = tree.get<int> ("<xmlattr>.extruder" );
std::string color = tree.get<std::string> ("<xmlattr>.color" );
- m_model->custom_gcode_per_print_z.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
+ m_model->custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{print_z, gcode, extruder, color}) ;
}
}
}
@@ -1717,9 +1717,6 @@ namespace Slic3r {
break;
}
}
-#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
- Transform3d inv_matrix = volume_matrix_to_object.inverse();
-#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// splits volume out of imported geometry
TriangleMesh triangle_mesh;
@@ -1739,15 +1736,7 @@ namespace Slic3r {
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = geometry.triangles[src_start_id + ii + v] * 3;
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
facet.vertex[v] = Vec3f(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
-#else
- Vec3f vertex(geometry.vertices[tri_id + 0], geometry.vertices[tri_id + 1], geometry.vertices[tri_id + 2]);
- facet.vertex[v] = has_transform ?
- // revert the vertices to the original mesh reference system
- (inv_matrix * vertex.cast<double>()).cast<float>() :
- vertex;
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
}
}
@@ -1755,15 +1744,9 @@ namespace Slic3r {
triangle_mesh.repair();
ModelVolume* volume = object.add_volume(std::move(triangle_mesh));
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// stores the volume matrix taken from the metadata, if present
if (has_transform)
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
-#else
- // apply the volume matrix taken from the metadata, if present
- if (has_transform)
- volume->set_transformation(Slic3r::Geometry::Transformation(volume_matrix_to_object));
-#endif //ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
volume->calculate_convex_hull();
// apply the remaining volume's metadata
@@ -2567,11 +2550,7 @@ namespace Slic3r {
// stores volume's local matrix
stream << " <" << METADATA_TAG << " " << TYPE_ATTR << "=\"" << VOLUME_TYPE << "\" " << KEY_ATTR << "=\"" << MATRIX_KEY << "\" " << VALUE_ATTR << "=\"";
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Transform3d matrix = volume->get_matrix() * volume->source.transform.get_matrix();
-#else
- const Transform3d& matrix = volume->get_matrix();
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
for (int r = 0; r < 4; ++r)
{
for (int c = 0; c < 4; ++c)
@@ -2631,12 +2610,12 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
{
std::string out = "";
- if (!model.custom_gcode_per_print_z.empty())
+ if (!model.custom_gcode_per_print_z.gcodes.empty())
{
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_print_z", "");
- for (const Model::CustomGCode& code : model.custom_gcode_per_print_z)
+ for (const Model::CustomGCode& code : model.custom_gcode_per_print_z.gcodes)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 947c04458..7041956ba 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -585,36 +585,20 @@ void AMFParserContext::endElement(const char * /* name */)
stl_allocate(&stl);
bool has_transform = ! m_volume_transform.isApprox(Transform3d::Identity(), 1e-10);
-#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
- Transform3d inv_matrix = m_volume_transform.inverse();
-#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
for (size_t i = 0; i < m_volume_facets.size();) {
stl_facet &facet = stl.facet_start[i/3];
for (unsigned int v = 0; v < 3; ++v)
{
unsigned int tri_id = m_volume_facets[i++] * 3;
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
facet.vertex[v] = Vec3f(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
-#else
- Vec3f vertex(m_object_vertices[tri_id + 0], m_object_vertices[tri_id + 1], m_object_vertices[tri_id + 2]);
- facet.vertex[v] = has_transform ?
- // revert the vertices to the original mesh reference system
- (inv_matrix * vertex.cast<double>()).cast<float>() :
- vertex;
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
}
}
stl_get_size(&stl);
mesh.repair();
m_volume->set_mesh(std::move(mesh));
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
// stores the volume matrix taken from the metadata, if present
if (has_transform)
m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
-#else
- if (has_transform)
- m_volume->set_transformation(m_volume_transform);
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART))
{
m_volume->source.object_idx = (int)m_model.objects.size() - 1;
@@ -653,7 +637,7 @@ void AMFParserContext::endElement(const char * /* name */)
int extruder = atoi(m_value[2].c_str());
const std::string& color = m_value[3];
- m_model.custom_gcode_per_print_z.push_back(Model::CustomGCode{height, gcode, extruder, color});
+ m_model.custom_gcode_per_print_z.gcodes.push_back(Model::CustomGCode{height, gcode, extruder, color});
for (std::string& val: m_value)
val.clear();
@@ -1163,11 +1147,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
stream << " <metadata type=\"slic3r.matrix\">";
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix();
-#else
- const Transform3d& matrix = volume->get_matrix();
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
for (int r = 0; r < 4; ++r)
{
@@ -1250,14 +1230,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
stream << " </constellation>\n";
}
- if (!model->custom_gcode_per_print_z.empty())
+ if (!model->custom_gcode_per_print_z.gcodes.empty())
{
std::string out = "";
pt::ptree tree;
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
- for (const Model::CustomGCode& code : model->custom_gcode_per_print_z)
+ for (const Model::CustomGCode& code : model->custom_gcode_per_print_z.gcodes)
{
pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index 3b2d2ca74..bd22c29e5 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -792,6 +792,297 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
}
+// free functions called by GCode::_do_export()
+namespace DoExport {
+ static void init_time_estimators(const PrintConfig &config, GCodeTimeEstimator &normal_time_estimator, GCodeTimeEstimator &silent_time_estimator, bool &silent_time_estimator_enabled)
+ {
+ // resets time estimators
+ normal_time_estimator.reset();
+ normal_time_estimator.set_dialect(config.gcode_flavor);
+ normal_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
+ silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
+
+ // Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
+ // and let the user to enter the G-code limits into the start G-code.
+ // If the following block is enabled for other firmwares than the Marlin, then the function
+ // this->print_machine_envelope(file, print);
+ // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
+ if (config.gcode_flavor.value == gcfMarlin) {
+ normal_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values[0]);
+ normal_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values[0]);
+ normal_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values[0]);
+ normal_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values[0]);
+ normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values[0]);
+ normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values[0]);
+ normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values[0]);
+ normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values[0]);
+ normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values[0]);
+ normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values[0]);
+ normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values[0]);
+ normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values[0]);
+ normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values[0]);
+ normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values[0]);
+ normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values[0]);
+ normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values[0]);
+
+ if (silent_time_estimator_enabled)
+ {
+ silent_time_estimator.reset();
+ silent_time_estimator.set_dialect(config.gcode_flavor);
+ silent_time_estimator.set_extrusion_axis(config.get_extrusion_axis()[0]);
+ /* "Stealth mode" values can be just a copy of "normal mode" values
+ * (when they aren't input for a printer preset).
+ * Thus, use back value from values, instead of second one, which could be absent
+ */
+ silent_time_estimator.set_max_acceleration((float)config.machine_max_acceleration_extruding.values.back());
+ silent_time_estimator.set_retract_acceleration((float)config.machine_max_acceleration_retracting.values.back());
+ silent_time_estimator.set_minimum_feedrate((float)config.machine_min_extruding_rate.values.back());
+ silent_time_estimator.set_minimum_travel_feedrate((float)config.machine_min_travel_rate.values.back());
+ silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)config.machine_max_acceleration_x.values.back());
+ silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)config.machine_max_acceleration_y.values.back());
+ silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)config.machine_max_acceleration_z.values.back());
+ silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)config.machine_max_acceleration_e.values.back());
+ silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)config.machine_max_feedrate_x.values.back());
+ silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)config.machine_max_feedrate_y.values.back());
+ silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)config.machine_max_feedrate_z.values.back());
+ silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)config.machine_max_feedrate_e.values.back());
+ silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)config.machine_max_jerk_x.values.back());
+ silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)config.machine_max_jerk_y.values.back());
+ silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)config.machine_max_jerk_z.values.back());
+ silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)config.machine_max_jerk_e.values.back());
+ if (config.single_extruder_multi_material) {
+ // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
+ // are considered to be active for the single extruder multi-material printers only.
+ silent_time_estimator.set_filament_load_times(config.filament_load_time.values);
+ silent_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
+ }
+ }
+ }
+ // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
+ if (config.single_extruder_multi_material) {
+ // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
+ // are considered to be active for the single extruder multi-material printers only.
+ normal_time_estimator.set_filament_load_times(config.filament_load_time.values);
+ normal_time_estimator.set_filament_unload_times(config.filament_unload_time.values);
+ }
+ }
+
+ static void init_gcode_analyzer(const PrintConfig &config, GCodeAnalyzer &analyzer)
+ {
+ // resets analyzer
+ analyzer.reset();
+
+ // send extruder offset data to analyzer
+ GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
+ unsigned int num_extruders = static_cast<unsigned int>(config.nozzle_diameter.values.size());
+ for (unsigned int extruder_id = 0; extruder_id < num_extruders; ++ extruder_id)
+ {
+ Vec2d offset = config.extruder_offset.get_at(extruder_id);
+ if (!offset.isApprox(Vec2d::Zero()))
+ extruder_offsets[extruder_id] = offset;
+ }
+ analyzer.set_extruder_offsets(extruder_offsets);
+
+ // tell analyzer about the extrusion axis
+ analyzer.set_extrusion_axis(config.get_extrusion_axis()[0]);
+
+ // send extruders count to analyzer to allow it to detect invalid extruder idxs
+ analyzer.set_extruders_count(num_extruders);
+
+ // tell analyzer about the gcode flavor
+ analyzer.set_gcode_flavor(config.gcode_flavor);
+ }
+
+ static double autospeed_volumetric_limit(const Print &print)
+ {
+ // get the minimum cross-section used in the print
+ std::vector<double> mm3_per_mm;
+ for (auto object : print.objects()) {
+ for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
+ const PrintRegion* region = print.regions()[region_id];
+ for (auto layer : object->layers()) {
+ const LayerRegion* layerm = layer->regions()[region_id];
+ if (region->config().get_abs_value("perimeter_speed") == 0 ||
+ region->config().get_abs_value("small_perimeter_speed") == 0 ||
+ region->config().get_abs_value("external_perimeter_speed") == 0 ||
+ region->config().get_abs_value("bridge_speed") == 0)
+ mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
+ if (region->config().get_abs_value("infill_speed") == 0 ||
+ region->config().get_abs_value("solid_infill_speed") == 0 ||
+ region->config().get_abs_value("top_solid_infill_speed") == 0 ||
+ region->config().get_abs_value("bridge_speed") == 0)
+ mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
+ }
+ }
+ if (object->config().get_abs_value("support_material_speed") == 0 ||
+ object->config().get_abs_value("support_material_interface_speed") == 0)
+ for (auto layer : object->support_layers())
+ mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
+ }
+ // filter out 0-width segments
+ mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
+ double volumetric_speed = 0.;
+ if (! mm3_per_mm.empty()) {
+ // In order to honor max_print_speed we need to find a target volumetric
+ // speed that we can use throughout the print. So we define this target
+ // volumetric speed as the volumetric speed produced by printing the
+ // smallest cross-section at the maximum speed: any larger cross-section
+ // will need slower feedrates.
+ volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value;
+ // limit such volumetric speed with max_volumetric_speed if set
+ if (print.config().max_volumetric_speed.value > 0)
+ volumetric_speed = std::min(volumetric_speed, print.config().max_volumetric_speed.value);
+ }
+ return volumetric_speed;
+ }
+
+ static void init_ooze_prevention(const Print &print, OozePrevention &ooze_prevention)
+ {
+ // Calculate wiping points if needed
+ if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
+ Points skirt_points;
+ for (const ExtrusionEntity *ee : print.skirt().entities)
+ for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
+ append(skirt_points, path.polyline.points);
+ if (! skirt_points.empty()) {
+ Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
+ Polygons skirts;
+ for (unsigned int extruder_id : print.extruders()) {
+ const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
+ Polygon s(outer_skirt);
+ s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
+ skirts.emplace_back(std::move(s));
+ }
+ ooze_prevention.enable = true;
+ ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.));
+ #if 0
+ require "Slic3r/SVG.pm";
+ Slic3r::SVG::output(
+ "ooze_prevention.svg",
+ red_polygons => \@skirts,
+ polygons => [$outer_skirt],
+ points => $gcodegen->ooze_prevention->standby_points,
+ );
+ #endif
+ }
+ }
+ }
+
+ #if ENABLE_THUMBNAIL_GENERATOR
+ template<typename WriteToOutput, typename ThrowIfCanceledCallback>
+ static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<Vec2d> &sizes, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
+ {
+ // Write thumbnails using base64 encoding
+ if (thumbnail_cb != nullptr)
+ {
+ const size_t max_row_length = 78;
+ ThumbnailsList thumbnails;
+ thumbnail_cb(thumbnails, sizes, true, true, true, true);
+ for (const ThumbnailData& data : thumbnails)
+ {
+ if (data.is_valid())
+ {
+ size_t png_size = 0;
+ void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
+ if (png_data != nullptr)
+ {
+ std::string encoded;
+ encoded.resize(boost::beast::detail::base64::encoded_size(png_size));
+ encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size));
+
+ output((boost::format("\n;\n; thumbnail begin %dx%d %d\n") % data.width % data.height % encoded.size()).str().c_str());
+
+ unsigned int row_count = 0;
+ while (encoded.size() > max_row_length)
+ {
+ output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str());
+ encoded = encoded.substr(max_row_length);
+ ++row_count;
+ }
+
+ if (encoded.size() > 0)
+ output((boost::format("; %s\n") % encoded).str().c_str());
+
+ output("; thumbnail end\n;\n");
+
+ mz_free(png_data);
+ }
+ }
+ throw_if_canceled();
+ }
+ }
+ }
+ #endif // ENABLE_THUMBNAIL_GENERATOR
+
+ // Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
+ static std::string update_print_stats_and_format_filament_stats(
+ const GCodeTimeEstimator &normal_time_estimator,
+ const GCodeTimeEstimator &silent_time_estimator,
+ const bool silent_time_estimator_enabled,
+ const bool has_wipe_tower,
+ const WipeTowerData &wipe_tower_data,
+ const std::vector<Extruder> &extruders,
+ PrintStatistics &print_statistics)
+ {
+ std::string filament_stats_string_out;
+
+ print_statistics.clear();
+ print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhms();
+ print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhms() : "N/A";
+ print_statistics.estimated_normal_color_print_times = normal_time_estimator.get_color_times_dhms(true);
+ if (silent_time_estimator_enabled)
+ print_statistics.estimated_silent_color_print_times = silent_time_estimator.get_color_times_dhms(true);
+ print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
+ if (! extruders.empty()) {
+ std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
+ std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
+ std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
+ std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
+ for (const Extruder &extruder : extruders) {
+ double used_filament = extruder.used_filament() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] : 0.f);
+ double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? wipe_tower_data.used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
+ double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
+ double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
+ auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
+ while (dst.second < extruder.id()) {
+ // Fill in the non-printing extruders with zeros.
+ dst.first += (dst.second > 0) ? ", 0" : "0";
+ ++ dst.second;
+ }
+ if (dst.second > 0)
+ dst.first += ", ";
+ char buf[64];
+ sprintf(buf, tmpl, value);
+ dst.first += buf;
+ ++ dst.second;
+ };
+ print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
+ append(out_filament_used_mm, "%.1lf", used_filament);
+ append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
+ if (filament_weight > 0.) {
+ print_statistics.total_weight = print_statistics.total_weight + filament_weight;
+ append(out_filament_used_g, "%.1lf", filament_weight);
+ if (filament_cost > 0.) {
+ print_statistics.total_cost = print_statistics.total_cost + filament_cost;
+ append(out_filament_cost, "%.1lf", filament_cost);
+ }
+ }
+ print_statistics.total_used_filament += used_filament;
+ print_statistics.total_extruded_volume += extruded_volume;
+ print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
+ print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
+ }
+ filament_stats_string_out += out_filament_used_mm.first;
+ filament_stats_string_out += out_filament_used_cm3.first;
+ if (out_filament_used_g.second)
+ filament_stats_string_out += out_filament_used_g.first;
+ if (out_filament_cost.second)
+ filament_stats_string_out += out_filament_cost.first;
+ }
+ return filament_stats_string_out;
+ }
+}
+
#if ENABLE_THUMBNAIL_GENERATOR
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
#else
@@ -800,99 +1091,10 @@ void GCode::_do_export(Print& print, FILE* file)
{
PROFILE_FUNC();
- // resets time estimators
- m_normal_time_estimator.reset();
- m_normal_time_estimator.set_dialect(print.config().gcode_flavor);
- m_normal_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
- m_silent_time_estimator_enabled = (print.config().gcode_flavor == gcfMarlin) && print.config().silent_mode;
-
- // Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
- // and let the user to enter the G-code limits into the start G-code.
- // If the following block is enabled for other firmwares than the Marlin, then the function
- // this->print_machine_envelope(file, print);
- // shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
- if (print.config().gcode_flavor.value == gcfMarlin) {
- m_normal_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values[0]);
- m_normal_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values[0]);
- m_normal_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values[0]);
- m_normal_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values[0]);
- m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values[0]);
- m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values[0]);
- m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values[0]);
- m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values[0]);
- m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values[0]);
- m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values[0]);
- m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values[0]);
- m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values[0]);
- m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values[0]);
- m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values[0]);
- m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values[0]);
- m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values[0]);
-
- if (m_silent_time_estimator_enabled)
- {
- m_silent_time_estimator.reset();
- m_silent_time_estimator.set_dialect(print.config().gcode_flavor);
- m_silent_time_estimator.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
- /* "Stealth mode" values can be just a copy of "normal mode" values
- * (when they aren't input for a printer preset).
- * Thus, use back value from values, instead of second one, which could be absent
- */
- m_silent_time_estimator.set_max_acceleration((float)print.config().machine_max_acceleration_extruding.values.back());
- m_silent_time_estimator.set_retract_acceleration((float)print.config().machine_max_acceleration_retracting.values.back());
- m_silent_time_estimator.set_minimum_feedrate((float)print.config().machine_min_extruding_rate.values.back());
- m_silent_time_estimator.set_minimum_travel_feedrate((float)print.config().machine_min_travel_rate.values.back());
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, (float)print.config().machine_max_acceleration_x.values.back());
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, (float)print.config().machine_max_acceleration_y.values.back());
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, (float)print.config().machine_max_acceleration_z.values.back());
- m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, (float)print.config().machine_max_acceleration_e.values.back());
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, (float)print.config().machine_max_feedrate_x.values.back());
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, (float)print.config().machine_max_feedrate_y.values.back());
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, (float)print.config().machine_max_feedrate_z.values.back());
- m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, (float)print.config().machine_max_feedrate_e.values.back());
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, (float)print.config().machine_max_jerk_x.values.back());
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, (float)print.config().machine_max_jerk_y.values.back());
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, (float)print.config().machine_max_jerk_z.values.back());
- m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, (float)print.config().machine_max_jerk_e.values.back());
- if (print.config().single_extruder_multi_material) {
- // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
- // are considered to be active for the single extruder multi-material printers only.
- m_silent_time_estimator.set_filament_load_times(print.config().filament_load_time.values);
- m_silent_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values);
- }
- }
- }
- // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
- if (print.config().single_extruder_multi_material) {
- // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
- // are considered to be active for the single extruder multi-material printers only.
- m_normal_time_estimator.set_filament_load_times(print.config().filament_load_time.values);
- m_normal_time_estimator.set_filament_unload_times(print.config().filament_unload_time.values);
- }
-
- // resets analyzer
- m_analyzer.reset();
-
- // send extruder offset data to analyzer
- GCodeAnalyzer::ExtruderOffsetsMap extruder_offsets;
- for (unsigned int extruder_id : print.extruders())
- {
- Vec2d offset = print.config().extruder_offset.get_at(extruder_id);
- if (!offset.isApprox(Vec2d::Zero()))
- extruder_offsets[extruder_id] = offset;
- }
- m_analyzer.set_extruder_offsets(extruder_offsets);
-
- // tell analyzer about the extrusion axis
- m_analyzer.set_extrusion_axis(print.config().get_extrusion_axis()[0]);
-
- // send extruders count to analyzer to allow it to detect invalid extruder idxs
- const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(print.config().option("extruder_colour"));
- const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(print.config().option("filament_colour"));
- m_analyzer.set_extruders_count(std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size()));
-
- // tell analyzer about the gcode flavor
- m_analyzer.set_gcode_flavor(print.config().gcode_flavor);
+ DoExport::init_time_estimators(print.config(),
+ // modifies the following:
+ m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled);
+ DoExport::init_gcode_analyzer(print.config(), m_analyzer);
// resets analyzer's tracking data
m_last_mm3_per_mm = GCodeAnalyzer::Default_mm3_per_mm;
@@ -914,8 +1116,7 @@ void GCode::_do_export(Print& print, FILE* file)
std::sort(zs.begin(), zs.end());
m_layer_count += (unsigned int)(object->copies().size() * (std::unique(zs.begin(), zs.end()) - zs.begin()));
}
- }
- else {
+ } else {
// Print all objects with the same print_z together.
std::vector<coordf_t> zs;
for (auto object : print.objects()) {
@@ -932,53 +1133,8 @@ void GCode::_do_export(Print& print, FILE* file)
m_enable_cooling_markers = true;
this->apply_print_config(print.config());
- this->set_extruders(print.extruders());
-
- // Initialize custom gcode
- Model* model = print.get_object(0)->model_object()->get_model();
- m_custom_gcode_per_print_z = model->custom_gcode_per_print_z;
- // Initialize autospeed.
- {
- // get the minimum cross-section used in the print
- std::vector<double> mm3_per_mm;
- for (auto object : print.objects()) {
- for (size_t region_id = 0; region_id < object->region_volumes.size(); ++region_id) {
- const PrintRegion* region = print.regions()[region_id];
- for (auto layer : object->layers()) {
- const LayerRegion* layerm = layer->regions()[region_id];
- if (region->config().get_abs_value("perimeter_speed") == 0 ||
- region->config().get_abs_value("small_perimeter_speed") == 0 ||
- region->config().get_abs_value("external_perimeter_speed") == 0 ||
- region->config().get_abs_value("bridge_speed") == 0)
- mm3_per_mm.push_back(layerm->perimeters.min_mm3_per_mm());
- if (region->config().get_abs_value("infill_speed") == 0 ||
- region->config().get_abs_value("solid_infill_speed") == 0 ||
- region->config().get_abs_value("top_solid_infill_speed") == 0 ||
- region->config().get_abs_value("bridge_speed") == 0)
- mm3_per_mm.push_back(layerm->fills.min_mm3_per_mm());
- }
- }
- if (object->config().get_abs_value("support_material_speed") == 0 ||
- object->config().get_abs_value("support_material_interface_speed") == 0)
- for (auto layer : object->support_layers())
- mm3_per_mm.push_back(layer->support_fills.min_mm3_per_mm());
- }
- print.throw_if_canceled();
- // filter out 0-width segments
- mm3_per_mm.erase(std::remove_if(mm3_per_mm.begin(), mm3_per_mm.end(), [](double v) { return v < 0.000001; }), mm3_per_mm.end());
- if (!mm3_per_mm.empty()) {
- // In order to honor max_print_speed we need to find a target volumetric
- // speed that we can use throughout the print. So we define this target
- // volumetric speed as the volumetric speed produced by printing the
- // smallest cross-section at the maximum speed: any larger cross-section
- // will need slower feedrates.
- m_volumetric_speed = *std::min_element(mm3_per_mm.begin(), mm3_per_mm.end()) * print.config().max_print_speed.value;
- // limit such volumetric speed with max_volumetric_speed if set
- if (print.config().max_volumetric_speed.value > 0)
- m_volumetric_speed = std::min(m_volumetric_speed, print.config().max_volumetric_speed.value);
- }
- }
+ m_volumetric_speed = DoExport::autospeed_volumetric_limit(print);
print.throw_if_canceled();
m_cooling_buffer = make_unique<CoolingBuffer>(*this);
@@ -996,47 +1152,9 @@ void GCode::_do_export(Print& print, FILE* file)
// Write information on the generator.
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
-#if ENABLE_THUMBNAIL_GENERATOR
- // Write thumbnails using base64 encoding
- if (thumbnail_cb != nullptr)
- {
- const size_t max_row_length = 78;
- ThumbnailsList thumbnails;
- thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
- for (const ThumbnailData& data : thumbnails)
- {
- if (data.is_valid())
- {
- size_t png_size = 0;
- void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
- if (png_data != nullptr)
- {
- std::string encoded;
- encoded.resize(boost::beast::detail::base64::encoded_size(png_size));
- encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size));
-
- _write_format(file, "\n;\n; thumbnail begin %dx%d %d\n", data.width, data.height, encoded.size());
-
- unsigned int row_count = 0;
- while (encoded.size() > max_row_length)
- {
- _write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
- encoded = encoded.substr(max_row_length);
- ++row_count;
- }
-
- if (encoded.size() > 0)
- _write_format(file, "; %s\n", encoded.c_str());
-
- _write(file, "; thumbnail end\n;\n");
-
- mz_free(png_data);
- }
- }
- print.throw_if_canceled();
- }
- }
-#endif // ENABLE_THUMBNAIL_GENERATOR
+ DoExport::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values,
+ [this, file](const char* sz) { this->_write(file, sz); },
+ [&print]() { print.throw_if_canceled(); });
// Write notes (content of the Print Settings tab -> Notes)
{
@@ -1079,9 +1197,6 @@ void GCode::_do_export(Print& print, FILE* file)
_writeln(file, GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag);
}
- // Hold total number of print toolchanges. Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
- int total_toolchanges = std::max(0, print.wipe_tower_data().number_of_toolchanges);
-
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser = print.placeholder_parser();
m_placeholder_parser.update_timestamp();
@@ -1101,18 +1216,23 @@ void GCode::_do_export(Print& print, FILE* file)
if ((initial_extruder_id = tool_ordering.first_extruder()) != (unsigned int)-1)
break;
}
+ // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
+ // Use the extruder IDs collected from Regions.
+ this->set_extruders(print.extruders());
} else {
// Find tool ordering for all the objects at once, and the initial extruder ID.
// If the tool ordering has been pre-calculated by Print class for wipe tower already, reuse it.
- tool_ordering = print.wipe_tower_data().tool_ordering.empty() ?
- ToolOrdering(print, initial_extruder_id) :
- print.wipe_tower_data().tool_ordering;
+ tool_ordering = print.tool_ordering();
+ tool_ordering.assign_custom_gcodes(print);
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
- initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
+ initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
// The priming towers will be skipped.
tool_ordering.all_extruders().back() :
- // Don't skip the priming towers.
+ // Don't skip the priming towers.
tool_ordering.first_extruder();
+ // In non-sequential print, the printing extruders may have been modified by the extruder switches stored in Model::custom_gcode_per_print_z.
+ // Therefore initialize the printing extruders from there.
+ this->set_extruders(tool_ordering.all_extruders());
}
if (initial_extruder_id == (unsigned int)-1) {
// Nothing to print!
@@ -1124,49 +1244,6 @@ void GCode::_do_export(Print& print, FILE* file)
}
print.throw_if_canceled();
-// #ys_FIXME_no_exported_codes
- /*
- /* To avoid change filament for non-used extruder for Multi-material,
- * check model->custom_gcode_per_print_z using tool_ordering values
- * /
- if (!m_custom_gcode_per_print_z. empty())
- {
- bool delete_executed = false;
- auto it = m_custom_gcode_per_print_z.end();
- while (it != m_custom_gcode_per_print_z.begin())
- {
- --it;
- if (it->gcode != ColorChangeCode)
- continue;
-
- auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), LayerTools(it->print_z));
-
- bool used_extruder = false;
- for (; it_layer_tools != tool_ordering.end(); it_layer_tools++)
- {
- const std::vector<unsigned>& extruders = it_layer_tools->extruders;
- if (std::find(extruders.begin(), extruders.end(), (unsigned)(it->extruder-1)) != extruders.end())
- {
- used_extruder = true;
- break;
- }
- }
- if (used_extruder)
- continue;
-
- /* If we are there, current extruder wouldn't be used,
- * so this color change is a redundant move.
- * Delete this item from m_custom_gcode_per_print_z
- * /
- it = m_custom_gcode_per_print_z.erase(it);
- delete_executed = true;
- }
-
- if (delete_executed)
- model->custom_gcode_per_print_z = m_custom_gcode_per_print_z;
- }
-*/
-
m_cooling_buffer->set_current_extruder(initial_extruder_id);
// Emit machine envelope limits for the Marlin firmware.
@@ -1187,7 +1264,8 @@ void GCode::_do_export(Print& print, FILE* file)
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
- m_placeholder_parser.set("total_toolchanges", total_toolchanges);
+ m_placeholder_parser.set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
+
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
// Set bed temperature if the start G-code does not contain any bed temp control G-codes.
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
@@ -1195,12 +1273,8 @@ void GCode::_do_export(Print& print, FILE* file)
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
if (m_enable_analyzer)
- {
// adds tag for analyzer
- char buf[32];
- sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
- _writeln(file, buf);
- }
+ _write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
// Write the custom start G-code
_writeln(file, start_gcode);
@@ -1228,35 +1302,8 @@ void GCode::_do_export(Print& print, FILE* file)
}
// Calculate wiping points if needed
- if (print.config().ooze_prevention.value && ! print.config().single_extruder_multi_material) {
- Points skirt_points;
- for (const ExtrusionEntity *ee : print.skirt().entities)
- for (const ExtrusionPath &path : dynamic_cast<const ExtrusionLoop*>(ee)->paths)
- append(skirt_points, path.polyline.points);
- if (! skirt_points.empty()) {
- Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
- Polygons skirts;
- for (unsigned int extruder_id : print.extruders()) {
- const Vec2d &extruder_offset = print.config().extruder_offset.get_at(extruder_id);
- Polygon s(outer_skirt);
- s.translate(Point::new_scale(-extruder_offset(0), -extruder_offset(1)));
- skirts.emplace_back(std::move(s));
- }
- m_ooze_prevention.enable = true;
- m_ooze_prevention.standby_points =
- offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.));
-#if 0
- require "Slic3r/SVG.pm";
- Slic3r::SVG::output(
- "ooze_prevention.svg",
- red_polygons => \@skirts,
- polygons => [$outer_skirt],
- points => $gcodegen->ooze_prevention->standby_points,
- );
-#endif
- }
- print.throw_if_canceled();
- }
+ DoExport::init_ooze_prevention(print, m_ooze_prevention);
+ print.throw_if_canceled();
if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming)) {
// Set initial extruder only after custom start G-code.
@@ -1387,12 +1434,8 @@ void GCode::_do_export(Print& print, FILE* file)
_write(file, m_writer.set_fan(false));
if (m_enable_analyzer)
- {
// adds tag for analyzer
- char buf[32];
- sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
- _writeln(file, buf);
- }
+ _write_format(file, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom);
// Process filament-specific gcode in extruder order.
{
@@ -1432,60 +1475,13 @@ void GCode::_do_export(Print& print, FILE* file)
m_silent_time_estimator.calculate_time(false);
// Get filament stats.
- print.m_print_statistics.clear();
- print.m_print_statistics.estimated_normal_print_time = m_normal_time_estimator.get_time_dhms();
- print.m_print_statistics.estimated_silent_print_time = m_silent_time_estimator_enabled ? m_silent_time_estimator.get_time_dhms() : "N/A";
- print.m_print_statistics.estimated_normal_color_print_times = m_normal_time_estimator.get_color_times_dhms(true);
- if (m_silent_time_estimator_enabled)
- print.m_print_statistics.estimated_silent_color_print_times = m_silent_time_estimator.get_color_times_dhms(true);
- print.m_print_statistics.total_toolchanges = total_toolchanges;
- std::vector<Extruder> extruders = m_writer.extruders();
- if (! extruders.empty()) {
- std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
- std::pair<std::string, unsigned int> out_filament_used_cm3("; filament used [cm3] = ", 0);
- std::pair<std::string, unsigned int> out_filament_used_g ("; filament used [g] = ", 0);
- std::pair<std::string, unsigned int> out_filament_cost ("; filament cost = ", 0);
- for (const Extruder &extruder : extruders) {
- double used_filament = extruder.used_filament() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] : 0.f);
- double extruded_volume = extruder.extruded_volume() + (has_wipe_tower ? print.wipe_tower_data().used_filament[extruder.id()] * 2.4052f : 0.f); // assumes 1.75mm filament diameter
- double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
- double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
- auto append = [&extruder, &extruders](std::pair<std::string, unsigned int> &dst, const char *tmpl, double value) {
- while (dst.second < extruder.id()) {
- // Fill in the non-printing extruders with zeros.
- dst.first += (dst.second > 0) ? ", 0" : "0";
- ++ dst.second;
- }
- if (dst.second > 0)
- dst.first += ", ";
- char buf[64];
- sprintf(buf, tmpl, value);
- dst.first += buf;
- ++ dst.second;
- };
- print.m_print_statistics.filament_stats.insert(std::pair<size_t, float>{extruder.id(), (float)used_filament});
- append(out_filament_used_mm, "%.1lf", used_filament);
- append(out_filament_used_cm3, "%.1lf", extruded_volume * 0.001);
- if (filament_weight > 0.) {
- print.m_print_statistics.total_weight = print.m_print_statistics.total_weight + filament_weight;
- append(out_filament_used_g, "%.1lf", filament_weight);
- if (filament_cost > 0.) {
- print.m_print_statistics.total_cost = print.m_print_statistics.total_cost + filament_cost;
- append(out_filament_cost, "%.1lf", filament_cost);
- }
- }
- print.m_print_statistics.total_used_filament += used_filament;
- print.m_print_statistics.total_extruded_volume += extruded_volume;
- print.m_print_statistics.total_wipe_tower_filament += has_wipe_tower ? used_filament - extruder.used_filament() : 0.;
- print.m_print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
- }
- _writeln(file, out_filament_used_mm.first);
- _writeln(file, out_filament_used_cm3.first);
- if (out_filament_used_g.second)
- _writeln(file, out_filament_used_g.first);
- if (out_filament_cost.second)
- _writeln(file, out_filament_cost.first);
- }
+ _write(file, DoExport::update_print_stats_and_format_filament_stats(
+ // Const inputs
+ m_normal_time_estimator, m_silent_time_estimator, m_silent_time_estimator_enabled,
+ has_wipe_tower, print.wipe_tower_data(),
+ m_writer.extruders(),
+ // Modifies
+ print.m_print_statistics));
_write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight);
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
if (print.m_print_statistics.total_toolchanges > 0)
@@ -1729,6 +1725,136 @@ std::vector<GCode::InstanceToPrint> GCode::sort_print_object_instances(
return out;
}
+namespace ProcessLayer
+{
+
+ static std::string emit_custom_gcode_per_print_z(
+ const Model::CustomGCode *custom_gcode,
+ // ID of the first extruder printing this layer.
+ unsigned int first_extruder_id,
+ bool single_material_print)
+ {
+ std::string gcode;
+
+ if (custom_gcode != nullptr) {
+ // Extruder switches are processed by LayerTools, they should be filtered out.
+ assert(custom_gcode->gcode != ToolChangeCode);
+
+ const std::string &custom_code = custom_gcode->gcode;
+ std::string pause_print_msg;
+ int m600_extruder_before_layer = -1;
+ if (custom_code == ColorChangeCode && custom_gcode->extruder > 0)
+ m600_extruder_before_layer = custom_gcode->extruder - 1;
+ else if (custom_code == PausePrintCode)
+ pause_print_msg = custom_gcode->color;
+
+ // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
+ if (custom_code == ColorChangeCode) // color change
+ {
+ // add tag for analyzer
+ gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n";
+ // add tag for time estimator
+ gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
+
+ if (!single_material_print && m600_extruder_before_layer >= 0 && first_extruder_id != m600_extruder_before_layer
+ // && !MMU1
+ ) {
+ //! FIXME_in_fw show message during print pause
+ gcode += "M601\n"; // pause print
+ gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
+ }
+ else
+ gcode += custom_code + "\n";
+ }
+ else
+ {
+ if (custom_code == PausePrintCode) // Pause print
+ {
+ // add tag for analyzer
+ gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
+ //! FIXME_in_fw show message during print pause
+ if (!pause_print_msg.empty())
+ gcode += "M117 " + pause_print_msg + "\n";
+ // add tag for time estimator
+ //gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
+ }
+ else // custom Gcode
+ {
+ // add tag for analyzer
+ gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
+ // add tag for time estimator
+ //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
+ }
+ gcode += custom_code + "\n";
+ }
+ }
+
+ return gcode;
+ }
+} // namespace ProcessLayer
+
+namespace Skirt {
+ static void skirt_loops_per_extruder_all_printing(const Print &print, const LayerTools &layer_tools, std::map<unsigned int, std::pair<size_t, size_t>> &skirt_loops_per_extruder_out)
+ {
+ // Prime all extruders printing over the 1st layer over the skirt lines.
+ size_t n_loops = print.skirt().entities.size();
+ size_t n_tools = layer_tools.extruders.size();
+ size_t lines_per_extruder = (n_loops + n_tools - 1) / n_tools;
+ for (size_t i = 0; i < n_loops; i += lines_per_extruder)
+ skirt_loops_per_extruder_out[layer_tools.extruders[i / lines_per_extruder]] = std::pair<size_t, size_t>(i, std::min(i + lines_per_extruder, n_loops));
+ }
+
+ static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_1st_layer(
+ const Print &print,
+ const std::vector<GCode::LayerToPrint> & /*layers */,
+ const LayerTools &layer_tools,
+ // Heights (print_z) at which the skirt has already been extruded.
+ std::vector<coordf_t> &skirt_done)
+ {
+ // Extrude skirt at the print_z of the raft layers and normal object layers
+ // not at the print_z of the interlaced support material layers.
+ std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
+ if (skirt_done.empty() && print.has_skirt() && ! print.skirt().entities.empty()) {
+ skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
+ skirt_done.emplace_back(layer_tools.print_z);
+ }
+ return skirt_loops_per_extruder_out;
+ }
+
+ static std::map<unsigned int, std::pair<size_t, size_t>> make_skirt_loops_per_extruder_other_layers(
+ const Print &print,
+ const std::vector<GCode::LayerToPrint> &layers,
+ const LayerTools &layer_tools,
+ // Heights (print_z) at which the skirt has already been extruded.
+ std::vector<coordf_t> &skirt_done)
+ {
+ // Extrude skirt at the print_z of the raft layers and normal object layers
+ // not at the print_z of the interlaced support material layers.
+ std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder_out;
+ if (print.has_skirt() && ! print.skirt().entities.empty() &&
+ // Not enough skirt layers printed yet.
+ //FIXME infinite or high skirt does not make sense for sequential print!
+ (skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
+ // This print_z has not been extruded yet (sequential print)
+ skirt_done.back() < layer_tools.print_z - EPSILON &&
+ // and this layer is an object layer, or it is a raft layer.
+ (layer_tools.has_object || layers.front().support_layer->id() < (size_t)layers.front().support_layer->object()->config().raft_layers.value)) {
+#if 0
+ // Prime just the first printing extruder. This is original Slic3r's implementation.
+ skirt_loops_per_extruder_out[layer_tools.extruders.front()] = std::pair<size_t, size_t>(0, print.config().skirts.value);
+#else
+ // Prime all extruders planned for this layer, see
+ // https://github.com/prusa3d/PrusaSlicer/issues/469#issuecomment-322450619
+ skirt_loops_per_extruder_all_printing(print, layer_tools, skirt_loops_per_extruder_out);
+#endif
+ assert(!skirt_done.empty());
+ skirt_done.emplace_back(layer_tools.print_z);
+ }
+ return skirt_loops_per_extruder_out;
+ }
+
+} // namespace Skirt
+
// In sequential mode, process_layer is called once per each object and its copy,
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
@@ -1765,7 +1891,7 @@ void GCode::process_layer(
if (l.support_layer != nullptr && support_layer == nullptr)
support_layer = l.support_layer;
}
- const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
+ const Layer &layer = (object_layer != nullptr) ? *object_layer : *support_layer;
coordf_t print_z = layer.print_z;
bool first_layer = layer.id() == 0;
unsigned int first_extruder_id = layer_tools.extruders.front();
@@ -1829,121 +1955,18 @@ void GCode::process_layer(
m_second_layer_things_done = true;
}
- // Let's issue a filament change command if requested at this layer.
- // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all.
- // (Layers can be close to each other, model could have been resliced with bigger layer height, ...).
- bool colorprint_change = false;
-
- std::string custom_code = "";
- std::string pause_print_msg = "";
- int m600_before_extruder = -1;
- while (!m_custom_gcode_per_print_z.empty() && m_custom_gcode_per_print_z.front().print_z - EPSILON < layer.print_z) {
- custom_code = m_custom_gcode_per_print_z.front().gcode;
-
- if (custom_code == ColorChangeCode && m_custom_gcode_per_print_z.front().extruder > 0)
- m600_before_extruder = m_custom_gcode_per_print_z.front().extruder - 1;
- if (custom_code == PausePrintCode)
- pause_print_msg = m_custom_gcode_per_print_z.front().color;
-
- m_custom_gcode_per_print_z.erase(m_custom_gcode_per_print_z.begin());
- colorprint_change = true;
- }
-
- // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
+ // Map from extruder ID to <begin, end> index of skirt loops to be extruded with that extruder.
+ std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
- // don't save "tool_change"(ExtruderChangeCode) code to GCode
- if (colorprint_change && custom_code != ExtruderChangeCode) {
- const bool single_material_print = print.config().nozzle_diameter.size() == 1;
-
- if (custom_code == ColorChangeCode) // color change
- {
- // add tag for analyzer
- gcode += "; " + GCodeAnalyzer::Color_Change_Tag + ",T" + std::to_string(m600_before_extruder) + "\n";
- // add tag for time estimator
- gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n";
-
- if (!single_material_print && m600_before_extruder >= 0 && first_extruder_id != m600_before_extruder
- // && !MMU1
- ) {
- //! FIXME_in_fw show message during print pause
- gcode += "M601\n"; // pause print
- gcode += "M117 Change filament for Extruder " + std::to_string(m600_before_extruder) + "\n";
- }
- else
- gcode += custom_code + "\n";
- }
- else
- {
- if (custom_code == PausePrintCode) // Pause print
- {
- // add tag for analyzer
- gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
- //! FIXME_in_fw show message during print pause
- if (!pause_print_msg.empty())
- gcode += "M117 " + pause_print_msg + "\n";
- // add tag for time estimator
- //gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
- }
- else // custom Gcode
- {
- // add tag for analyzer
- gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
- // add tag for time estimator
- //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
- }
- gcode += custom_code + "\n";
- }
+ if (single_object_instance_idx == size_t(-1)) {
+ // Normal (non-sequential) print.
+ gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config().nozzle_diameter.size() == 1);
}
-
-
// Extrude skirt at the print_z of the raft layers and normal object layers
// not at the print_z of the interlaced support material layers.
- bool extrude_skirt =
- ! print.skirt().entities.empty() &&
- // Not enough skirt layers printed yet.
- (m_skirt_done.size() < (size_t)print.config().skirt_height.value || print.has_infinite_skirt()) &&
- // This print_z has not been extruded yet
- (m_skirt_done.empty() ? 0. : m_skirt_done.back()) < print_z - EPSILON &&
- // and this layer is the 1st layer, or it is an object layer, or it is a raft layer.
- (first_layer || object_layer != nullptr || support_layer->id() < (size_t)m_config.raft_layers.value);
- std::map<unsigned int, std::pair<size_t, size_t>> skirt_loops_per_extruder;
- coordf_t skirt_height = 0.;
- if (extrude_skirt) {
- // Fill in skirt_loops_per_extruder.
- skirt_height = print_z - (m_skirt_done.empty() ? 0. : m_skirt_done.back());
- m_skirt_done.push_back(print_z);
- if (first_layer) {
- // Prime the extruders over the skirt lines.
- std::vector<unsigned int> extruder_ids = m_writer.extruder_ids();
- // Reorder the extruders, so that the last used extruder is at the front.
- for (size_t i = 1; i < extruder_ids.size(); ++ i)
- if (extruder_ids[i] == first_extruder_id) {
- // Move the last extruder to the front.
- memmove(extruder_ids.data() + 1, extruder_ids.data(), i * sizeof(unsigned int));
- extruder_ids.front() = first_extruder_id;
- break;
- }
- size_t n_loops = print.skirt().entities.size();
- if (n_loops <= extruder_ids.size()) {
- for (size_t i = 0; i < n_loops; ++i)
- skirt_loops_per_extruder[extruder_ids[i]] = std::pair<size_t, size_t>(i, i + 1);
- } else {
- // Assign skirt loops to the extruders.
- std::vector<unsigned int> extruder_loops(extruder_ids.size(), 1);
- n_loops -= extruder_loops.size();
- while (n_loops > 0) {
- for (size_t i = 0; i < extruder_ids.size() && n_loops > 0; ++ i, -- n_loops)
- ++ extruder_loops[i];
- }
- for (size_t i = 0; i < extruder_ids.size(); ++ i)
- skirt_loops_per_extruder[extruder_ids[i]] = std::make_pair<size_t, size_t>(
- (i == 0) ? 0 : extruder_loops[i - 1],
- ((i == 0) ? 0 : extruder_loops[i - 1]) + extruder_loops[i]);
- }
- } else
- // Extrude all skirts with the current extruder.
- skirt_loops_per_extruder[first_extruder_id] = std::pair<size_t, size_t>(0, print.config().skirts.value);
- }
+ skirt_loops_per_extruder = first_layer ?
+ Skirt::make_skirt_loops_per_extruder_1st_layer(print, layers, layer_tools, m_skirt_done) :
+ Skirt::make_skirt_loops_per_extruder_other_layers(print, layers, layer_tools, m_skirt_done);
// Group extrusions by an extruder, then by an object, an island and a region.
std::map<unsigned int, std::vector<ObjectByExtruder>> by_extruder;
@@ -2015,7 +2038,7 @@ void GCode::process_layer(
slices_test_order.reserve(n_slices);
for (size_t i = 0; i < n_slices; ++ i)
slices_test_order.emplace_back(i);
- std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](int i, int j) {
+ std::sort(slices_test_order.begin(), slices_test_order.end(), [&layer_surface_bboxes](size_t i, size_t j) {
const Vec2d s1 = layer_surface_bboxes[i].size().cast<double>();
const Vec2d s2 = layer_surface_bboxes[j].size().cast<double>();
return s1.x() * s1.y() < s2.x() * s2.y();
@@ -2046,7 +2069,7 @@ void GCode::process_layer(
continue;
// This extrusion is part of certain Region, which tells us which extruder should be used for it:
- int correct_extruder_id = Print::get_extruder(*extrusions, region);
+ int correct_extruder_id = layer_tools.extruder(*extrusions, region);
// Let's recover vector of extruder overrides:
const WipingExtrusions::ExtruderPerCopy *entity_overrides = nullptr;
@@ -2113,30 +2136,27 @@ void GCode::process_layer(
if (m_enable_analyzer && layer_tools.has_wipe_tower && m_wipe_tower)
m_last_analyzer_extrusion_role = erWipeTower;
- if (extrude_skirt) {
- auto loops_it = skirt_loops_per_extruder.find(extruder_id);
- if (loops_it != skirt_loops_per_extruder.end()) {
- const std::pair<size_t, size_t> loops = loops_it->second;
- this->set_origin(0.,0.);
- m_avoid_crossing_perimeters.use_external_mp = true;
- Flow skirt_flow = print.skirt_flow();
- for (size_t i = loops.first; i < loops.second; ++ i) {
- // Adjust flow according to this layer's layer height.
- ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
- Flow layer_skirt_flow(skirt_flow);
- layer_skirt_flow.height = (float)skirt_height;
- double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
- for (ExtrusionPath &path : loop.paths) {
- path.height = (float)layer.height;
- path.mm3_per_mm = mm3_per_mm;
- }
- gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value);
+ if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
+ const std::pair<size_t, size_t> loops = loops_it->second;
+ this->set_origin(0., 0.);
+ m_avoid_crossing_perimeters.use_external_mp = true;
+ Flow layer_skirt_flow(print.skirt_flow());
+ layer_skirt_flow.height = float(m_skirt_done.back() - (m_skirt_done.size() == 1 ? 0. : m_skirt_done[m_skirt_done.size() - 2]));
+ double mm3_per_mm = layer_skirt_flow.mm3_per_mm();
+ for (size_t i = loops.first; i < loops.second; ++i) {
+ // Adjust flow according to this layer's layer height.
+ ExtrusionLoop loop = *dynamic_cast<const ExtrusionLoop*>(print.skirt().entities[i]);
+ for (ExtrusionPath &path : loop.paths) {
+ path.height = layer_skirt_flow.height;
+ path.mm3_per_mm = mm3_per_mm;
}
- m_avoid_crossing_perimeters.use_external_mp = false;
- // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
- if (first_layer && loops.first == 0)
- m_avoid_crossing_perimeters.disable_once = true;
+ //FIXME using the support_material_speed of the 1st object printed.
+ gcode += this->extrude_loop(loop, "skirt", m_config.support_material_speed.value);
}
+ m_avoid_crossing_perimeters.use_external_mp = false;
+ // Allow a straight travel move to the first object point if this is the first layer (but don't in next layers).
+ if (first_layer && loops.first == 0)
+ m_avoid_crossing_perimeters.disable_once = true;
}
// Extrude brim with the extruder of the 1st region.
@@ -2188,7 +2208,7 @@ void GCode::process_layer(
m_layer = layers[instance_to_print.layer_id].layer();
}
for (ObjectByExtruder::Island &island : instance_to_print.object_by_extruder.islands) {
- const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, instance_to_print.instance_id, extruder_id, print_wipe_extrusions) : island.by_region;
+ const auto& by_region_specific = is_anything_overridden ? island.by_region_per_copy(by_region_per_copy_cache, static_cast<unsigned int>(instance_to_print.instance_id), extruder_id, print_wipe_extrusions != 0) : island.by_region;
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
if (print.config().infill_first) {
gcode += this->extrude_infill(print, by_region_specific);
@@ -2797,7 +2817,7 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
- for (ExtrusionEntity *ee : region.perimeters.entities)
+ for (const ExtrusionEntity *ee : region.perimeters)
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
}
return gcode;
@@ -2809,8 +2829,10 @@ std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectBy
std::string gcode;
for (const ObjectByExtruder::Island::Region &region : by_region) {
m_config.apply(print.regions()[&region - &by_region.front()]->config());
- for (ExtrusionEntity *fill : region.infills.chained_path_from(m_last_pos).entities) {
- auto *eec = dynamic_cast<ExtrusionEntityCollection*>(fill);
+ ExtrusionEntitiesPtr extrusions { region.infills };
+ chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
+ for (const ExtrusionEntity *fill : extrusions) {
+ auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
if (eec) {
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
gcode += this->extrude_entity(*ee, "infill");
@@ -3275,7 +3297,7 @@ Point GCode::gcode_to_point(const Vec2d &point) const
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
// Fills in by_region_per_copy_cache and returns its reference.
-const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities) const
+const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtruder::Island::by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities) const
{
bool has_overrides = false;
for (const auto& reg : by_region)
@@ -3300,8 +3322,8 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
// Now we are going to iterate through perimeters and infills and pick ones that are supposed to be printed
// References are used so that we don't have to repeat the same code
for (int iter = 0; iter < 2; ++iter) {
- const ExtrusionEntitiesPtr& entities = (iter ? reg.infills.entities : reg.perimeters.entities);
- ExtrusionEntityCollection& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
+ const ExtrusionEntitiesPtr& entities = (iter ? reg.infills : reg.perimeters);
+ ExtrusionEntitiesPtr& target_eec = (iter ? by_region_per_copy_cache.back().infills : by_region_per_copy_cache.back().perimeters);
const std::vector<const WipingExtrusions::ExtruderPerCopy*>& overrides = (iter ? reg.infills_overrides : reg.perimeters_overrides);
// Now the most important thing - which extrusion should we print.
@@ -3311,9 +3333,8 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
for (unsigned int i = 0; i < overrides.size(); ++ i) {
const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i];
// This copy (aka object instance) should be printed with this extruder, which overrides the default one.
- if (this_override != nullptr && (*this_override)[copy] == extruder)
- // Clone the ExtrusionEntity. This is quite expensive.
- target_eec.append((*entities[i]));
+ if (this_override != nullptr && (*this_override)[copy] == int(extruder))
+ target_eec.emplace_back(entities[i]);
}
} else {
// Apply normal extrusions (non-overrides) for this region.
@@ -3321,13 +3342,11 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
for (; i < overrides.size(); ++ i) {
const WipingExtrusions::ExtruderPerCopy *this_override = overrides[i];
// This copy (aka object instance) should be printed with this extruder, which shall be equal to the default one.
- if (this_override == nullptr || (*this_override)[copy] == -extruder-1)
- // Clone the ExtrusionEntity. This is quite expensive.
- target_eec.append((*entities[i]));
+ if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1)
+ target_eec.emplace_back(entities[i]);
}
for (; i < overrides.size(); ++ i)
- // Clone the ExtrusionEntity. This is quite expensive.
- target_eec.append(*entities[i]);
+ target_eec.emplace_back(entities[i]);
}
}
}
@@ -3339,7 +3358,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
void GCode::ObjectByExtruder::Island::Region::append(const Type type, const ExtrusionEntityCollection* eec, const WipingExtrusions::ExtruderPerCopy* copies_extruder)
{
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
- ExtrusionEntityCollection* perimeters_or_infills;
+ ExtrusionEntitiesPtr* perimeters_or_infills;
std::vector<const WipingExtrusions::ExtruderPerCopy*>* perimeters_or_infills_overrides;
switch (type) {
@@ -3356,8 +3375,10 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
}
// First we append the entities, there are eec->entities.size() of them:
- size_t old_size = perimeters_or_infills->entities.size();
- perimeters_or_infills->append(eec->entities);
+ size_t old_size = perimeters_or_infills->size();
+ perimeters_or_infills->reserve(perimeters_or_infills->size() + eec->entities.size());
+ for (auto* ee : eec->entities)
+ perimeters_or_infills->emplace_back(ee);
if (copies_extruder != nullptr) {
perimeters_or_infills_overrides->reserve(old_size + eec->entities.size());
diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp
index 934dcaece..0344924a1 100644
--- a/src/libslic3r/GCode.hpp
+++ b/src/libslic3r/GCode.hpp
@@ -197,23 +197,25 @@ public:
// append full config to the given string
static void append_full_config(const Print& print, std::string& str);
-protected:
-#if ENABLE_THUMBNAIL_GENERATOR
- void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb);
-#else
- void _do_export(Print &print, FILE *file);
-#endif //ENABLE_THUMBNAIL_GENERATOR
-
// Object and support extrusions of the same PrintObject at the same print_z.
+ // public, so that it could be accessed by free helper functions from GCode.cpp
struct LayerToPrint
{
LayerToPrint() : object_layer(nullptr), support_layer(nullptr) {}
- const Layer *object_layer;
- const SupportLayer *support_layer;
- const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
- const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
- coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
+ const Layer* object_layer;
+ const SupportLayer* support_layer;
+ const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; }
+ const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; }
+ coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; }
};
+
+private:
+#if ENABLE_THUMBNAIL_GENERATOR
+ void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
+#else
+ void _do_export(Print &print, FILE *file);
+#endif //ENABLE_THUMBNAIL_GENERATOR
+
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
void process_layer(
@@ -252,8 +254,11 @@ protected:
struct Island
{
struct Region {
- ExtrusionEntityCollection perimeters;
- ExtrusionEntityCollection infills;
+ // Non-owned references to LayerRegion::perimeters::entities
+ // std::vector<const ExtrusionEntity*> would be better here, but there is no way in C++ to convert from std::vector<T*> std::vector<const T*> without copying.
+ ExtrusionEntitiesPtr perimeters;
+ // Non-owned references to LayerRegion::fills::entities
+ ExtrusionEntitiesPtr infills;
std::vector<const WipingExtrusions::ExtruderPerCopy*> infills_overrides;
std::vector<const WipingExtrusions::ExtruderPerCopy*> perimeters_overrides;
@@ -271,7 +276,7 @@ protected:
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
// Fills in by_region_per_copy_cache and returns its reference.
- const std::vector<Region>& by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, int extruder, bool wiping_entities = false) const;
+ const std::vector<Region>& by_region_per_copy(std::vector<Region> &by_region_per_copy_cache, unsigned int copy, unsigned int extruder, bool wiping_entities = false) const;
};
std::vector<Island> islands;
};
@@ -361,7 +366,7 @@ protected:
#endif /* HAS_PRESSURE_EQUALIZER */
std::unique_ptr<WipeTowerIntegration> m_wipe_tower;
- // Heights at which the skirt has already been extruded.
+ // Heights (print_z) at which the skirt has already been extruded.
std::vector<coordf_t> m_skirt_done;
// Has the brim been extruded already? Brim is being extruded only for the first object of a multi-object print.
bool m_brim_done;
@@ -369,11 +374,6 @@ protected:
bool m_second_layer_things_done;
// Index of a last object copy extruded.
std::pair<const PrintObject*, Point> m_last_obj_copy;
- // Extensions for colorprint - now it's not a just color_print_heights,
- // there can be some custom gcode.
- // Updated before the export and erased during the process,
- // so no toolchange occurs twice.
- std::vector<Model::CustomGCode> m_custom_gcode_per_print_z;
// Time estimators
GCodeTimeEstimator m_normal_time_estimator;
diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp
index 7b8004ab0..ec5de71b1 100644
--- a/src/libslic3r/GCode/Analyzer.cpp
+++ b/src/libslic3r/GCode/Analyzer.cpp
@@ -311,24 +311,22 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
{
auto axis_absolute_position = [this](GCodeAnalyzer::EAxis axis, const GCodeReader::GCodeLine& lineG1) -> float
{
- float current_absolute_position = _get_axis_position(axis);
- float current_origin = _get_axis_origin(axis);
- float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
-
bool is_relative = (_get_global_positioning_type() == Relative);
if (axis == E)
is_relative |= (_get_e_local_positioning_type() == Relative);
if (lineG1.has(Slic3r::Axis(axis)))
{
+ float lengthsScaleFactor = (_get_units() == GCodeAnalyzer::Inches) ? INCHES_TO_MM : 1.0f;
float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
- return is_relative ? current_absolute_position + ret : ret + current_origin;
+ return is_relative ? _get_axis_position(axis) + ret : _get_axis_origin(axis) + ret;
}
else
- return current_absolute_position;
+ return _get_axis_position(axis);
};
// updates axes positions from line
+
float new_pos[Num_Axis];
for (unsigned char a = X; a < Num_Axis; ++a)
{
@@ -352,7 +350,7 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
if (delta_pos[E] < 0.0f)
{
if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f))
- type = GCodeMove::Move;
+ type = GCodeMove::Move;
else
type = GCodeMove::Retract;
}
@@ -440,7 +438,9 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
if (line.has_e())
{
- _set_axis_origin(E, _get_axis_position(E) - line.e() * lengthsScaleFactor);
+ // extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments,
+ // we set the value taken from the G92 line as the new current position for it
+ _set_axis_position(E, line.e() * lengthsScaleFactor);
anyFound = true;
}
@@ -956,7 +956,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
GCodePreviewData::Extrusion::Path &path = paths.back();
path.polyline = polyline;
path.extrusion_role = data.extrusion_role;
- path.mm3_per_mm = data.mm3_per_mm;
+ path.mm3_per_mm = float(data.mm3_per_mm);
path.width = data.width;
path.height = data.height;
path.feedrate = data.feedrate;
@@ -978,7 +978,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
float volumetric_rate = FLT_MAX;
GCodePreviewData::Range height_range;
GCodePreviewData::Range width_range;
- GCodePreviewData::Range feedrate_range;
+ GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
GCodePreviewData::Range volumetric_rate_range;
GCodePreviewData::Range fan_speed_range;
@@ -1013,7 +1013,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
height_range.update_from(move.data.height);
width_range.update_from(move.data.width);
- feedrate_range.update_from(move.data.feedrate);
+ feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION);
volumetric_rate_range.update_from(volumetric_rate);
fan_speed_range.update_from(move.data.fan_speed);
}
@@ -1066,7 +1066,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
GCodePreviewData::Range height_range;
GCodePreviewData::Range width_range;
- GCodePreviewData::Range feedrate_range;
+ GCodePreviewData::MultiRange<GCodePreviewData::FeedrateKind> feedrate_range;
// to avoid to call the callback too often
unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1);
@@ -1106,7 +1106,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
extruder_id = move.data.extruder_id;
height_range.update_from(move.data.height);
width_range.update_from(move.data.width);
- feedrate_range.update_from(move.data.feedrate);
+ feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::TRAVEL);
}
// store last polyline
diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp
index b00bc73eb..6815ea73a 100644
--- a/src/libslic3r/GCode/CoolingBuffer.cpp
+++ b/src/libslic3r/GCode/CoolingBuffer.cpp
@@ -303,8 +303,8 @@ std::vector<PerExtruderAdjustments> CoolingBuffer::parse_layer_gcode(const std::
unsigned int extruder_id = extruders[i].id();
adj.extruder_id = extruder_id;
adj.cooling_slow_down_enabled = config.cooling.get_at(extruder_id);
- adj.slowdown_below_layer_time = config.slowdown_below_layer_time.get_at(extruder_id);
- adj.min_print_speed = config.min_print_speed.get_at(extruder_id);
+ adj.slowdown_below_layer_time = float(config.slowdown_below_layer_time.get_at(extruder_id));
+ adj.min_print_speed = float(config.min_print_speed.get_at(extruder_id));
map_extruder_to_per_extruder_adjustment[extruder_id] = i;
}
diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp
index e7475089a..bdc4367a3 100644
--- a/src/libslic3r/GCode/PreviewData.cpp
+++ b/src/libslic3r/GCode/PreviewData.cpp
@@ -1,6 +1,5 @@
#include "Analyzer.hpp"
#include "PreviewData.hpp"
-#include <float.h>
#include <I18N.hpp>
#include "Utils.hpp"
@@ -11,9 +10,7 @@
namespace Slic3r {
-const GCodePreviewData::Color GCodePreviewData::Color::Dummy(0.0f, 0.0f, 0.0f, 0.0f);
-
-std::vector<unsigned char> GCodePreviewData::Color::as_bytes() const
+std::vector<unsigned char> Color::as_bytes() const
{
std::vector<unsigned char> ret;
for (unsigned int i = 0; i < 4; ++i)
@@ -38,20 +35,6 @@ GCodePreviewData::Travel::Polyline::Polyline(EType type, EDirection direction, f
{
}
-const GCodePreviewData::Color GCodePreviewData::Range::Default_Colors[Colors_Count] =
-{
- Color(0.043f, 0.173f, 0.478f, 1.0f),
- Color(0.075f, 0.349f, 0.522f, 1.0f),
- Color(0.110f, 0.533f, 0.569f, 1.0f),
- Color(0.016f, 0.839f, 0.059f, 1.0f),
- Color(0.667f, 0.949f, 0.000f, 1.0f),
- Color(0.988f, 0.975f, 0.012f, 1.0f),
- Color(0.961f, 0.808f, 0.039f, 1.0f),
- Color(0.890f, 0.533f, 0.125f, 1.0f),
- Color(0.820f, 0.408f, 0.188f, 1.0f),
- Color(0.761f, 0.322f, 0.235f, 1.0f)
-};
-
GCodePreviewData::Range::Range()
{
reset();
@@ -59,54 +42,52 @@ GCodePreviewData::Range::Range()
void GCodePreviewData::Range::reset()
{
- min = FLT_MAX;
- max = -FLT_MAX;
+ min_val = FLT_MAX;
+ max_val = -FLT_MAX;
}
bool GCodePreviewData::Range::empty() const
{
- return min == max;
+ return min_val >= max_val;
}
void GCodePreviewData::Range::update_from(float value)
{
- min = std::min(min, value);
- max = std::max(max, value);
+ min_val = std::min(min_val, value);
+ max_val = std::max(max_val, value);
}
-void GCodePreviewData::Range::update_from(const Range& other)
+void GCodePreviewData::Range::update_from(const RangeBase& other)
{
- min = std::min(min, other.min);
- max = std::max(max, other.max);
+ min_val = std::min(min_val, other.min());
+ max_val = std::max(max_val, other.max());
}
-void GCodePreviewData::Range::set_from(const Range& other)
+float GCodePreviewData::RangeBase::step_size() const
{
- min = other.min;
- max = other.max;
+ return (max() - min()) / static_cast<float>(range_rainbow_colors.size() - 1);
}
-float GCodePreviewData::Range::step_size() const
-{
- return (max - min) / (float)(Colors_Count - 1);
-}
-
-GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
+Color GCodePreviewData::RangeBase::get_color_at(float value) const
{
if (empty())
- return Color::Dummy;
-
- float global_t = (value - min) / step_size();
+ return Color{};
- unsigned int low = (unsigned int)global_t;
- unsigned int high = clamp((unsigned int)0, Colors_Count - 1, low + 1);
+ // Input value scaled to the color range
+ const float global_t = std::max(0.0f, value - min()) / step_size(); // lower limit of 0.0f
+
+ constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
- Color color_low = colors[low];
- Color color_high = colors[high];
+ // Compute the two colors just below (low) and above (high) the input value
+ const std::size_t color_low_idx = std::clamp(static_cast<std::size_t>(global_t), std::size_t{ 0 }, color_max_idx);
+ const std::size_t color_high_idx = std::clamp(color_low_idx + 1, std::size_t{ 0 }, color_max_idx);
+ const Color color_low = range_rainbow_colors[color_low_idx];
+ const Color color_high = range_rainbow_colors[color_high_idx];
- float local_t = global_t - (float)low;
+ // Compute how far the value is between the low and high colors so that they can be interpolated
+ const float local_t = std::min(global_t - static_cast<float>(color_low_idx), 1.0f); // upper limit of 1.0f
- // interpolate in RGB space
+ // Interpolate between the low and high colors in RGB space to find exactly which color the input value should get
Color ret;
for (unsigned int i = 0; i < 4; ++i)
{
@@ -115,13 +96,23 @@ GCodePreviewData::Color GCodePreviewData::Range::get_color_at(float value) const
return ret;
}
-GCodePreviewData::LegendItem::LegendItem(const std::string& text, const GCodePreviewData::Color& color)
+float GCodePreviewData::Range::min() const
+{
+ return min_val;
+}
+
+float GCodePreviewData::Range::max() const
+{
+ return max_val;
+}
+
+GCodePreviewData::LegendItem::LegendItem(const std::string& text, const Color& color)
: text(text)
, color(color)
{
}
-const GCodePreviewData::Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
+const Color GCodePreviewData::Extrusion::Default_Extrusion_Role_Colors[erCount] =
{
Color(0.0f, 0.0f, 0.0f, 1.0f), // erNone
Color(1.0f, 0.0f, 0.0f, 1.0f), // erPerimeter
@@ -180,7 +171,7 @@ size_t GCodePreviewData::Extrusion::memory_used() const
const float GCodePreviewData::Travel::Default_Width = 0.075f;
const float GCodePreviewData::Travel::Default_Height = 0.075f;
-const GCodePreviewData::Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
+const Color GCodePreviewData::Travel::Default_Type_Colors[Num_Types] =
{
Color(0.0f, 0.0f, 0.75f, 1.0f), // Move
Color(0.0f, 0.75f, 0.0f, 1.0f), // Extrude
@@ -206,7 +197,7 @@ size_t GCodePreviewData::Travel::memory_used() const
return out;
}
-const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
+const Color GCodePreviewData::Retraction::Default_Color = Color(1.0f, 1.0f, 1.0f, 1.0f);
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
: position(position)
@@ -238,17 +229,15 @@ GCodePreviewData::GCodePreviewData()
void GCodePreviewData::set_default()
{
- ::memcpy((void*)ranges.height.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
- ::memcpy((void*)ranges.width.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
- ::memcpy((void*)ranges.feedrate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
- ::memcpy((void*)ranges.fan_speed.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
- ::memcpy((void*)ranges.volumetric_rate.colors, (const void*)Range::Default_Colors, Range::Colors_Count * sizeof(Color));
-
extrusion.set_default();
travel.set_default();
retraction.set_default();
unretraction.set_default();
shell.set_default();
+
+ // Configure the color range for feedrate to match the default for travels and to enable extrusions since they are always visible
+ ranges.feedrate.set_mode(FeedrateKind::TRAVEL, travel.is_visible);
+ ranges.feedrate.set_mode(FeedrateKind::EXTRUSION, true);
}
void GCodePreviewData::reset()
@@ -268,32 +257,32 @@ bool GCodePreviewData::empty() const
return extrusion.layers.empty() && travel.polylines.empty() && retraction.positions.empty() && unretraction.positions.empty();
}
-GCodePreviewData::Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
+Color GCodePreviewData::get_extrusion_role_color(ExtrusionRole role) const
{
return extrusion.role_colors[role];
}
-GCodePreviewData::Color GCodePreviewData::get_height_color(float height) const
+Color GCodePreviewData::get_height_color(float height) const
{
return ranges.height.get_color_at(height);
}
-GCodePreviewData::Color GCodePreviewData::get_width_color(float width) const
+Color GCodePreviewData::get_width_color(float width) const
{
return ranges.width.get_color_at(width);
}
-GCodePreviewData::Color GCodePreviewData::get_feedrate_color(float feedrate) const
+Color GCodePreviewData::get_feedrate_color(float feedrate) const
{
return ranges.feedrate.get_color_at(feedrate);
}
-GCodePreviewData::Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
+Color GCodePreviewData::get_fan_speed_color(float fan_speed) const
{
return ranges.fan_speed.get_color_at(fan_speed);
}
-GCodePreviewData::Color GCodePreviewData::get_volumetric_rate_color(float rate) const
+Color GCodePreviewData::get_volumetric_rate_color(float rate) const
{
return ranges.volumetric_rate.get_color_at(rate);
}
@@ -384,16 +373,16 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
{
struct Helper
{
- static void FillListFromRange(LegendItemsList& list, const Range& range, unsigned int decimals, float scale_factor)
+ static void FillListFromRange(LegendItemsList& list, const RangeBase& range, unsigned int decimals, float scale_factor)
{
- list.reserve(Range::Colors_Count);
+ list.reserve(range_rainbow_colors.size());
float step = range.step_size();
- for (int i = Range::Colors_Count - 1; i >= 0; --i)
+ for (int i = static_cast<int>(range_rainbow_colors.size()) - 1; i >= 0; --i)
{
char buf[1024];
- sprintf(buf, "%.*f", decimals, scale_factor * (range.min + (float)i * step));
- list.emplace_back(buf, range.colors[i]);
+ sprintf(buf, "%.*f", decimals, scale_factor * (range.min() + (float)i * step));
+ list.emplace_back(buf, range_rainbow_colors[i]);
}
}
};
@@ -446,8 +435,8 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
items.reserve(tools_colors_count);
for (unsigned int i = 0; i < tools_colors_count; ++i)
{
- GCodePreviewData::Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
+ Color color;
+ ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
items.emplace_back((boost::format(Slic3r::I18N::translate(L("Extruder %d"))) % (i + 1)).str(), color);
}
@@ -460,7 +449,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
if (color_print_cnt == 1) // means "Default print color"
{
Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data()), 4 * sizeof(float));
+ ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data()), 4 * sizeof(float));
items.emplace_back(cp_items[0], color);
break;
@@ -472,7 +461,7 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
for (int i = 0 ; i < color_print_cnt; ++i)
{
Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
+ ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + i * 4), 4 * sizeof(float));
items.emplace_back(cp_items[i], color);
}
@@ -502,20 +491,20 @@ const std::vector<std::string>& GCodePreviewData::ColorPrintColors()
return color_print;
}
-GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2)
+Color operator + (const Color& c1, const Color& c2)
{
- return GCodePreviewData::Color(clamp(0.0f, 1.0f, c1.rgba[0] + c2.rgba[0]),
- clamp(0.0f, 1.0f, c1.rgba[1] + c2.rgba[1]),
- clamp(0.0f, 1.0f, c1.rgba[2] + c2.rgba[2]),
- clamp(0.0f, 1.0f, c1.rgba[3] + c2.rgba[3]));
+ return Color(std::clamp(c1.rgba[0] + c2.rgba[0], 0.0f, 1.0f),
+ std::clamp(c1.rgba[1] + c2.rgba[1], 0.0f, 1.0f),
+ std::clamp(c1.rgba[2] + c2.rgba[2], 0.0f, 1.0f),
+ std::clamp(c1.rgba[3] + c2.rgba[3], 0.0f, 1.0f));
}
-GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color)
+Color operator * (float f, const Color& color)
{
- return GCodePreviewData::Color(clamp(0.0f, 1.0f, f * color.rgba[0]),
- clamp(0.0f, 1.0f, f * color.rgba[1]),
- clamp(0.0f, 1.0f, f * color.rgba[2]),
- clamp(0.0f, 1.0f, f * color.rgba[3]));
+ return Color(std::clamp(f * color.rgba[0], 0.0f, 1.0f),
+ std::clamp(f * color.rgba[1], 0.0f, 1.0f),
+ std::clamp(f * color.rgba[2], 0.0f, 1.0f),
+ std::clamp(f * color.rgba[3], 0.0f, 1.0f));
}
} // namespace Slic3r
diff --git a/src/libslic3r/GCode/PreviewData.hpp b/src/libslic3r/GCode/PreviewData.hpp
index 725c0258d..35bbfa50a 100644
--- a/src/libslic3r/GCode/PreviewData.hpp
+++ b/src/libslic3r/GCode/PreviewData.hpp
@@ -5,43 +5,190 @@
#include "../ExtrusionEntity.hpp"
#include "../Point.hpp"
+#include <tuple>
+#include <array>
+#include <vector>
+#include <bitset>
+#include <cstddef>
+#include <algorithm>
+#include <string>
+
+#include <float.h>
+
namespace Slic3r {
+// Represents an RGBA color
+struct Color
+{
+ std::array<float,4> rgba;
+
+ Color(const float *argba)
+ {
+ memcpy(this->rgba.data(), argba, sizeof(float) * 4);
+ }
+ constexpr Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) : rgba{r,g,b,a}
+ {
+ // Intentionally empty
+ }
+
+ std::vector<unsigned char> as_bytes() const;
+};
+Color operator + (const Color& c1, const Color& c2);
+Color operator * (float f, const Color& color);
+
+// Default colors for Ranges
+constexpr std::array<Color, 10> range_rainbow_colors{
+ Color{0.043f, 0.173f, 0.478f, 1.0f},
+ Color{0.075f, 0.349f, 0.522f, 1.0f},
+ Color{0.110f, 0.533f, 0.569f, 1.0f},
+ Color{0.016f, 0.839f, 0.059f, 1.0f},
+ Color{0.667f, 0.949f, 0.000f, 1.0f},
+ Color{0.988f, 0.975f, 0.012f, 1.0f},
+ Color{0.961f, 0.808f, 0.039f, 1.0f},
+ Color{0.890f, 0.533f, 0.125f, 1.0f},
+ Color{0.820f, 0.408f, 0.188f, 1.0f},
+ Color{0.761f, 0.322f, 0.235f, 1.0f}};
+
class GCodePreviewData
{
public:
- struct Color
+
+ // Color mapping to convert a float into a smooth rainbow of 10 colors.
+ class RangeBase
{
- float rgba[4];
+ public:
+
+ virtual void reset() = 0;
+ virtual bool empty() const = 0;
+ virtual float min() const = 0;
+ virtual float max() const = 0;
+
+ // Gets the step size using min(), max() and colors
+ float step_size() const;
+
+ // Gets the color at a value using colors, min(), and max()
+ Color get_color_at(float value) const;
+ };
- Color(const float *argba) { memcpy(this->rgba, argba, sizeof(float) * 4); }
- Color(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f) { rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a; }
+ // Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
+ class Range : public RangeBase
+ {
+ public:
+ Range();
- std::vector<unsigned char> as_bytes() const;
+ // RangeBase Overrides
+ void reset() override;
+ bool empty() const override;
+ float min() const override;
+ float max() const override;
+
+ // Range-specific methods
+ void update_from(float value);
+ void update_from(const RangeBase& other);
- static const Color Dummy;
+ private:
+ float min_val;
+ float max_val;
};
-
- // Color mapping from a <min, max> range into a smooth rainbow of 10 colors.
- struct Range
+
+ // Like Range, but stores multiple ranges internally that are used depending on mode.
+ // Template param EnumRangeType must be an enum with values for each type of range that needs to be tracked in this MultiRange.
+ // The last enum value should be num_values. The numerical values of all enum values should range from 0 to num_values.
+ template <typename EnumRangeType>
+ class MultiRange : public RangeBase
{
- static const unsigned int Colors_Count = 10;
- static const Color Default_Colors[Colors_Count];
+ public:
- Color colors[Colors_Count];
- float min;
- float max;
+ void reset() override
+ {
+ bounds = decltype(bounds){};
+ }
- Range();
+ bool empty() const override
+ {
+ for (std::size_t i = 0; i < bounds.size(); ++i)
+ {
+ if (bounds[i].min != bounds[i].max)
+ return false;
+ }
+ return true;
+ }
- void reset();
- bool empty() const;
- void update_from(float value);
- void update_from(const Range& other);
- void set_from(const Range& other);
- float step_size() const;
+ float min() const override
+ {
+ float min = FLT_MAX;
+ for (std::size_t i = 0; i < bounds.size(); ++i)
+ {
+ // Only use bounds[i] if the current mode includes it
+ if (mode.test(i))
+ {
+ min = std::min(min, bounds[i].min);
+ }
+ }
+ return min;
+ }
+
+ float max() const override
+ {
+ float max = -FLT_MAX;
+ for (std::size_t i = 0; i < bounds.size(); ++i)
+ {
+ // Only use bounds[i] if the current mode includes it
+ if (mode.test(i))
+ {
+ max = std::max(max, bounds[i].max);
+ }
+ }
+ return max;
+ }
+
+ void update_from(const float value, EnumRangeType range_type_value)
+ {
+ bounds[static_cast<std::size_t>(range_type_value)].update_from(value);
+ }
- Color get_color_at(float value) const;
+ void update_from(const MultiRange& other)
+ {
+ for (std::size_t i = 0; i < bounds.size(); ++i)
+ {
+ bounds[i].update_from(other.bounds[i]);
+ }
+ }
+
+ void set_mode(const EnumRangeType range_type_value, const bool enable)
+ {
+ mode.set(static_cast<std::size_t>(range_type_value), enable);
+ }
+
+ private:
+
+ // Interval bounds
+ struct Bounds
+ {
+ float min{FLT_MAX};
+ float max{-FLT_MAX};
+ void update_from(const float value)
+ {
+ min = std::min(min, value);
+ max = std::max(max, value);
+ }
+ void update_from(const Bounds other_bounds)
+ {
+ min = std::min(min, other_bounds.min);
+ max = std::max(max, other_bounds.max);
+ }
+ };
+
+ std::array<Bounds, static_cast<std::size_t>(EnumRangeType::num_values)> bounds;
+ std::bitset<static_cast<std::size_t>(EnumRangeType::num_values)> mode;
+ };
+
+ // Enum distinguishing different kinds of feedrate data
+ enum class FeedrateKind
+ {
+ EXTRUSION = 0, // values must go from 0 up to num_values
+ TRAVEL,
+ num_values //must be last in the list of values
};
struct Ranges
@@ -51,7 +198,7 @@ public:
// Color mapping by extrusion width.
Range width;
// Color mapping by feedrate.
- Range feedrate;
+ MultiRange<FeedrateKind> feedrate;
// Color mapping by fan speed.
Range fan_speed;
// Color mapping by volumetric extrusion rate.
@@ -245,9 +392,6 @@ public:
static const std::vector<std::string>& ColorPrintColors();
};
-GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2);
-GCodePreviewData::Color operator * (float f, const GCodePreviewData::Color& color);
-
} // namespace Slic3r
#endif /* slic3r_GCode_PreviewData_hpp_ */
diff --git a/src/libslic3r/GCode/PrintExtents.cpp b/src/libslic3r/GCode/PrintExtents.cpp
index d44ef1aad..1fedcf3f0 100644
--- a/src/libslic3r/GCode/PrintExtents.cpp
+++ b/src/libslic3r/GCode/PrintExtents.cpp
@@ -29,7 +29,7 @@ static inline BoundingBox extrusion_polyline_extents(const Polyline &polyline, c
static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusion_path)
{
- BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
+ BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width)));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = unscale(bbox.min);
@@ -43,7 +43,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio
{
BoundingBox bbox;
for (const ExtrusionPath &extrusion_path : extrusion_loop.paths)
- bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
+ bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width))));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = unscale(bbox.min);
@@ -57,7 +57,7 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext
{
BoundingBox bbox;
for (const ExtrusionPath &extrusion_path : extrusion_multi_path.paths)
- bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
+ bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, coord_t(scale_(0.5 * extrusion_path.width))));
BoundingBoxf bboxf;
if (! empty(bbox)) {
bboxf.min = unscale(bbox.min);
diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp
index 123656e43..3e01e2594 100644
--- a/src/libslic3r/GCode/ToolOrdering.cpp
+++ b/src/libslic3r/GCode/ToolOrdering.cpp
@@ -13,6 +13,10 @@
#include <cassert>
#include <limits>
+#include <libslic3r.h>
+
+#include "../GCodeWriter.hpp"
+
namespace Slic3r {
@@ -32,6 +36,39 @@ bool LayerTools::is_extruder_order(unsigned int a, unsigned int b) const
return false;
}
+// Return a zero based extruder from the region, or extruder_override if overriden.
+unsigned int LayerTools::perimeter_extruder(const PrintRegion &region) const
+{
+ assert(region.config().perimeter_extruder.value > 0);
+ return ((this->extruder_override == 0) ? region.config().perimeter_extruder.value : this->extruder_override) - 1;
+}
+
+unsigned int LayerTools::infill_extruder(const PrintRegion &region) const
+{
+ assert(region.config().infill_extruder.value > 0);
+ return ((this->extruder_override == 0) ? region.config().infill_extruder.value : this->extruder_override) - 1;
+}
+
+unsigned int LayerTools::solid_infill_extruder(const PrintRegion &region) const
+{
+ assert(region.config().solid_infill_extruder.value > 0);
+ return ((this->extruder_override == 0) ? region.config().solid_infill_extruder.value : this->extruder_override) - 1;
+}
+
+// Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
+unsigned int LayerTools::extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const
+{
+ assert(region.config().perimeter_extruder.value > 0);
+ assert(region.config().infill_extruder.value > 0);
+ assert(region.config().solid_infill_extruder.value > 0);
+ // 1 based extruder ID.
+ unsigned int extruder = ((this->extruder_override == 0) ?
+ (is_infill(extrusions.role()) ?
+ (is_solid_infill(extrusions.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) :
+ region.config().perimeter_extruder.value) :
+ this->extruder_override);
+ return (extruder == 0) ? 0 : extruder - 1;
+}
// For the use case when each object is printed separately
// (print.config().complete_objects is true).
@@ -52,7 +89,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
}
// Collect extruders reuqired to print the layers.
- this->collect_extruders(object);
+ this->collect_extruders(object, std::vector<std::pair<double, unsigned int>>());
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
@@ -89,9 +126,19 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
this->initialize_layers(zs);
}
+ // Use the extruder switches from Model::custom_gcode_per_print_z to override the extruder to print the object.
+ // Do it only if all the objects were configured to be printed with a single extruder.
+ std::vector<std::pair<double, unsigned int>> per_layer_extruder_switches;
+ if (auto num_extruders = unsigned(print.config().nozzle_diameter.size());
+ num_extruders > 1 && print.object_extruders().size() == 1) {
+ // Printing a single extruder platter on a printer with more than 1 extruder (or single-extruder multi-material).
+ // There may be custom per-layer tool changes available at the model.
+ per_layer_extruder_switches = custom_tool_changes(print.model(), num_extruders);
+ }
+
// Collect extruders reuqired to print the layers.
for (auto object : print.objects())
- this->collect_extruders(*object);
+ this->collect_extruders(*object, per_layer_extruder_switches);
// Reorder the extruders to minimize tool switches.
this->reorder_extruders(first_extruder);
@@ -111,13 +158,13 @@ void ToolOrdering::initialize_layers(std::vector<coordf_t> &zs)
coordf_t zmax = zs[i] + EPSILON;
for (; j < zs.size() && zs[j] <= zmax; ++ j) ;
// Assign an average print_z to the set of layers with nearly equal print_z.
- m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1]), m_print_config_ptr));
+ m_layer_tools.emplace_back(LayerTools(0.5 * (zs[i] + zs[j-1])));
i = j;
}
}
// Collect extruders reuqired to print layers.
-void ToolOrdering::collect_extruders(const PrintObject &object)
+void ToolOrdering::collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches)
{
// Collect the support extruders.
for (auto support_layer : object.support_layers()) {
@@ -134,9 +181,23 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
if (has_support || has_interface)
layer_tools.has_support = true;
}
+
+ // Extruder overrides are ordered by print_z.
+ std::vector<std::pair<double, unsigned int>>::const_iterator it_per_layer_extruder_override;
+ it_per_layer_extruder_override = per_layer_extruder_switches.begin();
+ unsigned int extruder_override = 0;
+
// Collect the object extruders.
for (auto layer : object.layers()) {
LayerTools &layer_tools = this->tools_for_layer(layer->print_z);
+
+ // Override extruder with the next
+ for (; it_per_layer_extruder_override != per_layer_extruder_switches.end() && it_per_layer_extruder_override->first < layer->print_z + EPSILON; ++ it_per_layer_extruder_override)
+ extruder_override = (int)it_per_layer_extruder_override->second;
+
+ // Store the current extruder override (set to zero if no overriden), so that layer_tools.wiping_extrusions().is_overridable_and_mark() will use it.
+ layer_tools.extruder_override = extruder_override;
+
// What extruders are required to print this object layer?
for (size_t region_id = 0; region_id < object.region_volumes.size(); ++ region_id) {
const LayerRegion *layerm = (region_id < layer->regions().size()) ? layer->regions()[region_id] : nullptr;
@@ -150,19 +211,18 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
something_nonoverriddable = false;
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
- if (!layer_tools.wiping_extrusions().is_overriddable(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
+ if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
something_nonoverriddable = true;
break;
}
}
if (something_nonoverriddable)
- layer_tools.extruders.push_back(region.config().perimeter_extruder.value);
+ layer_tools.extruders.emplace_back((extruder_override == 0) ? region.config().perimeter_extruder.value : extruder_override);
layer_tools.has_object = true;
}
-
bool has_infill = false;
bool has_solid_infill = false;
bool something_nonoverriddable = false;
@@ -176,17 +236,19 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
has_infill = true;
if (m_print_config_ptr) {
- if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable(*fill, *m_print_config_ptr, object, region))
+ if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
something_nonoverriddable = true;
}
}
- if (something_nonoverriddable || !m_print_config_ptr)
- {
- if (has_solid_infill)
- layer_tools.extruders.push_back(region.config().solid_infill_extruder);
- if (has_infill)
- layer_tools.extruders.push_back(region.config().infill_extruder);
+ if (something_nonoverriddable || !m_print_config_ptr) {
+ if (extruder_override == 0) {
+ if (has_solid_infill)
+ layer_tools.extruders.emplace_back(region.config().solid_infill_extruder);
+ if (has_infill)
+ layer_tools.extruders.emplace_back(region.config().infill_extruder);
+ } else if (has_solid_infill || has_infill)
+ layer_tools.extruders.emplace_back(extruder_override);
}
if (has_solid_infill || has_infill)
layer_tools.has_object = true;
@@ -199,7 +261,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object)
// make sure that there are some tools for each object layer (e.g. tall wiping object will result in empty extruders vector)
if (layer.extruders.empty() && layer.has_object)
- layer.extruders.push_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
+ layer.extruders.emplace_back(0); // 0="dontcare" extruder - it will be taken care of in reorder_extruders
}
}
@@ -254,11 +316,9 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
for (unsigned int &extruder_id : lt.extruders) {
assert(extruder_id > 0);
-- extruder_id;
- }
+ }
}
-
-
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z)
{
if (m_layer_tools.empty())
@@ -394,6 +454,52 @@ void ToolOrdering::collect_extruder_statistics(bool prime_multi_material)
}
}
+// Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
+// Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
+// If multiple events are planned over a span of a single layer, use the last one.
+void ToolOrdering::assign_custom_gcodes(const Print &print)
+{
+ // Only valid for non-sequential print.
+ assert(! print.config().complete_objects.value);
+
+ const Model::CustomGCodeInfo &custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
+ if (custom_gcode_per_print_z.gcodes.empty())
+ return;
+
+ unsigned int num_extruders = *std::max_element(m_all_printing_extruders.begin(), m_all_printing_extruders.end()) + 1;
+ std::vector<unsigned char> extruder_printing_above(num_extruders, false);
+ auto custom_gcode_it = custom_gcode_per_print_z.gcodes.rbegin();
+ // If printing on a single extruder machine, make the tool changes trigger color change (M600) events.
+ bool tool_changes_as_color_changes = num_extruders == 1;
+ // From the last layer to the first one:
+ for (auto it_lt = m_layer_tools.rbegin(); it_lt != m_layer_tools.rend(); ++ it_lt) {
+ LayerTools &lt = *it_lt;
+ // Add the extruders of the current layer to the set of extruders printing at and above this print_z.
+ for (unsigned int i : lt.extruders)
+ extruder_printing_above[i] = true;
+ // Skip all custom G-codes above this layer and skip all extruder switches.
+ for (; custom_gcode_it != custom_gcode_per_print_z.gcodes.rend() && (custom_gcode_it->print_z > lt.print_z + EPSILON || custom_gcode_it->gcode == ToolChangeCode); ++ custom_gcode_it);
+ if (custom_gcode_it == custom_gcode_per_print_z.gcodes.rend())
+ // Custom G-codes were processed.
+ break;
+ // Some custom G-code is configured for this layer or a layer below.
+ const Model::CustomGCode &custom_gcode = *custom_gcode_it;
+ // print_z of the layer below the current layer.
+ coordf_t print_z_below = 0.;
+ if (auto it_lt_below = it_lt; ++ it_lt_below != m_layer_tools.rend())
+ print_z_below = it_lt_below->print_z;
+ if (custom_gcode.print_z > print_z_below + 0.5 * EPSILON) {
+ // The custom G-code applies to the current layer.
+ if ( tool_changes_as_color_changes || custom_gcode.gcode != ColorChangeCode ||
+ (custom_gcode.extruder <= num_extruders && extruder_printing_above[unsigned(custom_gcode.extruder - 1)]))
+ // If it is color change, it will actually be useful as the exturder above will print.
+ lt.custom_gcode = &custom_gcode;
+ // Consume that custom G-code event.
+ ++ custom_gcode_it;
+ }
+ }
+}
+
const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const
{
auto it_layer_tools = std::lower_bound(m_layer_tools.begin(), m_layer_tools.end(), LayerTools(print_z - EPSILON));
@@ -411,7 +517,7 @@ const LayerTools& ToolOrdering::tools_for_layer(coordf_t print_z) const
}
// This function is called from Print::mark_wiping_extrusions and sets extruder this entity should be printed with (-1 .. as usual)
-void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies)
+void WipingExtrusions::set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies)
{
something_overridden = true;
@@ -447,11 +553,10 @@ int WipingExtrusions::last_nonsoluble_extruder_on_layer(const PrintConfig& print
return (-1);
}
-
// Decides whether this entity could be overridden
bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const
{
- if (print_config.filament_soluble.get_at(Print::get_extruder(eec, region)))
+ if (print_config.filament_soluble.get_at(m_layer_tools->extruder(eec, region)))
return false;
if (object.config().wipe_into_objects)
@@ -463,7 +568,6 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
return true;
}
-
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
// and returns volume that is left to be wiped on the wipe tower.
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
@@ -471,8 +575,8 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
const LayerTools& lt = *m_layer_tools;
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
- if (print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
- return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
+ if (! this->something_overridable || volume_to_wipe <= 0. || print.config().filament_soluble.get_at(old_extruder) || print.config().filament_soluble.get_at(new_extruder))
+ return std::max(0.f, volume_to_wipe); // Soluble filament cannot be wiped in a random infill, neither the filament after it
// we will sort objects so that dedicated for wiping are at the beginning:
PrintObjectPtrs object_list = print.objects();
@@ -495,13 +599,13 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
const PrintObject* object = object_list[i];
// Finds this layer:
- auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
- if (this_layer_it == object->layers().end())
- continue;
- const Layer* this_layer = *this_layer_it;
+ const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON);
+ if (this_layer == nullptr)
+ continue;
size_t num_of_copies = object->copies().size();
- for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
+ // iterate through copies (aka PrintObject instances) first, so that we mark neighbouring infills to minimize travel moves
+ for (unsigned int copy = 0; copy < num_of_copies; ++copy) {
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
const auto& region = *object->print()->regions()[region_id];
@@ -509,51 +613,48 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
if (!region.config().wipe_into_infill && !object->config().wipe_into_objects)
continue;
-
- if ((!print.config().infill_first ? perimeters_done : !perimeters_done) || (!object->config().wipe_into_objects && region.config().wipe_into_infill)) {
+ bool wipe_into_infill_only = ! object->config().wipe_into_objects && region.config().wipe_into_infill;
+ if (print.config().infill_first != perimeters_done || wipe_into_infill_only) {
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->fills.entities) { // iterate through all infill Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (!is_overriddable(*fill, print.config(), *object, region))
continue;
- if (volume_to_wipe<=0)
- continue;
-
- if (!object->config().wipe_into_objects && !print.config().infill_first && region.config().wipe_into_infill)
+ if (wipe_into_infill_only && ! print.config().infill_first)
// In this case we must check that the original extruder is used on this layer before the one we are overridding
// (and the perimeters will be finished before the infill is printed):
- if (!lt.is_extruder_order(region.config().perimeter_extruder - 1, new_extruder))
+ if (!lt.is_extruder_order(lt.perimeter_extruder(region), new_extruder))
continue;
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
set_extruder_override(fill, copy, new_extruder, num_of_copies);
- volume_to_wipe -= float(fill->total_volume());
+ if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f)
+ // More material was purged already than asked for.
+ return 0.f;
}
}
}
// Now the same for perimeters - see comments above for explanation:
- if (object->config().wipe_into_objects && (print.config().infill_first ? perimeters_done : !perimeters_done))
+ if (object->config().wipe_into_objects && print.config().infill_first == perimeters_done)
{
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) {
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
- if (!is_overriddable(*fill, print.config(), *object, region))
- continue;
-
- if (volume_to_wipe<=0)
- continue;
-
- if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) {
+ if (is_overriddable(*fill, print.config(), *object, region) && !is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume) {
set_extruder_override(fill, copy, new_extruder, num_of_copies);
- volume_to_wipe -= float(fill->total_volume());
+ if ((volume_to_wipe -= float(fill->total_volume())) <= 0.f)
+ // More material was purged already than asked for.
+ return 0.f;
}
}
}
}
}
}
- return std::max(0.f, volume_to_wipe);
+ // Some purge remains to be done on the Wipe Tower.
+ assert(volume_to_wipe > 0.);
+ return volume_to_wipe;
}
@@ -564,16 +665,18 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
// them again and make sure we override it.
void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
{
+ if (! this->something_overridable)
+ return;
+
const LayerTools& lt = *m_layer_tools;
unsigned int first_nonsoluble_extruder = first_nonsoluble_extruder_on_layer(print.config());
unsigned int last_nonsoluble_extruder = last_nonsoluble_extruder_on_layer(print.config());
for (const PrintObject* object : print.objects()) {
// Finds this layer:
- auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [&lt](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
- if (this_layer_it == object->layers().end())
- continue;
- const Layer* this_layer = *this_layer_it;
+ const Layer* this_layer = object->get_layer_at_printz(lt.print_z, EPSILON);
+ if (this_layer == nullptr)
+ continue;
size_t num_of_copies = object->copies().size();
for (size_t copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
@@ -596,9 +699,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
// Either way, we will now force-override it with something suitable:
if (print.config().infill_first
|| object->config().wipe_into_objects // in this case the perimeter is overridden, so we can override by the last one safely
- || lt.is_extruder_order(region.config().perimeter_extruder - 1, last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
- || std::find(lt.extruders.begin(), lt.extruders.end(), region.config().infill_extruder - 1) == lt.extruders.end()) // we have to force override - this could violate infill_first (FIXME)
- )
+ || lt.is_extruder_order(lt.perimeter_extruder(region), last_nonsoluble_extruder // !infill_first, but perimeter is already printed when last extruder prints
+ || ! lt.has_extruder(lt.infill_extruder(region)))) // we have to force override - this could violate infill_first (FIXME)
set_extruder_override(fill, copy, (print.config().infill_first ? first_nonsoluble_extruder : last_nonsoluble_extruder), num_of_copies);
else {
// In this case we can (and should) leave it to be printed normally.
@@ -609,11 +711,8 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
// Now the same for perimeters - see comments above for explanation:
for (const ExtrusionEntity* ee : this_layer->regions()[region_id]->perimeters.entities) { // iterate through all perimeter Collections
auto* fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
- if (!is_overriddable(*fill, print.config(), *object, region)
- || is_entity_overridden(fill, copy) )
- continue;
-
- set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
+ if (is_overriddable(*fill, print.config(), *object, region) && ! is_entity_overridden(fill, copy))
+ set_extruder_override(fill, copy, (print.config().infill_first ? last_nonsoluble_extruder : first_nonsoluble_extruder), num_of_copies);
}
}
}
diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp
index dcb93c021..08dd72656 100644
--- a/src/libslic3r/GCode/ToolOrdering.hpp
+++ b/src/libslic3r/GCode/ToolOrdering.hpp
@@ -48,6 +48,11 @@ public:
void ensure_perimeters_infills_order(const Print& print);
bool is_overriddable(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) const;
+ bool is_overriddable_and_mark(const ExtrusionEntityCollection& ee, const PrintConfig& print_config, const PrintObject& object, const PrintRegion& region) {
+ bool out = this->is_overriddable(ee, print_config, object, region);
+ this->something_overridable |= out;
+ return out;
+ }
void set_layer_tools_ptr(const LayerTools* lt) { m_layer_tools = lt; }
@@ -56,14 +61,16 @@ private:
int last_nonsoluble_extruder_on_layer(const PrintConfig& print_config) const;
// This function is called from mark_wiping_extrusions and sets extruder that it should be printed with (-1 .. as usual)
- void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
+ void set_extruder_override(const ExtrusionEntity* entity, size_t copy_id, int extruder, size_t num_of_copies);
// Returns true in case that entity is not printed with its usual extruder for a given copy:
bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const {
- return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
+ auto it = entity_map.find(entity);
+ return it == entity_map.end() ? false : it->second[copy_id] != -1;
}
std::map<const ExtrusionEntity*, ExtruderPerCopy> entity_map; // to keep track of who prints what
+ bool something_overridable = false;
bool something_overridden = false;
const LayerTools* m_layer_tools; // so we know which LayerTools object this belongs to
};
@@ -73,13 +80,7 @@ private:
class LayerTools
{
public:
- LayerTools(const coordf_t z, const PrintConfig* print_config_ptr = nullptr) :
- print_z(z),
- has_object(false),
- has_support(false),
- has_wipe_tower(false),
- wipe_tower_partitions(0),
- wipe_tower_layer_height(0.) {}
+ LayerTools(const coordf_t z) : print_z(z) {}
// Changing these operators to epsilon version can make a problem in cases where support and object layers get close to each other.
// In case someone tries to do it, make sure you know what you're doing and test it properly (slice multiple objects at once with supports).
@@ -89,19 +90,31 @@ public:
bool is_extruder_order(unsigned int a, unsigned int b) const;
bool has_extruder(unsigned int extruder) const { return std::find(this->extruders.begin(), this->extruders.end(), extruder) != this->extruders.end(); }
- coordf_t print_z;
- bool has_object;
- bool has_support;
+ // Return a zero based extruder from the region, or extruder_override if overriden.
+ unsigned int perimeter_extruder(const PrintRegion &region) const;
+ unsigned int infill_extruder(const PrintRegion &region) const;
+ unsigned int solid_infill_extruder(const PrintRegion &region) const;
+ // Returns a zero based extruder this eec should be printed with, according to PrintRegion config or extruder_override if overriden.
+ unsigned int extruder(const ExtrusionEntityCollection &extrusions, const PrintRegion &region) const;
+
+ coordf_t print_z = 0.;
+ bool has_object = false;
+ bool has_support = false;
// Zero based extruder IDs, ordered to minimize tool switches.
std::vector<unsigned int> extruders;
+ // If per layer extruder switches are inserted by the G-code preview slider, this value contains the new (1 based) extruder, with which the whole object layer is being printed with.
+ // If not overriden, it is set to 0.
+ unsigned int extruder_override = 0;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
- bool has_wipe_tower;
+ bool has_wipe_tower = false;
// Number of wipe tower partitions to support the required number of tool switches
// and to support the wipe tower partitions above this one.
- size_t wipe_tower_partitions;
- coordf_t wipe_tower_layer_height;
+ size_t wipe_tower_partitions = 0;
+ coordf_t wipe_tower_layer_height = 0.;
+ // Custom G-code (color change, extruder switch, pause) to be performed before this layer starts to print.
+ const Model::CustomGCode *custom_gcode = nullptr;
WipingExtrusions& wiping_extrusions() {
m_wiping_extrusions.set_layer_tools_ptr(this);
@@ -122,14 +135,20 @@ public:
// For the use case when each object is printed separately
// (print.config.complete_objects is true).
- ToolOrdering(const PrintObject &object, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
+ ToolOrdering(const PrintObject &object, unsigned int first_extruder, bool prime_multi_material = false);
// For the use case when all objects are printed at once.
// (print.config.complete_objects is false).
- ToolOrdering(const Print &print, unsigned int first_extruder = (unsigned int)-1, bool prime_multi_material = false);
+ ToolOrdering(const Print &print, unsigned int first_extruder, bool prime_multi_material = false);
void clear() { m_layer_tools.clear(); }
+ // Only valid for non-sequential print:
+ // Assign a pointer to a custom G-code to the respective ToolOrdering::LayerTools.
+ // Ignore color changes, which are performed on a layer and for such an extruder, that the extruder will not be printing above that layer.
+ // If multiple events are planned over a span of a single layer, use the last one.
+ void assign_custom_gcodes(const Print &print);
+
// Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed.
unsigned int first_extruder() const { return m_first_printing_extruder; }
@@ -153,7 +172,7 @@ public:
private:
void initialize_layers(std::vector<coordf_t> &zs);
- void collect_extruders(const PrintObject &object);
+ void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
void reorder_extruders(unsigned int last_extruder_id);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
void collect_extruder_statistics(bool prime_multi_material);
@@ -166,7 +185,6 @@ private:
// All extruders, which extrude some material over m_layer_tools.
std::vector<unsigned int> m_all_printing_extruders;
-
const PrintConfig* m_print_config_ptr = nullptr;
};
diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp
index c624c0fce..36127cad7 100644
--- a/src/libslic3r/GCodeTimeEstimator.cpp
+++ b/src/libslic3r/GCodeTimeEstimator.cpp
@@ -1261,7 +1261,9 @@ namespace Slic3r {
if (line.has_e())
{
- set_axis_origin(E, get_axis_position(E) - line.e() * lengthsScaleFactor);
+ // extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments,
+ // we set the value taken from the G92 line as the new current position for it
+ set_axis_position(E, line.e() * lengthsScaleFactor);
anyFound = true;
}
else
diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp
index 364ba12ae..4c53048dc 100644
--- a/src/libslic3r/GCodeWriter.cpp
+++ b/src/libslic3r/GCodeWriter.cpp
@@ -19,12 +19,13 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
this->config.apply(print_config, true);
m_extrusion_axis = this->config.get_extrusion_axis();
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
- m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ?
- print_config.machine_max_acceleration_extruding.values.front() : 0;
+ m_max_acceleration = std::lrint((print_config.gcode_flavor.value == gcfMarlin) ?
+ print_config.machine_max_acceleration_extruding.values.front() : 0);
}
-void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
+void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
{
+ std::sort(extruder_ids.begin(), extruder_ids.end());
m_extruders.clear();
m_extruders.reserve(extruder_ids.size());
for (unsigned int extruder_id : extruder_ids)
@@ -247,9 +248,9 @@ std::string GCodeWriter::toolchange_prefix() const
std::string GCodeWriter::toolchange(unsigned int extruder_id)
{
// set the new extruder
- auto it_extruder = std::lower_bound(m_extruders.begin(), m_extruders.end(), Extruder::key(extruder_id));
- assert(it_extruder != m_extruders.end());
- m_extruder = const_cast<Extruder*>(&*it_extruder);
+ auto it_extruder = Slic3r::lower_bound_by_predicate(m_extruders.begin(), m_extruders.end(), [extruder_id](const Extruder &e) { return e.id() < extruder_id; });
+ assert(it_extruder != m_extruders.end() && it_extruder->id() == extruder_id);
+ m_extruder = &*it_extruder;
// return the toolchange command
// if we are running a single-extruder setup, just set the extruder and return nothing
diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp
index 98abdda28..abeaf0024 100644
--- a/src/libslic3r/GCodeWriter.hpp
+++ b/src/libslic3r/GCodeWriter.hpp
@@ -13,7 +13,7 @@ namespace Slic3r {
// Additional Codes which can be set by user using DoubleSlider
static constexpr char ColorChangeCode[] = "M600";
static constexpr char PausePrintCode[] = "M601";
-static constexpr char ExtruderChangeCode[] = "tool_change";
+static constexpr char ToolChangeCode[] = "tool_change";
class GCodeWriter {
public:
@@ -33,7 +33,7 @@ public:
std::string extrusion_axis() const { return m_extrusion_axis; }
void apply_print_config(const PrintConfig &print_config);
// Extruders are expected to be sorted in an increasing order.
- void set_extruders(const std::vector<unsigned int> &extruder_ids);
+ void set_extruders(std::vector<unsigned int> extruder_ids);
const std::vector<Extruder>& extruders() const { return m_extruders; }
std::vector<unsigned int> extruder_ids() const {
std::vector<unsigned int> out;
@@ -74,7 +74,8 @@ public:
Vec3d get_position() const { return m_pos; }
private:
- std::vector<Extruder> m_extruders;
+ // Extruders are sorted by their ID, so that binary search is possible.
+ std::vector<Extruder> m_extruders;
std::string m_extrusion_axis;
bool m_single_extruder_multi_material;
Extruder* m_extruder;
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 96a32680e..8699eed7f 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -126,7 +126,7 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
if (add_default_instances)
model.add_default_instances();
- update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
+ update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config);
return model;
}
@@ -163,7 +163,7 @@ Model Model::read_from_archive(const std::string& input_file, DynamicPrintConfig
if (add_default_instances)
model.add_default_instances();
- update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, config);
+ update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z.gcodes, config);
return model;
}
@@ -598,21 +598,6 @@ std::string Model::propose_export_file_name_and_path(const std::string &new_exte
return boost::filesystem::path(this->propose_export_file_name_and_path()).replace_extension(new_extension).string();
}
-std::vector<std::pair<double, DynamicPrintConfig>> Model::get_custom_tool_changes(double default_layer_height, size_t num_extruders) const
-{
- std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes;
- for (const CustomGCode& custom_gcode : custom_gcode_per_print_z)
- if (custom_gcode.gcode == ExtruderChangeCode) {
- DynamicPrintConfig config;
- // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
- config.set_key_value("extruder", new ConfigOptionInt(custom_gcode.extruder > num_extruders ? 0 : custom_gcode.extruder));
- // For correct extruders(tools) changing, we should decrease custom_gcode.height value by one default layer height
- custom_tool_changes.push_back({ custom_gcode.print_z - default_layer_height, config });
- }
-
- return custom_tool_changes;
-}
-
ModelObject::~ModelObject()
{
this->clear_volumes();
@@ -1856,6 +1841,19 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
return ret;
}
+// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
+// print_z corresponds to the first layer printed with the new extruder.
+std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders)
+{
+ std::vector<std::pair<double, unsigned int>> custom_tool_changes;
+ for (const Model::CustomGCode &custom_gcode : model.custom_gcode_per_print_z.gcodes)
+ if (custom_gcode.gcode == ToolChangeCode) {
+ // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
+ custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(custom_gcode.extruder > num_extruders ? 1 : custom_gcode.extruder));
+ }
+ return custom_tool_changes;
+}
+
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
// ordered in the same order. In that case it is not necessary to kill the background processing.
bool model_object_list_equal(const Model &model_old, const Model &model_new)
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 44f5049c9..d7c813113 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -399,13 +399,9 @@ public:
int object_idx{ -1 };
int volume_idx{ -1 };
Vec3d mesh_offset{ Vec3d::Zero() };
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
Geometry::Transformation transform;
template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset, transform); }
-#else
- template<class Archive> void serialize(Archive& ar) { ar(input_file, object_idx, volume_idx, mesh_offset); }
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
};
Source source;
@@ -767,12 +763,34 @@ public:
double print_z;
std::string gcode;
- int extruder; // 0 - "gcode" will be applied for whole print
- // else - "gcode" will be applied only for "extruder" print
+ int extruder; // Informative value for ColorChangeCode and ToolChangeCode
+ // "gcode" == ColorChangeCode => M600 will be applied for "extruder" extruder
+ // "gcode" == ToolChangeCode => for whole print tool will be switched to "extruder" extruder
std::string color; // if gcode is equal to PausePrintCode,
// this field is used for save a short message shown on Printer display
};
- std::vector<CustomGCode> custom_gcode_per_print_z;
+
+ struct CustomGCodeInfo
+ {
+ enum MODE
+ {
+ SingleExtruder, // single extruder printer preset is selected
+ MultiAsSingle, // multiple extruder printer preset is selected, but
+ // this mode works just for Single extruder print
+ // (For all print from objects settings is used just one extruder)
+ MultiExtruder // multiple extruder printer preset is selected
+ } mode;
+
+ std::vector<CustomGCode> gcodes;
+
+ bool operator==(const CustomGCodeInfo& rhs) const
+ {
+ return (rhs.mode == this->mode ) &&
+ (rhs.gcodes == this->gcodes );
+ }
+ bool operator!=(const CustomGCodeInfo& rhs) const { return !(*this == rhs); }
+ }
+ custom_gcode_per_print_z;
// Default constructor assigns a new ID to the model.
Model() { assert(this->id().valid()); }
@@ -838,9 +856,6 @@ public:
// Propose an output path, replace extension. The new_extension shall contain the initial dot.
std::string propose_export_file_name_and_path(const std::string &new_extension) const;
- // from custom_gcode_per_print_z get just tool_change codes
- std::vector<std::pair<double, DynamicPrintConfig>> get_custom_tool_changes(double default_layer_height, size_t num_extruders) const;
-
private:
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };
void assign_new_unique_ids_recursive();
@@ -857,6 +872,10 @@ private:
#undef OBJECTBASE_DERIVED_COPY_MOVE_CLONE
#undef OBJECTBASE_DERIVED_PRIVATE_COPY_MOVE
+// Return pairs of <print_z, 1-based extruder ID> sorted by increasing print_z from custom_gcode_per_print_z.
+// print_z corresponds to the first layer printed with the new extruder.
+extern std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Model &model, size_t num_extruders);
+
// Test whether the two models contain the same number of ModelObjects with the same set of IDs
// ordered in the same order. In that case it is not necessary to kill the background processing.
extern bool model_object_list_equal(const Model &model_old, const Model &model_new);
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 02d9da784..1cb16b4de 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -478,7 +478,7 @@ static std::vector<PrintInstances> print_objects_from_model_object(const ModelOb
// Compare just the layer ranges and their layer heights, not the associated configs.
// Ignore the layer heights if check_layer_heights is false.
-bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
+static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_config_ranges &lr2, bool check_layer_height)
{
if (lr1.size() != lr2.size())
return false;
@@ -493,6 +493,37 @@ bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_layer_c
return true;
}
+// Returns true if va == vb when all CustomGCode items that are not ToolChangeCode are ignored.
+static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Model::CustomGCode> &va, const std::vector<Model::CustomGCode> &vb)
+{
+ auto it_a = va.begin();
+ auto it_b = vb.begin();
+ while (it_a != va.end() && it_b != vb.end()) {
+ if (it_a != va.end() && it_a->gcode != ToolChangeCode) {
+ // Skip any CustomGCode items, which are not tool changes.
+ ++ it_a;
+ continue;
+ }
+ if (it_b != vb.end() && it_b->gcode != ToolChangeCode) {
+ // Skip any CustomGCode items, which are not tool changes.
+ ++ it_b;
+ continue;
+ }
+ if (it_a == va.end() || it_b == vb.end())
+ // va or vb contains more Tool Changes than the other.
+ return true;
+ assert(it_a->gcode == ToolChangeCode);
+ assert(it_b->gcode == ToolChangeCode);
+ if (*it_a != *it_b)
+ // The two Tool Changes differ.
+ return true;
+ ++ it_a;
+ ++ it_b;
+ }
+ // There is no change in custom Tool Changes.
+ return false;
+}
+
// Collect diffs of configuration values at various containers,
// resolve the filament rectract overrides of extruder retract values.
void Print::config_diffs(
@@ -638,48 +669,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
}
- // Convert input config ranges into continuous non-overlapping sorted vector of intervals and their configs,
- // considering custom_tool_change values
- void assign(const t_layer_config_ranges &in, const std::vector<std::pair<double, DynamicPrintConfig>> &custom_tool_changes) {
- m_ranges.clear();
- m_ranges.reserve(in.size());
- // Input ranges are sorted lexicographically. First range trims the other ranges.
- coordf_t last_z = 0;
- for (const std::pair<const t_layer_height_range, DynamicPrintConfig> &range : in)
- if (range.first.second > last_z) {
- coordf_t min_z = std::max(range.first.first, 0.);
- if (min_z > last_z + EPSILON) {
- m_ranges.emplace_back(t_layer_height_range(last_z, min_z), nullptr);
- last_z = min_z;
- }
- if (range.first.second > last_z + EPSILON) {
- const DynamicPrintConfig* cfg = &range.second;
- m_ranges.emplace_back(t_layer_height_range(last_z, range.first.second), cfg);
- last_z = range.first.second;
- }
- }
-
- // add ranges for extruder changes from custom_tool_changes
- for (size_t i = 0; i < custom_tool_changes.size(); i++) {
- const DynamicPrintConfig* cfg = &custom_tool_changes[i].second;
- coordf_t cur_Z = custom_tool_changes[i].first;
- coordf_t next_Z = i == custom_tool_changes.size()-1 ? DBL_MAX : custom_tool_changes[i+1].first;
- if (cur_Z > last_z + EPSILON) {
- if (i==0)
- m_ranges.emplace_back(t_layer_height_range(last_z, cur_Z), nullptr);
- m_ranges.emplace_back(t_layer_height_range(cur_Z, next_Z), cfg);
- }
- else if (next_Z > last_z + EPSILON)
- m_ranges.emplace_back(t_layer_height_range(last_z, next_Z), cfg);
- }
-
- if (m_ranges.empty())
- m_ranges.emplace_back(t_layer_height_range(0, DBL_MAX), nullptr);
- else if (m_ranges.back().second == nullptr)
- m_ranges.back().first.second = DBL_MAX;
- else if (m_ranges.back().first.second != DBL_MAX)
- m_ranges.emplace_back(t_layer_height_range(m_ranges.back().first.second, DBL_MAX), nullptr);
- }
const DynamicPrintConfig* config(const t_layer_height_range &range) const {
auto it = std::lower_bound(m_ranges.begin(), m_ranges.end(), std::make_pair< t_layer_height_range, const DynamicPrintConfig*>(t_layer_height_range(range.first - EPSILON, range.second - EPSILON), nullptr));
// #ys_FIXME_COLOR
@@ -733,17 +722,18 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
for (const ModelObject *model_object : m_model.objects)
model_object_status.emplace(model_object->id(), ModelObjectStatus::New);
} else {
+ if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
+ update_apply_status(custom_per_printz_gcodes_tool_changes_differ(m_model.custom_gcode_per_print_z.gcodes, model.custom_gcode_per_print_z.gcodes) ?
+ // The Tool Ordering and the Wipe Tower are no more valid.
+ this->invalidate_steps({ psWipeTower, psGCodeExport }) :
+ // There is no change in Tool Changes stored in custom_gcode_per_print_z, therefore there is no need to update Tool Ordering.
+ this->invalidate_step(psGCodeExport));
+ m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
+ }
if (model_object_list_equal(m_model, model)) {
// The object list did not change.
for (const ModelObject *model_object : m_model.objects)
model_object_status.emplace(model_object->id(), ModelObjectStatus::Old);
-
- // But if custom gcode per layer height was changed
- if (m_model.custom_gcode_per_print_z != model.custom_gcode_per_print_z) {
- // we should stop background processing
- update_apply_status(this->invalidate_step(psGCodeExport));
- m_model.custom_gcode_per_print_z = model.custom_gcode_per_print_z;
- }
} else if (model_object_list_extended(m_model, model)) {
// Add new objects. Their volumes and configs will be synchronized later.
update_apply_status(this->invalidate_step(psGCodeExport));
@@ -835,9 +825,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
for (PrintObject *print_object : m_objects)
print_object_status.emplace(PrintObjectStatus(print_object));
- std::vector<std::pair<double, DynamicPrintConfig>> custom_tool_changes =
- m_model.get_custom_tool_changes(m_default_object_config.layer_height, num_extruders);
-
// 3) Synchronize ModelObjects & PrintObjects.
for (size_t idx_model_object = 0; idx_model_object < model.objects.size(); ++ idx_model_object) {
ModelObject &model_object = *m_model.objects[idx_model_object];
@@ -845,9 +832,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
assert(it_status != model_object_status.end());
assert(it_status->status != ModelObjectStatus::Deleted);
const ModelObject& model_object_new = *model.objects[idx_model_object];
- // ys_FIXME_COLOR
- // const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
- const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges, custom_tool_changes);
+ const_cast<ModelObjectStatus&>(*it_status).layer_ranges.assign(model_object_new.layer_config_ranges);
if (it_status->status == ModelObjectStatus::New)
// PrintObject instances will be added in the next loop.
continue;
@@ -1015,8 +1000,6 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
PrintRegionConfig this_region_config;
bool this_region_config_set = false;
for (PrintObject *print_object : m_objects) {
- if(m_force_update_print_regions && !custom_tool_changes.empty())
- goto print_object_end;
const LayerRanges *layer_ranges;
{
auto it_status = model_object_status.find(ModelObjectStatus(print_object->model_object()->id()));
@@ -1572,9 +1555,13 @@ void Print::process()
obj->generate_support_material();
if (this->set_started(psWipeTower)) {
m_wipe_tower_data.clear();
+ m_tool_ordering.clear();
if (this->has_wipe_tower()) {
//this->set_status(95, L("Generating wipe tower"));
this->_make_wipe_tower();
+ } else if (! this->config().complete_objects.value) {
+ // Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
+ m_tool_ordering = ToolOrdering(*this, -1, false);
}
this->set_done(psWipeTower);
}
@@ -1963,8 +1950,8 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt, double first_l
// If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default.
if (! is_step_done(psWipeTower) && extruders_cnt !=0) {
- float width = m_config.wipe_tower_width;
- float brim_spacing = nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4);
+ float width = float(m_config.wipe_tower_width);
+ float brim_spacing = float(nozzle_diameter * 1.25f - first_layer_height * (1. - M_PI_4));
const_cast<Print*>(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1);
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = 4.5f * brim_spacing;
@@ -1990,6 +1977,7 @@ void Print::_make_wipe_tower()
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
+
if (! m_wipe_tower_data.tool_ordering.has_wipe_tower())
// Don't generate any wipe tower.
return;
@@ -2107,13 +2095,6 @@ void Print::_make_wipe_tower()
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
}
-// Returns extruder this eec should be printed with, according to PrintRegion config
-int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion &region)
-{
- return is_infill(fill.role()) ? std::max<int>(0, (is_solid_infill(fill.entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) :
- std::max<int>(region.config().perimeter_extruder.value - 1, 0);
-}
-
// Generate a recommended G-code output file name based on the format template, default extension, and template parameters
// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before G-code is finalized).
diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp
index 95c7b656a..53a6f97b9 100644
--- a/src/libslic3r/Print.hpp
+++ b/src/libslic3r/Print.hpp
@@ -15,6 +15,8 @@
#include "GCode/ThumbnailData.hpp"
#endif // ENABLE_THUMBNAIL_GENERATOR
+#include "libslic3r.h"
+
namespace Slic3r {
class Print;
@@ -25,8 +27,19 @@ class GCodePreviewData;
// Print step IDs for keeping track of the print state.
enum PrintStep {
- psSkirt, psBrim, psWipeTower, psGCodeExport, psCount,
+ psSkirt,
+ psBrim,
+ // Synonym for the last step before the Wipe Tower / Tool Ordering, for the G-code preview slider to understand that
+ // all the extrusions are there for the layer slider to add color changes etc.
+ psExtrusionPaths = psBrim,
+ psWipeTower,
+ // psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
+ // while if printing without the Wipe Tower, the ToolOrdering is calculated as well.
+ psToolOrdering = psWipeTower,
+ psGCodeExport,
+ psCount,
};
+
enum PrintObjectStep {
posSlice, posPerimeters, posPrepareInfill,
posInfill, posSupportMaterial, posCount,
@@ -50,7 +63,7 @@ public:
// Average diameter of nozzles participating on extruding this region.
coordf_t bridging_height_avg(const PrintConfig &print_config) const;
- // Collect extruder indices used to print this region's object.
+ // Collect 0-based extruder indices used to print this region's object.
void collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const;
static void collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig &region_config, std::vector<unsigned int> &object_extruders);
@@ -116,8 +129,21 @@ public:
size_t total_layer_count() const { return this->layer_count() + this->support_layer_count(); }
size_t layer_count() const { return m_layers.size(); }
void clear_layers();
- Layer* get_layer(int idx) { return m_layers[idx]; }
- const Layer* get_layer(int idx) const { return m_layers[idx]; }
+ const Layer* get_layer(int idx) const { return m_layers[idx]; }
+ Layer* get_layer(int idx) { return m_layers[idx]; }
+ // Get a layer exactly at print_z.
+ const Layer* get_layer_at_printz(coordf_t print_z) const {
+ auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
+ return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
+ }
+ Layer* get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
+ // Get a layer approximately at print_z.
+ const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
+ coordf_t limit = print_z + epsilon;
+ auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
+ return (it == m_layers.end() || (*it)->print_z < print_z - epsilon) ? nullptr : *it;
+ }
+ Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
// print_z: top of the layer; slice_z: center of the layer.
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
@@ -219,7 +245,7 @@ struct WipeTowerData
// Following section will be consumed by the GCodeGenerator.
// Tool ordering of a non-sequential print has to be known to calculate the wipe tower.
// Cache it here, so it does not need to be recalculated during the G-code generation.
- ToolOrdering tool_ordering;
+ ToolOrdering &tool_ordering;
// Cache of tool changes per print layer.
std::unique_ptr<std::vector<WipeTower::ToolChangeResult>> priming;
std::vector<std::vector<WipeTower::ToolChangeResult>> tool_changes;
@@ -232,7 +258,6 @@ struct WipeTowerData
float brim_width;
void clear() {
- tool_ordering.clear();
priming.reset(nullptr);
tool_changes.clear();
final_purge.reset(nullptr);
@@ -241,6 +266,14 @@ struct WipeTowerData
depth = 0.f;
brim_width = 0.f;
}
+
+private:
+ // Only allow the WipeTowerData to be instantiated internally by Print,
+ // as this WipeTowerData shares reference to Print::m_tool_ordering.
+ friend class Print;
+ WipeTowerData(ToolOrdering &tool_ordering) : tool_ordering(tool_ordering) { clear(); }
+ WipeTowerData(const WipeTowerData & /* rhs */) = delete;
+ WipeTowerData &operator=(const WipeTowerData & /* rhs */) = delete;
};
struct PrintStatistics
@@ -345,6 +378,7 @@ public:
const PrintConfig& config() const { return m_config; }
const PrintObjectConfig& default_object_config() const { return m_default_object_config; }
const PrintRegionConfig& default_region_config() const { return m_default_region_config; }
+ //FIXME returning const vector to non-const PrintObject*, caller could modify PrintObjects!
const PrintObjectPtrs& objects() const { return m_objects; }
PrintObject* get_object(size_t idx) { return m_objects[idx]; }
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
@@ -353,9 +387,6 @@ public:
// If zero, then the print is empty and the print shall not be executed.
unsigned int num_object_instances() const;
- // Returns extruder this eec should be printed with, according to PrintRegion config:
- static int get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion &region);
-
const ExtrusionEntityCollection& skirt() const { return m_skirt; }
const ExtrusionEntityCollection& brim() const { return m_brim; }
@@ -364,14 +395,13 @@ public:
// Wipe tower support.
bool has_wipe_tower() const;
const WipeTowerData& wipe_tower_data(size_t extruders_cnt = 0, double first_layer_height = 0., double nozzle_diameter = 0.) const;
+ const ToolOrdering& tool_ordering() const { return m_tool_ordering; }
std::string output_filename(const std::string &filename_base = std::string()) const override;
// Accessed by SupportMaterial
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
-
- // force update of PrintRegions, when custom_tool_change is not empty and (Re)Slicing is started
- void set_force_update_print_regions(bool force_update_print_regions) { m_force_update_print_regions = force_update_print_regions; }
+ const ToolOrdering& get_tool_ordering() const { return m_wipe_tower_data.tool_ordering; } // #ys_FIXME just for testing
protected:
// methods for handling regions
@@ -410,14 +440,12 @@ private:
ExtrusionEntityCollection m_brim;
// Following section will be consumed by the GCodeGenerator.
- WipeTowerData m_wipe_tower_data;
+ ToolOrdering m_tool_ordering;
+ WipeTowerData m_wipe_tower_data {m_tool_ordering};
// Estimated print time, filament consumed.
PrintStatistics m_print_statistics;
- // flag used
- bool m_force_update_print_regions = false;
-
// To allow GCode to set the Print's GCodeExport step status.
friend class GCode;
// Allow PrintObject to access m_mutex and m_cancel_callback.
diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp
index 8199bde03..2a32ba5ef 100644
--- a/src/libslic3r/Slicing.cpp
+++ b/src/libslic3r/Slicing.cpp
@@ -300,26 +300,14 @@ std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slici
layer_height_profile.push_back(print_z);
layer_height_profile.push_back(height);
print_z += height;
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- layer_height_profile.push_back(print_z);
- layer_height_profile.push_back(height);
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
double z_gap = slicing_params.object_print_z_height() - layer_height_profile[layer_height_profile.size() - 2];
if (z_gap > 0.0)
{
layer_height_profile.push_back(slicing_params.object_print_z_height());
layer_height_profile.push_back(clamp(slicing_params.min_layer_height, slicing_params.max_layer_height, z_gap));
}
-#else
- double last = std::max(slicing_params.first_object_layer_height, layer_height_profile[layer_height_profile.size() - 2]);
- layer_height_profile.push_back(last);
- layer_height_profile.push_back(slicing_params.first_object_layer_height);
- layer_height_profile.push_back(slicing_params.object_print_z_height());
- layer_height_profile.push_back(slicing_params.first_object_layer_height);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
return layer_height_profile;
}
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 23c516a34..be1fbd001 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -41,24 +41,6 @@
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
-// Enable adaptive layer height profile
-#define ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE (1 && ENABLE_2_2_0_ALPHA1)
-
-// Enable grayed variant for gizmos icons in non activable state
-#define ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE (1 && ENABLE_2_2_0_ALPHA1)
-
-// Enable fix for view toolbar background not showing up on Mac with dark mode
-#define ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX (1 && ENABLE_2_2_0_ALPHA1)
-
-// Enable selection for missing files in reload from disk command
-#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1)
-
-// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
-#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
-
-// Enable not applying volume transformation during 3mf and amf loading, but keeping it as a ModelVolume member
-#define ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE (1 && ENABLE_2_2_0_ALPHA1)
-
//==================
// 2.2.0.beta1 techs
diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h
index afbf94fa3..d3e4992ce 100644
--- a/src/libslic3r/libslic3r.h
+++ b/src/libslic3r/libslic3r.h
@@ -158,6 +158,53 @@ inline std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
+// Variant of std::lower_bound() with compare predicate, but without the key.
+// This variant is very useful in case that the T type is large or it does not even have a public constructor.
+template<class ForwardIt, class LowerThanKeyPredicate>
+ForwardIt lower_bound_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key)
+{
+ ForwardIt it;
+ typename std::iterator_traits<ForwardIt>::difference_type count, step;
+ count = std::distance(first, last);
+
+ while (count > 0) {
+ it = first;
+ step = count / 2;
+ std::advance(it, step);
+ if (lower_thank_key(*it)) {
+ first = ++it;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+ return first;
+}
+
+// from https://en.cppreference.com/w/cpp/algorithm/lower_bound
+template<class ForwardIt, class T, class Compare=std::less<>>
+ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
+{
+ // Note: BOTH type T and the type after ForwardIt is dereferenced
+ // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
+ // This is stricter than lower_bound requirement (see above)
+
+ first = std::lower_bound(first, last, value, comp);
+ return first != last && !comp(value, *first) ? first : last;
+}
+
+// from https://en.cppreference.com/w/cpp/algorithm/lower_bound
+template<class ForwardIt, class LowerThanKeyPredicate, class EqualToKeyPredicate>
+ForwardIt binary_find_by_predicate(ForwardIt first, ForwardIt last, LowerThanKeyPredicate lower_thank_key, EqualToKeyPredicate equal_to_key)
+{
+ // Note: BOTH type T and the type after ForwardIt is dereferenced
+ // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
+ // This is stricter than lower_bound requirement (see above)
+
+ first = lower_bound_by_predicate(first, last, lower_thank_key);
+ return first != last && equal_to_key(*first) ? first : last;
+}
+
template<typename T>
static inline T sqr(T x)
{
diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp
index 9e32df783..beb0a6577 100644
--- a/src/slic3r/GUI/3DBed.cpp
+++ b/src/slic3r/GUI/3DBed.cpp
@@ -335,24 +335,10 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
printf("Unable to create bed grid lines\n");
}
-static const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
-{
- const VendorProfile::PrinterModel *out = nullptr;
- if (preset.vendor != nullptr) {
- auto *printer_model = preset.config.opt<ConfigOptionString>("printer_model");
- if (printer_model != nullptr && ! printer_model->value.empty()) {
- auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; });
- if (it != preset.vendor->models.end())
- out = &(*it);
- }
- }
- return out;
-}
-
static std::string system_print_bed_model(const Preset &preset)
{
std::string out;
- const VendorProfile::PrinterModel *pm = system_printer_model(preset);
+ const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && ! pm->bed_model.empty())
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model;
return out;
@@ -361,7 +347,7 @@ static std::string system_print_bed_model(const Preset &preset)
static std::string system_print_bed_texture(const Preset &preset)
{
std::string out;
- const VendorProfile::PrinterModel *pm = system_printer_model(preset);
+ const VendorProfile::PrinterModel *pm = PresetUtils::system_printer_model(preset);
if (pm != nullptr && ! pm->bed_texture.empty())
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
return out;
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index bbfcabd36..f6b1719db 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -877,13 +877,10 @@ bool can_export_to_obj(const GLVolume& volume)
if (!volume.is_active || !volume.is_extrusion_path)
return false;
- if (volume.indexed_vertex_array.triangle_indices.empty() && (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) == 0))
- return false;
-
- if (volume.indexed_vertex_array.quad_indices.empty() && (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) == 0))
- return false;
+ bool has_triangles = !volume.indexed_vertex_array.triangle_indices.empty() || (std::min(volume.indexed_vertex_array.triangle_indices_size, volume.tverts_range.second - volume.tverts_range.first) > 0);
+ bool has_quads = !volume.indexed_vertex_array.quad_indices.empty() || (std::min(volume.indexed_vertex_array.quad_indices_size, volume.qverts_range.second - volume.qverts_range.first) > 0);
- return true;
+ return has_triangles || has_quads;
}
bool GLVolumeCollection::has_toolpaths_to_export() const
diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp
index bcd79274f..d277fc095 100644
--- a/src/slic3r/GUI/AppConfig.cpp
+++ b/src/slic3r/GUI/AppConfig.cpp
@@ -63,7 +63,7 @@ void AppConfig::set_defaults()
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
if (get("export_sources_full_pathnames").empty())
- set("export_sources_full_pathnames", "1");
+ set("export_sources_full_pathnames", "0");
#endif // ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
// remove old 'use_legacy_opengl' parameter from this config, if present
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 9d6a2a5ec..8af721f9d 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -95,14 +95,6 @@ void BackgroundSlicingProcess::process_fff()
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
#endif // ENABLE_THUMBNAIL_GENERATOR
- /* #ys_FIXME_no_exported_codes
- if (m_fff_print->model().custom_gcode_per_print_z != GUI::wxGetApp().model().custom_gcode_per_print_z) {
- GUI::wxGetApp().model().custom_gcode_per_print_z = m_fff_print->model().custom_gcode_per_print_z;
- GUI::show_info(nullptr, _(L("To except of redundant tool manipulation, \n"
- "Color change(s) for unused extruder(s) was(were) deleted")), _(L("Info")));
- }
- */
-
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
//FIXME localize the messages
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
index a66dcf39c..984686e35 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
@@ -132,11 +132,6 @@ public:
// This "finished" flag does not account for the final export of the output file (.gcode or zipped PNGs),
// and it does not account for the OctoPrint scheduling.
bool finished() const { return m_print->finished(); }
-
- void set_force_update_print_regions(bool force_update_print_regions) {
- if (m_fff_print)
- m_fff_print->set_force_update_print_regions(force_update_print_regions);
- }
private:
void thread_proc();
diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp
index f7cefe72b..7322a88d1 100644
--- a/src/slic3r/GUI/BitmapCache.cpp
+++ b/src/slic3r/GUI/BitmapCache.cpp
@@ -1,6 +1,7 @@
#include "BitmapCache.hpp"
#include "libslic3r/Utils.hpp"
+#include <boost/filesystem.hpp>
#if ! defined(WIN32) && ! defined(__APPLE__)
#define BROKEN_ALPHA
@@ -15,7 +16,7 @@
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvg/nanosvgrast.h"
-#include "GUI_App.hpp"
+//#include "GUI_App.hpp"
namespace Slic3r { namespace GUI {
@@ -226,7 +227,7 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width,
}
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height,
- float scale /* = 1.0f */, const bool grayscale/* = false*/)
+ float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
{
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
"-h" + std::to_string(target_height) :
@@ -234,16 +235,45 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
+ (scale != 1.0f ? "-s" + std::to_string(scale) : "")
+ (grayscale ? "-gs" : "");
- target_height != 0 ? target_height *= scale : target_width *= scale;
+ /* For the Dark mode of any platform, we should draw icons in respect to OS background
+ * Note: All standard(regular) icons are collected in "icons" folder,
+ * SVG-icons, which have "Dark mode" variant, are collected in "icons/white" folder
+ */
+ std::string folder;
+ if (dark_mode)
+ {
+#ifdef __WXMSW__
+ folder = "white\\";
+#else
+ folder = "white/";
+#endif
+ auto it = m_map.find(folder + bitmap_key);
+ if (it != m_map.end())
+ return it->second;
+ else {
+ it = m_map.find(bitmap_key);
+ if (it != m_map.end())
+ return it->second;
+ }
- auto it = m_map.find(bitmap_key);
- if (it != m_map.end())
- return it->second;
+ if (!boost::filesystem::exists(Slic3r::var(folder + bitmap_name + ".svg")))
+ folder.clear();
+ else
+ bitmap_key = folder + bitmap_key;
+ }
+ else
+ {
+ auto it = m_map.find(bitmap_key);
+ if (it != m_map.end())
+ return it->second;
+ }
- NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f);
+ NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(folder + bitmap_name + ".svg").c_str(), "px", 96.0f);
if (image == nullptr)
return nullptr;
+ target_height != 0 ? target_height *= scale : target_width *= scale;
+
float svg_scale = target_height != 0 ?
(float)target_height / image->height : target_width != 0 ?
(float)target_width / image->width : 1;
diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp
index ce77057c8..041e7d892 100644
--- a/src/slic3r/GUI/BitmapCache.hpp
+++ b/src/slic3r/GUI/BitmapCache.hpp
@@ -34,7 +34,7 @@ public:
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false);
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
- wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false);
+ wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false);
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp
index 75d170b03..add680a40 100644
--- a/src/slic3r/GUI/ConfigWizard.cpp
+++ b/src/slic3r/GUI/ConfigWizard.cpp
@@ -350,6 +350,21 @@ bool PrinterPicker::any_selected() const
return false;
}
+std::set<std::string> PrinterPicker::get_selected_models() const
+{
+ std::set<std::string> ret_set;
+
+ for (const auto& cb : cboxes)
+ if (cb->GetValue())
+ ret_set.emplace(cb->model);
+
+ for (const auto& cb : cboxes_alt)
+ if (cb->GetValue())
+ ret_set.emplace(cb->model);
+
+ return ret_set;
+}
+
void PrinterPicker::on_checkbox(const Checkbox *cbox, bool checked)
{
PrinterPickerEvent evt(EVT_PRINTER_PICK, GetId(), vendor_id, cbox->model, cbox->variant, checked);
@@ -500,6 +515,19 @@ bool PagePrinters::any_selected() const
return false;
}
+std::set<std::string> PagePrinters::get_selected_models()
+{
+ std::set<std::string> ret_set;
+
+ for (const auto *picker : printer_pickers)
+ {
+ std::set<std::string> tmp_models = picker->get_selected_models();
+ ret_set.insert(tmp_models.begin(), tmp_models.end());
+ }
+
+ return ret_set;
+}
+
void PagePrinters::set_run_reason(ConfigWizard::RunReason run_reason)
{
if (technology == T_FFF
@@ -768,7 +796,7 @@ PageUpdate::PageUpdate(ConfigWizard *parent)
#if ENABLE_CONFIGURABLE_PATHS_EXPORT_TO_3MF_AND_AMF
PageReloadFromDisk::PageReloadFromDisk(ConfigWizard* parent)
: ConfigWizardPage(parent, _(L("Reload from disk")), _(L("Reload from disk")))
- , full_pathnames(true)
+ , full_pathnames(false)
{
auto* box_pathnames = new wxCheckBox(this, wxID_ANY, _(L("Export full pathnames of models and parts sources into 3mf and amf files")));
box_pathnames->SetValue(wxGetApp().app_config->get("export_sources_full_pathnames") == "1");
@@ -1600,6 +1628,10 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
preset.is_visible = evt.enable;
}
}
+
+ // if at list one printer is selected but there in no one selected material,
+ // select materials which is default for selected printer(s)
+ select_default_materials_if_needed(pair.second.vendor_profile, page->technology, evt.model_id);
}
if (page->technology & T_FFF) {
@@ -1609,6 +1641,57 @@ void ConfigWizard::priv::on_printer_pick(PagePrinters *page, const PrinterPicker
}
}
+void ConfigWizard::priv::select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel>& models, Technology technology, const std::string& model_id)
+{
+ PageMaterials* page_materials = technology & T_FFF ? page_filaments : page_sla_materials;
+
+ auto it = std::find_if(models.begin(), models.end(), [model_id](VendorProfile::PrinterModel model) {return model_id == model.id; });
+ if (it != models.end())
+ for (const std::string& material : it->default_materials)
+ appconfig_new.set(page_materials->materials->appconfig_section(), material, "1");
+}
+
+void ConfigWizard::priv::select_default_materials_if_needed(VendorProfile* vendor_profile, Technology technology, const std::string& model_id)
+{
+ if ((technology & T_FFF && !any_fff_selected) ||
+ (technology & T_SLA && !any_sla_selected) ||
+ check_materials_in_config(technology, false))
+ return;
+
+ select_default_materials_for_printer_model(vendor_profile->models, technology, model_id);
+}
+
+void ConfigWizard::priv::selected_default_materials(Technology technology)
+{
+ auto select_default_materials_for_printer_page = [this](PagePrinters * page_printers, Technology technology)
+ {
+ std::set<std::string> selected_models = page_printers->get_selected_models();
+ const std::string vendor_id = page_printers->get_vendor_id();
+
+ for (auto& pair : bundles)
+ {
+ if (pair.first != vendor_id)
+ continue;
+
+ for (const std::string& model_id : selected_models)
+ select_default_materials_for_printer_model(pair.second.vendor_profile->models, technology, model_id);
+ }
+ };
+
+ PagePrinters* page_printers = technology & T_FFF ? page_fff : page_msla;
+ select_default_materials_for_printer_page(page_printers, technology);
+
+ for (const auto& printer : pages_3rdparty)
+ {
+ page_printers = technology & T_FFF ? printer.second.first : printer.second.second;
+ if (page_printers)
+ select_default_materials_for_printer_page(page_printers, technology);
+ }
+
+ update_materials(technology);
+ (technology& T_FFF ? page_filaments : page_sla_materials)->reload_presets();
+}
+
void ConfigWizard::priv::on_3rdparty_install(const VendorProfile *vendor, bool install)
{
auto it = pages_3rdparty.find(vendor->id);
@@ -1645,7 +1728,7 @@ bool ConfigWizard::priv::on_bnt_finish()
return check_materials_in_config(T_ANY);
}
-bool ConfigWizard::priv::check_materials_in_config(Technology technology)
+bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool show_info_msg)
{
const auto exist_preset = [this](const std::string& section, const Materials& materials)
{
@@ -1660,15 +1743,32 @@ bool ConfigWizard::priv::check_materials_in_config(Technology technology)
return false;
};
+ const auto ask_and_selected_default_materials = [this](wxString message, Technology technology)
+ {
+ wxMessageDialog msg(q, message, _(L("Notice")), wxYES_NO);
+ if (msg.ShowModal() == wxID_YES)
+ selected_default_materials(technology);
+ };
+
if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments))
{
- show_info(q, _(L("You have to select at least one filament for selected printers")), "");
+ if (show_info_msg)
+ {
+ wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
+ _(L("Do you want to automatic select default filaments?"));
+ ask_and_selected_default_materials(message, T_FFF);
+ }
return false;
}
if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials))
{
- show_info(q, _(L("You have to select at least one material for selected printers")), "");
+ if (show_info_msg)
+ {
+ wxString message = _(L("You have to select at least one material for selected printers")) + "\n\n\t" +
+ _(L("Do you want to automatic select default materials?"));
+ ask_and_selected_default_materials(message, T_SLA);
+ }
return false;
}
diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp
index 3ea5321f8..9c14633c9 100644
--- a/src/slic3r/GUI/ConfigWizard_private.hpp
+++ b/src/slic3r/GUI/ConfigWizard_private.hpp
@@ -149,6 +149,7 @@ struct PrinterPicker: wxPanel
void select_all(bool select, bool alternates = false);
void select_one(size_t i, bool select);
bool any_selected() const;
+ std::set<std::string> get_selected_models() const ;
int get_width() const { return width; }
const std::vector<int>& get_button_indexes() { return m_button_indexes; }
@@ -215,6 +216,9 @@ struct PagePrinters: ConfigWizardPage
void select_all(bool select, bool alternates = false);
int get_width() const;
bool any_selected() const;
+ std::set<std::string> get_selected_models();
+
+ std::string get_vendor_id() const { return printer_pickers.empty() ? "" : printer_pickers[0]->vendor_id; }
virtual void set_run_reason(ConfigWizard::RunReason run_reason) override;
};
@@ -503,10 +507,17 @@ struct ConfigWizard::priv
void on_custom_setup();
void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt);
+ void select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel> &models,
+ Technology technology,
+ const std::string & model_id);
+ void select_default_materials_if_needed(VendorProfile* vendor_profile,
+ Technology technology,
+ const std::string &model_id);
+ void selected_default_materials(Technology technology);
void on_3rdparty_install(const VendorProfile *vendor, bool install);
bool on_bnt_finish();
- bool check_materials_in_config(Technology technology);
+ bool check_materials_in_config(Technology technology, bool show_info_msg = true);
void apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater);
// #ys_FIXME_alise
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index d2428cf96..ce4908c38 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -132,9 +132,7 @@ GLCanvas3D::LayersEditing::LayersEditing()
, m_object_max_z(0.f)
, m_slicing_parameters(nullptr)
, m_layer_height_profile_modified(false)
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, m_adaptive_quality(0.5f)
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
, state(Unknown)
, band_width(2.0f)
, strength(0.005f)
@@ -155,9 +153,6 @@ GLCanvas3D::LayersEditing::~LayersEditing()
}
const float GLCanvas3D::LayersEditing::THICKNESS_BAR_WIDTH = 70.0f;
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-const float GLCanvas3D::LayersEditing::THICKNESS_RESET_BUTTON_HEIGHT = 22.0f;
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
{
@@ -224,7 +219,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
if (!m_enabled)
return;
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
const Size& cnv_size = canvas.get_canvas_size();
@@ -319,13 +313,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
imgui.end();
const Rect& bar_rect = get_bar_rect_viewport(canvas);
-#else
- const Rect& bar_rect = get_bar_rect_viewport(canvas);
- const Rect& reset_rect = get_reset_rect_viewport(canvas);
-
- _render_tooltip_texture(canvas, bar_rect, reset_rect);
- _render_reset_texture(reset_rect);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
render_active_object_annotations(canvas, bar_rect);
render_profile(bar_rect);
}
@@ -352,38 +339,15 @@ bool GLCanvas3D::LayersEditing::bar_rect_contains(const GLCanvas3D& canvas, floa
return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
}
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-bool GLCanvas3D::LayersEditing::reset_rect_contains(const GLCanvas3D& canvas, float x, float y)
-{
- const Rect& rect = get_reset_rect_screen(canvas);
- return (rect.get_left() <= x) && (x <= rect.get_right()) && (rect.get_top() <= y) && (y <= rect.get_bottom());
-}
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-
Rect GLCanvas3D::LayersEditing::get_bar_rect_screen(const GLCanvas3D& canvas)
{
const Size& cnv_size = canvas.get_canvas_size();
float w = (float)cnv_size.get_width();
float h = (float)cnv_size.get_height();
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
return Rect(w - thickness_bar_width(canvas), 0.0f, w, h);
-#else
- return Rect(w - thickness_bar_width(canvas), 0.0f, w, h - reset_button_height(canvas));
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
}
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-Rect GLCanvas3D::LayersEditing::get_reset_rect_screen(const GLCanvas3D& canvas)
-{
- const Size& cnv_size = canvas.get_canvas_size();
- float w = (float)cnv_size.get_width();
- float h = (float)cnv_size.get_height();
-
- return Rect(w - thickness_bar_width(canvas), h - reset_button_height(canvas), w, h);
-}
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-
Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
{
const Size& cnv_size = canvas.get_canvas_size();
@@ -393,26 +357,8 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas)
float zoom = (float)canvas.get_camera().get_zoom();
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
-#else
- return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-}
-
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas)
-{
- const Size& cnv_size = canvas.get_canvas_size();
- float half_w = 0.5f * (float)cnv_size.get_width();
- float half_h = 0.5f * (float)cnv_size.get_height();
-
- float zoom = (float)canvas.get_camera().get_zoom();
- float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
-
- return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom);
}
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
bool GLCanvas3D::LayersEditing::is_initialized() const
{
@@ -448,54 +394,6 @@ std::string GLCanvas3D::LayersEditing::get_tooltip(const GLCanvas3D& canvas) con
return ret;
}
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const
-{
- // TODO: do this with ImGui
-
- if (m_tooltip_texture.get_id() == 0)
- {
- std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png";
- if (!m_tooltip_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
- return;
- }
-
-#if ENABLE_RETINA_GL
- const float scale = canvas.get_canvas_size().get_scale_factor();
-#else
- const float scale = canvas.get_wxglcanvas()->GetContentScaleFactor();
-#endif
- const float width = (float)m_tooltip_texture.get_width() * scale;
- const float height = (float)m_tooltip_texture.get_height() * scale;
-
- float zoom = (float)canvas.get_camera().get_zoom();
- float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
- float gap = 10.0f * inv_zoom;
-
- float bar_left = bar_rect.get_left();
- float reset_bottom = reset_rect.get_bottom();
-
- float l = bar_left - width * inv_zoom - gap;
- float r = bar_left - gap;
- float t = reset_bottom + height * inv_zoom + gap;
- float b = reset_bottom + gap;
-
- GLTexture::render_texture(m_tooltip_texture.get_id(), l, r, b, t);
-}
-
-void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) const
-{
- if (m_reset_texture.get_id() == 0)
- {
- std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png";
- if (!m_reset_texture.load_from_file(filename, false, GLTexture::SingleThreaded, false))
- return;
- }
-
- GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top());
-}
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-
void GLCanvas3D::LayersEditing::render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
{
m_shader.start_using();
@@ -644,7 +542,6 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
{
this->update_slicing_parameters();
@@ -662,7 +559,6 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas,
m_layers_texture.valid = false;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
{
@@ -725,19 +621,6 @@ float GLCanvas3D::LayersEditing::thickness_bar_width(const GLCanvas3D &canvas)
* THICKNESS_BAR_WIDTH;
}
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-float GLCanvas3D::LayersEditing::reset_button_height(const GLCanvas3D &canvas)
-{
- return
-#if ENABLE_RETINA_GL
- canvas.get_canvas_size().get_scale_factor()
-#else
- canvas.get_wxglcanvas()->GetContentScaleFactor()
-#endif
- * THICKNESS_RESET_BUTTON_HEIGHT;
-}
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
-
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
const Vec3d GLCanvas3D::Mouse::Drag::Invalid_3D_Point(DBL_MAX, DBL_MAX, DBL_MAX);
@@ -1011,7 +894,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::vector<float>& colors,
std::vector<std::string>& cp_legend_items)
{
- std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z;
+ std::vector<Model::CustomGCode> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
if (extruders_cnt == 1)
@@ -1349,9 +1232,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const
}
}
-#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
-wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
-#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
@@ -1375,11 +1255,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
#if ENABLE_THUMBNAIL_GENERATOR
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
@@ -1521,10 +1399,6 @@ bool GLCanvas3D::init()
if (m_selection.is_enabled() && !m_selection.init())
return false;
-#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
- post_event(SimpleEvent(EVT_GLCANVAS_INIT));
-#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
-
m_initialized = true;
return true;
@@ -1681,7 +1555,6 @@ bool GLCanvas3D::is_layers_editing_allowed() const
return m_layers_editing.is_allowed();
}
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void GLCanvas3D::reset_layer_height_profile()
{
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Reset")));
@@ -1705,7 +1578,6 @@ void GLCanvas3D::smooth_layer_height_profile(const HeightProfileSmoothingParams&
m_layers_editing.state = LayersEditing::Completed;
m_dirty = true;
}
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
bool GLCanvas3D::is_reload_delayed() const
{
@@ -1927,11 +1799,7 @@ void GLCanvas3D::render()
m_camera.debug_render();
#endif // ENABLE_CAMERA_STATISTICS
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
-#else
- wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
wxGetApp().imgui()->render();
@@ -2427,7 +2295,7 @@ static void load_gcode_retractions(const GCodePreviewData::Retraction& retractio
volume_index.first_volumes.emplace_back(extrusion_type, 0, (unsigned int)volumes.volumes.size());
- GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba, VERTEX_BUFFER_RESERVE_SIZE);
+ GLVolume *volume = volumes.new_nontoolpath_volume(retractions.color.rgba.data(), VERTEX_BUFFER_RESERVE_SIZE);
GCodePreviewData::Retraction::PositionsList copy(retractions.positions);
std::sort(copy.begin(), copy.end(), [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2) { return p1.position(2) < p2.position(2); });
@@ -3117,20 +2985,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_layers_editing.state = LayersEditing::Editing;
_perform_layer_editing_action(&evt);
}
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- else if ((layer_editing_object_idx != -1) && m_layers_editing.reset_rect_contains(*this, pos(0), pos(1)))
- {
- if (evt.LeftDown())
- {
- // A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
- m_layers_editing.reset_layer_height_profile(*this);
- // Index 2 means no editing, just wait for mouse up event.
- m_layers_editing.state = LayersEditing::Completed;
-
- m_dirty = true;
- }
- }
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
else if (evt.LeftDown() && (evt.ShiftDown() || evt.AltDown()) && m_picking_enabled)
{
if (m_gizmos.get_current_type() != GLGizmosManager::SlaSupports)
@@ -4233,10 +4087,8 @@ bool GLCanvas3D::_init_toolbars()
if (!_init_undoredo_toolbar())
return false;
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
if (!_init_view_toolbar())
return false;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
return true;
}
@@ -4495,12 +4347,10 @@ bool GLCanvas3D::_init_undoredo_toolbar()
return true;
}
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool GLCanvas3D::_init_view_toolbar()
{
return wxGetApp().plater()->init_view_toolbar();
}
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool GLCanvas3D::_set_current()
{
@@ -5413,11 +5263,11 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
const std::string& code = it->gcode;
// pause print or custom Gcode
if (code == PausePrintCode ||
- (code != ColorChangeCode && code != ExtruderChangeCode))
+ (code != ColorChangeCode && code != ToolChangeCode))
return number_tools()-1; // last color item is a gray color for pause print or custom G-code
// change tool (extruder)
- if (code == ExtruderChangeCode)
+ if (code == ToolChangeCode)
return get_color_idx_for_tool_change(it, extruder);
// change color for current extruder
if (code == ColorChangeCode) {
@@ -5439,7 +5289,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
return color_idx;
}
// change tool (extruder)
- if (it->gcode == ExtruderChangeCode)
+ if (it->gcode == ToolChangeCode)
return get_color_idx_for_tool_change(it, extruder);
}
@@ -5483,7 +5333,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
bool is_tool_change = false;
while (it_n != color_print_values->begin()) {
--it_n;
- if (it_n->gcode == ExtruderChangeCode) {
+ if (it_n->gcode == ToolChangeCode) {
is_tool_change = true;
if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == extruder))
return get_m600_color_idx(it);
@@ -5863,7 +5713,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
return 0.0f;
}
- static GCodePreviewData::Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
+ static Color path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
{
switch (data.extrusion.view_type)
{
@@ -5881,8 +5731,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
return data.get_volumetric_rate_color(value);
case GCodePreviewData::Extrusion::Tool:
{
- GCodePreviewData::Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
+ Color color;
+ ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
return color;
}
case GCodePreviewData::Extrusion::ColorPrint:
@@ -5890,16 +5740,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
int color_cnt = (int)tool_colors.size() / 4;
int val = value > color_cnt ? color_cnt - 1 : value;
- GCodePreviewData::Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
+ Color color;
+ ::memcpy((void*)color.rgba.data(), (const void*)(tool_colors.data() + val * 4), 4 * sizeof(float));
return color;
}
default:
- return GCodePreviewData::Color::Dummy;
+ return Color{};
}
- return GCodePreviewData::Color::Dummy;
+ return Color{};
}
};
@@ -5942,7 +5792,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
if (! values.empty()) {
m_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, role, (unsigned int)m_volumes.volumes.size());
for (const float value : values)
- roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba, vertex_buffer_prealloc_size));
+ roles_filters.back().emplace_back(value, m_volumes.new_toolpath_volume(Helper::path_color(preview_data, tool_colors, value).rgba.data(), vertex_buffer_prealloc_size));
}
}
}
@@ -6025,7 +5875,7 @@ inline void travel_paths_internal(
by_type.reserve(values.size());
// creates a new volume for each feedrate
for (TYPE type : values)
- by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba, VERTEX_BUFFER_RESERVE_SIZE));
+ by_type.emplace_back(type, volumes.new_nontoolpath_volume(func_color(type).rgba.data(), VERTEX_BUFFER_RESERVE_SIZE));
}
// populates volumes
@@ -6072,19 +5922,19 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data,
case GCodePreviewData::Extrusion::Feedrate:
travel_paths_internal<float>(preview_data,
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.feedrate; },
- [&preview_data](const float feedrate) -> const GCodePreviewData::Color { return preview_data.get_feedrate_color(feedrate); },
+ [&preview_data](const float feedrate) -> const Color { return preview_data.get_feedrate_color(feedrate); },
m_volumes, m_initialized);
break;
case GCodePreviewData::Extrusion::Tool:
travel_paths_internal<unsigned int>(preview_data,
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.extruder_id; },
- [&tool_colors](const unsigned int extruder_id) -> const GCodePreviewData::Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return GCodePreviewData::Color(tool_colors.data() + extruder_id * 4); },
+ [&tool_colors](const unsigned int extruder_id) -> const Color { assert((extruder_id + 1) * 4 <= tool_colors.size()); return Color(tool_colors.data() + extruder_id * 4); },
m_volumes, m_initialized);
break;
default:
travel_paths_internal<unsigned int>(preview_data,
[](const GCodePreviewData::Travel::Polyline &polyline) { return polyline.type; },
- [&preview_data](const unsigned int type) -> const GCodePreviewData::Color& { return preview_data.travel.type_colors[type]; },
+ [&preview_data](const unsigned int type) -> const Color& { return preview_data.travel.type_colors[type]; },
m_volumes, m_initialized);
break;
}
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index e07ccd7fd..d4386f7f3 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -83,9 +83,6 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
-#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
-wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
-#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
@@ -108,11 +105,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
class GLCanvas3D
{
@@ -162,17 +157,10 @@ private:
private:
static const float THICKNESS_BAR_WIDTH;
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- static const float THICKNESS_RESET_BUTTON_HEIGHT;
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
bool m_enabled;
Shader m_shader;
unsigned int m_z_texture_id;
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- mutable GLTexture m_tooltip_texture;
- mutable GLTexture m_reset_texture;
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// Not owned by LayersEditing.
const DynamicPrintConfig *m_config;
// ModelObject for the currently selected object (Model::objects[last_object_id]).
@@ -184,10 +172,8 @@ private:
std::vector<double> m_layer_height_profile;
bool m_layer_height_profile_modified;
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
mutable float m_adaptive_quality;
mutable HeightProfileSmoothingParams m_smooth_params;
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
class LayersTexture
{
@@ -235,24 +221,13 @@ private:
void adjust_layer_height_profile();
void accept_changes(GLCanvas3D& canvas);
void reset_layer_height_profile(GLCanvas3D& canvas);
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor);
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static float get_cursor_z_relative(const GLCanvas3D& canvas);
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- static bool reset_rect_contains(const GLCanvas3D& canvas, float x, float y);
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- static Rect get_reset_rect_screen(const GLCanvas3D& canvas);
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- static Rect get_reset_rect_viewport(const GLCanvas3D& canvas);
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
float object_max_z() const { return m_object_max_z; }
@@ -261,18 +236,11 @@ private:
private:
bool is_initialized() const;
void generate_layer_height_texture();
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const;
- void _render_reset_texture(const Rect& reset_rect) const;
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
void render_profile(const Rect& bar_rect) const;
void update_slicing_parameters();
static float thickness_bar_width(const GLCanvas3D &canvas);
-#if !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
- static float reset_button_height(const GLCanvas3D &canvas);
-#endif // !ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
};
struct Mouse
@@ -539,11 +507,9 @@ public:
bool is_layers_editing_enabled() const;
bool is_layers_editing_allowed() const;
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
void reset_layer_height_profile();
void adaptive_layer_height_profile(float quality_factor);
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
bool is_reload_delayed() const;
@@ -683,9 +649,7 @@ private:
bool _init_toolbars();
bool _init_main_toolbar();
bool _init_undoredo_toolbar();
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool _init_view_toolbar();
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool _set_current();
void _resize(unsigned int w, unsigned int h);
diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp
index 2834c9603..4ac69d71f 100644
--- a/src/slic3r/GUI/GLTexture.cpp
+++ b/src/slic3r/GUI/GLTexture.cpp
@@ -276,12 +276,12 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
float inv_255 = 1.0f / 255.0f;
// offset by 1 to leave the first pixel empty (both in x and y)
- for (int r = 1; r <= sprite_size_px; ++r)
+ for (unsigned int r = 1; r <= sprite_size_px; ++r)
{
- int offset_r = r * sprite_size_px_ex;
- for (int c = 1; c <= sprite_size_px; ++c)
+ unsigned int offset_r = r * sprite_size_px_ex;
+ for (unsigned int c = 1; c <= sprite_size_px; ++c)
{
- int offset = (offset_r + c) * 4;
+ unsigned int offset = (offset_r + c) * 4;
float alpha = (float)output_data.data()[offset + 3] * inv_255;
output_data.data()[offset + 0] = (unsigned char)(output_data.data()[offset + 0] * alpha);
output_data.data()[offset + 1] = (unsigned char)(output_data.data()[offset + 1] * alpha);
diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp
index bbc773de2..f53b8efb9 100644
--- a/src/slic3r/GUI/GLToolbar.hpp
+++ b/src/slic3r/GUI/GLToolbar.hpp
@@ -295,9 +295,7 @@ public:
bool is_any_item_pressed() const;
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
unsigned int get_items_count() const { return (unsigned int)m_items.size(); }
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
int get_item_id(const std::string& name) const;
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index 1a4d12d31..f7010a503 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -533,7 +533,9 @@ void Preview::on_combochecklist_features(wxCommandEvent& evt)
void Preview::on_checkbox_travel(wxCommandEvent& evt)
{
m_gcode_preview_data->travel.is_visible = m_checkbox_travel->IsChecked();
- refresh_print();
+ m_gcode_preview_data->ranges.feedrate.set_mode(GCodePreviewData::FeedrateKind::TRAVEL, m_gcode_preview_data->travel.is_visible);
+ // Rather than refresh, reload print so that speed color ranges get recomputed (affected by travel visibility)
+ reload_print();
}
void Preview::on_checkbox_retractions(wxCommandEvent& evt)
@@ -564,7 +566,7 @@ void Preview::update_view_type(bool slice_completed)
{
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
- const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.empty() /*&&
+ const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes.empty() /*&&
(wxGetApp().extruders_edited_cnt()==1 || !slice_completed) */?
_(L("Color Print")) :
config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values.size() > 1 ?
@@ -664,8 +666,11 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
- std::vector<Model::CustomGCode> &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
- check_slider_values(ticks_from_model, layers_z);
+ // Detect and set manipulation mode for double slider
+ update_double_slider_mode();
+
+ Model::CustomGCodeInfo &ticks_info_from_model = wxGetApp().plater()->model().custom_gcode_per_print_z;
+ check_slider_values(ticks_info_from_model.gcodes, layers_z);
m_slider->SetSliderValues(layers_z);
assert(m_slider->GetMinValue() == 0);
@@ -687,12 +692,61 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
}
m_slider->SetSelectionSpan(idx_low, idx_high);
- m_slider->SetTicksValues(ticks_from_model);
+ m_slider->SetTicksValues(ticks_info_from_model);
+
+ m_slider->EnableTickManipulation(wxGetApp().plater()->printer_technology() == ptFFF);
+}
+
+void Preview::update_double_slider_mode()
+{
+ // true -> single-extruder printer profile OR
+ // multi-extruder printer profile , but whole model is printed by only one extruder
+ // false -> multi-extruder printer profile , and model is printed by several extruders
+ bool one_extruder_printed_model = true;
- bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
+ // extruder used for whole model for multi-extruder printer profile
+ int only_extruder = -1;
+
+ if (wxGetApp().extruders_edited_cnt() > 1)
+ {
+ const ModelObjectPtrs& objects = wxGetApp().plater()->model().objects;
+
+ // check if whole model uses just only one extruder
+ if (!objects.empty())
+ {
+ const int extruder = objects[0]->config.has("extruder") ?
+ objects[0]->config.option("extruder")->getInt() : 0;
+
+ auto is_one_extruder_printed_model = [objects, extruder]()
+ {
+ for (ModelObject* object : objects)
+ {
+ if (object->config.has("extruder") &&
+ object->config.option("extruder")->getInt() != extruder)
+ return false;
+
+ if (object->volumes.size() > 1)
+ for (ModelVolume* volume : object->volumes)
+ if (volume->config.has("extruder") &&
+ volume->config.option("extruder")->getInt() != extruder)
+ return false;
+
+ for (const auto& range : object->layer_config_ranges)
+ if (range.second.has("extruder") &&
+ range.second.option("extruder")->getInt() != extruder)
+ return false;
+ }
+ return true;
+ };
+
+ if (is_one_extruder_printed_model())
+ only_extruder = extruder;
+ else
+ one_extruder_printed_model = false;
+ }
+ }
- m_slider->EnableTickManipulation(color_print_enable);
- m_slider->SetManipulationState(wxGetApp().extruders_edited_cnt());
+ m_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder);
}
void Preview::reset_double_slider()
@@ -784,7 +838,7 @@ void Preview::load_print_as_fff(bool keep_z_range)
colors.push_back("#808080"); // gray color for pause print or custom G-code
if (!gcode_preview_data_valid)
- color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z;
+ color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
}
else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) )
{
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index 92ec15b22..ae93e2ff0 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -157,8 +157,9 @@ private:
void create_double_slider();
void check_slider_values(std::vector<Model::CustomGCode> &ticks_from_model,
const std::vector<double> &layers_z);
- void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
void reset_double_slider();
+ void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
+ void update_double_slider_mode();
// update DoubleSlider after keyDown in canvas
void update_double_slider_from_canvas(wxKeyEvent& event);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
index 925727e76..6be108c85 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp
@@ -48,12 +48,10 @@ std::string GLGizmoMove3D::on_get_name() const
return (_(L("Move")) + " [M]").ToUTF8().data();
}
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
bool GLGizmoMove3D::on_is_activable() const
{
return !m_parent.get_selection().is_empty();
}
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
void GLGizmoMove3D::on_start_dragging()
{
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
index 19958615e..b2367ac68 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp
@@ -33,9 +33,7 @@ public:
protected:
virtual bool on_init();
virtual std::string on_get_name() const;
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
virtual bool on_is_activable() const;
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
virtual void on_start_dragging();
virtual void on_stop_dragging();
virtual void on_update(const UpdateData& data);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
index 5d3b6f365..9a0d75033 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp
@@ -449,12 +449,10 @@ std::string GLGizmoRotate3D::on_get_name() const
return (_(L("Rotate")) + " [R]").ToUTF8().data();
}
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
bool GLGizmoRotate3D::on_is_activable() const
{
return !m_parent.get_selection().is_empty();
}
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
void GLGizmoRotate3D::on_start_dragging()
{
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
index 930a76e2e..6e7bf1a09 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp
@@ -104,9 +104,7 @@ protected:
if (id < 3)
m_gizmos[id].disable_grabber(0);
}
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
virtual bool on_is_activable() const;
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
virtual void on_start_dragging();
virtual void on_stop_dragging();
virtual void on_update(const UpdateData& data)
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
index fa49b06ce..b4972e6fa 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp
@@ -49,12 +49,8 @@ std::string GLGizmoScale3D::on_get_name() const
bool GLGizmoScale3D::on_is_activable() const
{
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
const Selection& selection = m_parent.get_selection();
return !selection.is_empty() && !selection.is_wipe_tower();
-#else
- return !m_parent.get_selection().is_wipe_tower();
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
}
void GLGizmoScale3D::on_start_dragging()
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index abcb39c14..fc63d766c 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -881,11 +881,7 @@ void GLGizmosManager::do_render_overlay() const
if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1))
return;
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
float du = (float)(tex_width - 1) / (4.0f * (float)tex_width); // 4 is the number of possible states if the icons
-#else
- float du = (float)(tex_width - 1) / (3.0f * (float)tex_width); // 3 is the number of possible states if the icons
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height);
// tiles in the texture are spaced by 1 pixel
@@ -908,11 +904,7 @@ void GLGizmosManager::do_render_overlay() const
GLGizmoBase* gizmo = m_gizmos[idx].get();
unsigned int sprite_id = gizmo->get_sprite_id();
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
int icon_idx = (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3));
-#else
- int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
#if ENABLE_MODIFIED_TOOLBAR_TEXTURES
float v_top = v_offset + sprite_id * dv;
@@ -971,9 +963,7 @@ bool GLGizmosManager::generate_icons_texture() const
states.push_back(std::make_pair(1, false)); // Activable
states.push_back(std::make_pair(0, false)); // Hovered
states.push_back(std::make_pair(0, true)); // Selected
-#if ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
states.push_back(std::make_pair(2, false)); // Disabled
-#endif // ENABLE_GIZMO_ICONS_NON_ACTIVABLE_STATE
unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size();
// // force even size
diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp
index 8485c4b27..8eee313c0 100644
--- a/src/slic3r/GUI/Mouse3DController.cpp
+++ b/src/slic3r/GUI/Mouse3DController.cpp
@@ -5,9 +5,7 @@
#include "GUI_App.hpp"
#include "PresetBundle.hpp"
#include "AppConfig.hpp"
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include "GLCanvas3D.hpp"
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
#include <wx/glcanvas.h>
@@ -200,9 +198,7 @@ Mouse3DController::Mouse3DController()
, m_device_str("")
, m_running(false)
, m_show_settings_dialog(false)
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
, m_settings_dialog_closed_by_user(false)
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
m_last_time = std::chrono::high_resolution_clock::now();
}
@@ -247,9 +243,7 @@ bool Mouse3DController::apply(Camera& camera)
disconnect_device();
// hides the settings dialog if the user un-plug the device
m_show_settings_dialog = false;
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
m_settings_dialog_closed_by_user = false;
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
}
// check if the user plugged the device
@@ -259,16 +253,11 @@ bool Mouse3DController::apply(Camera& camera)
return is_device_connected() ? m_state.apply(camera) : false;
}
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
-#else
-void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
{
if (!m_running || !m_show_settings_dialog)
return;
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
// when the user clicks on [X] or [Close] button we need to trigger
// an extra frame to let the dialog disappear
if (m_settings_dialog_closed_by_user)
@@ -280,16 +269,10 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
}
Size cnv_size = canvas.get_canvas_size();
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGuiWrapper& imgui = *wxGetApp().imgui();
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
-#else
- imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
static ImVec2 last_win_size(0.0f, 0.0f);
bool shown = true;
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
@@ -304,9 +287,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
last_win_size = win_size;
canvas.request_extra_frame();
}
-#else
- imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
ImGui::PushStyleColor(ImGuiCol_Text, color);
@@ -389,7 +369,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
ImGui::Separator();
if (imgui.button(_(L("Close"))))
@@ -406,7 +385,6 @@ void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsign
canvas.set_as_dirty();
}
}
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
imgui.end();
}
diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp
index 1cddf254b..f3826f8e2 100644
--- a/src/slic3r/GUI/Mouse3DController.hpp
+++ b/src/slic3r/GUI/Mouse3DController.hpp
@@ -18,9 +18,7 @@ namespace Slic3r {
namespace GUI {
struct Camera;
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class GLCanvas3D;
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
class Mouse3DController
{
@@ -143,13 +141,9 @@ class Mouse3DController
hid_device* m_device;
std::string m_device_str;
bool m_running;
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
mutable bool m_show_settings_dialog;
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
mutable bool m_settings_dialog_closed_by_user;
-#else
- bool m_show_settings_dialog;
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
public:
@@ -167,11 +161,7 @@ public:
bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
-#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
void render_settings_dialog(GLCanvas3D& canvas) const;
-#else
- void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
-#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
private:
bool connect_device();
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 011d7e7ce..83570ae74 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1857,9 +1857,7 @@ struct Plater::priv
void set_current_canvas_as_dirty();
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool init_view_toolbar();
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
void reset_all_gizmos();
void update_ui_from_settings();
@@ -2006,9 +2004,6 @@ private:
bool complit_init_object_menu();
bool complit_init_sla_object_menu();
bool complit_init_part_menu();
-#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
- void init_view_toolbar();
-#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool can_split() const;
bool layers_height_allowed() const;
@@ -2142,11 +2137,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); });
view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); });
view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); });
-#if ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
-#endif // ENABLE_ADAPTIVE_LAYER_HEIGHT_PROFILE
// 3DScene/Toolbar:
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
@@ -2160,9 +2153,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this);
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
-#if !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
- view3D_canvas->Bind(EVT_GLCANVAS_INIT, [this](SimpleEvent&) { init_view_toolbar(); });
-#endif // !ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [this](SimpleEvent&)
{
set_bed_shape(config->option<ConfigOptionPoints>("bed_shape")->values,
@@ -2791,7 +2781,7 @@ void Plater::priv::reset()
// The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here
this->sidebar->show_sliced_info_sizer(false);
- model.custom_gcode_per_print_z.clear();
+ model.custom_gcode_per_print_z.gcodes.clear();
}
void Plater::priv::mirror(Axis axis)
@@ -3022,7 +3012,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
this->update_print_volume_state();
// Apply new config to the possibly running background task.
bool was_running = this->background_process.running();
- this->background_process.set_force_update_print_regions(force_validation);
Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
@@ -3242,12 +3231,9 @@ void Plater::priv::reload_from_disk()
// collects paths of files to load
std::vector<fs::path> input_paths;
-#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
std::vector<fs::path> missing_input_paths;
-#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
for (const SelectedVolume& v : selected_volumes)
{
-#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
const ModelObject* object = model.objects[v.object_idx];
const ModelVolume* volume = object->volumes[v.volume_idx];
@@ -3258,14 +3244,8 @@ void Plater::priv::reload_from_disk()
else
missing_input_paths.push_back(volume->source.input_file);
}
-#else
- const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx];
- if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file))
- input_paths.push_back(volume->source.input_file);
-#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
}
-#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
std::sort(missing_input_paths.begin(), missing_input_paths.end());
missing_input_paths.erase(std::unique(missing_input_paths.begin(), missing_input_paths.end()), missing_input_paths.end());
@@ -3315,7 +3295,6 @@ void Plater::priv::reload_from_disk()
return;
}
}
-#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
std::sort(input_paths.begin(), input_paths.end());
input_paths.erase(std::unique(input_paths.begin(), input_paths.end()), input_paths.end());
@@ -3361,27 +3340,17 @@ void Plater::priv::reload_from_disk()
new_volume->config.apply(old_volume->config);
new_volume->set_type(old_volume->type());
new_volume->set_material_id(old_volume->material_id());
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
new_volume->set_transformation(old_volume->get_transformation() * old_volume->source.transform);
-#else
- new_volume->set_transformation(old_volume->get_transformation());
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
new_volume->translate(new_volume->get_transformation().get_matrix(true) * (new_volume->source.mesh_offset - old_volume->source.mesh_offset));
new_volume->source.input_file = path;
std::swap(old_model_object->volumes[old_v.volume_idx], old_model_object->volumes.back());
old_model_object->delete_volume(old_model_object->volumes.size() - 1);
-#if ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
old_model_object->ensure_on_bed();
-#endif // ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
}
}
}
}
-#if !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
- model.adjust_min_z();
-#endif // !ENABLE_KEEP_LOADED_VOLUME_TRANSFORM_AS_STAND_ALONE
-
// update 3D scene
update();
@@ -3995,17 +3964,11 @@ void Plater::priv::set_current_canvas_as_dirty()
preview->set_as_dirty();
}
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool Plater::priv::init_view_toolbar()
-#else
-void Plater::priv::init_view_toolbar()
-#endif //!ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
{
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
if (view_toolbar.get_items_count() > 0)
// already initialized
return true;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
BackgroundTexture::Metadata background_data;
background_data.filename = "toolbar_background.png";
@@ -4015,11 +3978,7 @@ void Plater::priv::init_view_toolbar()
background_data.bottom = 16;
if (!view_toolbar.init(background_data))
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
return false;
-#else
- return;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
view_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Left);
view_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Bottom);
@@ -4034,11 +3993,7 @@ void Plater::priv::init_view_toolbar()
item.sprite_id = 0;
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
if (!view_toolbar.add_item(item))
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
return false;
-#else
- return;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
item.name = "Preview";
item.icon_filename = "preview.svg";
@@ -4046,18 +4001,12 @@ void Plater::priv::init_view_toolbar()
item.sprite_id = 1;
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
if (!view_toolbar.add_item(item))
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
return false;
-#else
- return;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
view_toolbar.select_item("3D");
view_toolbar.set_enabled(true);
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
return true;
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
}
bool Plater::priv::can_set_instance_to_object() const
@@ -4122,11 +4071,7 @@ bool Plater::priv::can_reload_from_disk() const
for (const SelectedVolume& v : selected_volumes)
{
const ModelVolume* volume = model.objects[v.object_idx]->volumes[v.volume_idx];
-#if ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
if (!volume->source.input_file.empty())
-#else
- if (!volume->source.input_file.empty() && boost::filesystem::exists(volume->source.input_file))
-#endif // ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION
paths.push_back(volume->source.input_file);
}
std::sort(paths.begin(), paths.end());
@@ -5350,9 +5295,9 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config() const
std::vector<std::string> Plater::get_colors_for_color_print() const
{
std::vector<std::string> colors = get_extruder_colors_from_plater_config();
- colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.size());
+ colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size());
- for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z)
+ for (const Model::CustomGCode& code : p->model.custom_gcode_per_print_z.gcodes)
if (code.gcode == ColorChangeCode)
colors.emplace_back(code.color);
@@ -5516,12 +5461,10 @@ void Plater::msw_rescale()
GetParent()->Layout();
}
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool Plater::init_view_toolbar()
{
return p->init_view_toolbar();
}
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
const Camera& Plater::get_camera() const
{
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index 479397705..1bea07795 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -266,9 +266,7 @@ public:
void msw_rescale();
-#if ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
bool init_view_toolbar();
-#endif // ENABLE_VIEW_TOOLBAR_BACKGROUND_FIX
const Camera& get_camera() const;
const Mouse3DController& get_mouse3d_controller() const;
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index c20a5bb28..b89000891 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -184,6 +184,14 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
} else {
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed variants field: `%2%`") % id % variants_field;
}
+ auto default_materials_field = section.second.get<std::string>("default_materials", "");
+ if (default_materials_field.empty())
+ default_materials_field = section.second.get<std::string>("default_filaments", "");
+ if (Slic3r::unescape_strings_cstyle(default_materials_field, model.default_materials)) {
+ Slic3r::sort_remove_duplicates(model.default_materials);
+ } else {
+ BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Malformed default_materials field: `%2%`") % id % default_materials_field;
+ }
model.bed_model = section.second.get<std::string>("bed_model", "");
model.bed_texture = section.second.get<std::string>("bed_texture", "");
if (! model.id.empty() && ! model.variants.empty())
@@ -1502,4 +1510,20 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model
return it != cend() ? &*it : nullptr;
}
+namespace PresetUtils {
+ const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
+ {
+ const VendorProfile::PrinterModel *out = nullptr;
+ if (preset.vendor != nullptr) {
+ auto *printer_model = preset.config.opt<ConfigOptionString>("printer_model");
+ if (printer_model != nullptr && ! printer_model->value.empty()) {
+ auto it = std::find_if(preset.vendor->models.begin(), preset.vendor->models.end(), [printer_model](const VendorProfile::PrinterModel &pm) { return pm.id == printer_model->value; });
+ if (it != preset.vendor->models.end())
+ out = &(*it);
+ }
+ }
+ return out;
+ }
+} // namespace PresetUtils
+
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp
index 19d07d007..0a26f90cc 100644
--- a/src/slic3r/GUI/Preset.hpp
+++ b/src/slic3r/GUI/Preset.hpp
@@ -61,6 +61,7 @@ public:
PrinterTechnology technology;
std::string family;
std::vector<PrinterVariant> variants;
+ std::vector<std::string> default_materials;
// Vendor & Printer Model specific print bed model & texture.
std::string bed_model;
std::string bed_texture;
@@ -563,6 +564,11 @@ public:
const Preset* find_by_model_id(const std::string &model_id) const;
};
+namespace PresetUtils {
+ // PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile.
+ const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
+} // namespace PresetUtils
+
} // namespace Slic3r
#endif /* slic3r_Preset_hpp_ */
diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp
index 219d7b89d..8f5d58bc1 100644
--- a/src/slic3r/GUI/PresetBundle.cpp
+++ b/src/slic3r/GUI/PresetBundle.cpp
@@ -877,7 +877,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
// 4) Load the project config values (the per extruder wipe matrix etc).
this->project_config.apply_only(config, s_project_options);
- update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
+ update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes, &this->project_config);
break;
}
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 7b36207f5..7689e31cb 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -5,6 +5,7 @@
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
+#include "libslic3r/Print.hpp"
#include <wx/sizer.h>
#include <wx/bmpcbox.h>
@@ -13,9 +14,7 @@
#include <wx/numformatter.h>
#include <wx/colordlg.h>
-#include <boost/filesystem.hpp>
#include <boost/algorithm/string/replace.hpp>
-#include <boost/nowide/cstdio.hpp>
#include "BitmapCache.hpp"
#include "GUI.hpp"
@@ -426,28 +425,6 @@ static float get_svg_scale_factor(wxWindow *win)
#endif
}
-// in the Dark mode of any platform, we should draw icons in respect to OS background
-static std::string icon_name_respected_to_mode(const std::string& bmp_name_in)
-{
-#ifdef __WXMSW__
- const std::string folder = "white\\";
-#else
- const std::string folder = "white/";
-#endif
- std::string bmp_name;
- if (Slic3r::GUI::wxGetApp().dark_mode()) {
- bmp_name = folder + bmp_name_in;
- boost::replace_last(bmp_name, ".png", "");
- if (! boost::filesystem::exists(Slic3r::var(bmp_name + ".svg")))
- bmp_name.clear();
- }
- if (bmp_name.empty()) {
- bmp_name = bmp_name_in;
- boost::replace_last(bmp_name, ".png", "");
- }
- return bmp_name;
-}
-
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/, const bool grayscale/* = false*/)
@@ -474,13 +451,13 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
scale_base = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f);
-// std::string bmp_name = bmp_name_in;
-// boost::replace_last(bmp_name, ".png", "");
+ std::string bmp_name = bmp_name_in;
+ boost::replace_last(bmp_name, ".png", "");
- std::string bmp_name = icon_name_respected_to_mode(bmp_name_in);
+// std::string bmp_name = icon_name_respected_to_mode(bmp_name_in);
// Try loading an SVG first, then PNG if SVG is not found:
- wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale);
+ wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale, Slic3r::GUI::wxGetApp().dark_mode());
if (bmp == nullptr) {
bmp = cache.load_png(bmp_name, width, height, grayscale);
}
@@ -2555,41 +2532,50 @@ double DoubleSlider::get_double_value(const SelectedSlider& selection)
}
using t_custom_code = Slic3r::Model::CustomGCode;
-std::vector<t_custom_code> DoubleSlider::GetTicksValues() const
+Slic3r::Model::CustomGCodeInfo DoubleSlider::GetTicksValues() const
{
- std::vector<t_custom_code> values;
+ Slic3r::Model::CustomGCodeInfo custom_gcode_per_print_z;
+ std::vector<t_custom_code>& values = custom_gcode_per_print_z.gcodes;
const int val_size = m_values.size();
if (!m_values.empty())
- for (const TICK_CODE& tick : m_ticks_) {
+ for (const TICK_CODE& tick : m_ticks) {
if (tick.tick > val_size)
break;
values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color});
}
- return values;
+ custom_gcode_per_print_z.mode = m_mode;
+
+ return custom_gcode_per_print_z;
}
-void DoubleSlider::SetTicksValues(const std::vector<t_custom_code>& heights)
+void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_gcode_per_print_z)
{
if (m_values.empty())
+ {
+ m_ticks_mode = m_mode;
return;
+ }
- const bool was_empty = m_ticks_.empty();
+ const bool was_empty = m_ticks.empty();
- m_ticks_.clear();
+ m_ticks.clear();
+ const std::vector<t_custom_code>& heights = custom_gcode_per_print_z.gcodes;
for (auto h : heights) {
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
if (it == m_values.end())
continue;
- m_ticks_.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
+ m_ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
}
- if (!was_empty && m_ticks_.empty())
+ if (!was_empty && m_ticks.empty())
// Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ post_ticks_changed_event();
+
+ m_ticks_mode = custom_gcode_per_print_z.mode;
Refresh();
Update();
@@ -2638,11 +2624,6 @@ void DoubleSlider::render()
// draw line
draw_scroll_line(dc, lower_pos, higher_pos);
-// //lower slider:
-// draw_thumb(dc, lower_pos, ssLower);
-// //higher slider:
-// draw_thumb(dc, higher_pos, ssHigher);
-
//draw color print ticks
draw_ticks(dc);
@@ -2668,7 +2649,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin
return;
wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp();
- if (m_ticks_.find(TICK_CODE{tick}) != m_ticks_.end())
+ if (m_ticks.find(TICK_CODE{tick}) != m_ticks.end())
icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp();
wxCoord x_draw, y_draw;
@@ -2811,7 +2792,7 @@ void DoubleSlider::draw_ticks(wxDC& dc)
int height, width;
get_size(&width, &height);
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
- for (auto tick : m_ticks_)
+ for (auto tick : m_ticks)
{
const wxCoord pos = get_position_from_value(tick.tick);
@@ -2821,7 +2802,7 @@ void DoubleSlider::draw_ticks(wxDC& dc)
dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/);
// Draw icon for "Pause print" or "Custom Gcode"
- if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ExtruderChangeCode)
+ if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ToolChangeCode)
{
wxBitmap icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode");
@@ -2834,6 +2815,40 @@ void DoubleSlider::draw_ticks(wxDC& dc)
}
}
+std::string DoubleSlider::get_color_for_tool_change_tick(std::set<TICK_CODE>::const_iterator it) const
+{
+ const int current_extruder = it->extruder == 0 ? std::max<int>(m_only_extruder, 1) : it->extruder;
+
+ auto it_n = it;
+ while (it_n != m_ticks.begin()) {
+ --it_n;
+ if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder)
+ return it_n->color;
+ }
+
+ return it->color;
+}
+
+std::string DoubleSlider::get_color_for_color_change_tick(std::set<TICK_CODE>::const_iterator it) const
+{
+ const int def_extruder = std::max<int>(1, m_only_extruder);
+ auto it_n = it;
+ bool is_tool_change = false;
+ while (it_n != m_ticks.begin()) {
+ --it_n;
+ if (it_n->gcode == Slic3r::ToolChangeCode) {
+ is_tool_change = true;
+ if (it_n->extruder == it->extruder)
+ return it->color;
+ break;
+ }
+ }
+ if (!is_tool_change && it->extruder == def_extruder)
+ return it->color;
+
+ return "";
+}
+
void DoubleSlider::draw_colored_band(wxDC& dc)
{
if (!m_is_enabled_tick_manipulation)
@@ -2856,29 +2871,36 @@ void DoubleSlider::draw_colored_band(wxDC& dc)
dc.DrawRectangle(band_rc);
};
- const std::vector<std::string>& colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
- int colors_cnt = colors.size();
+ // don't color a band for MultiExtruder mode
+ if (m_ticks.empty() || m_mode == t_mode::MultiExtruder)
+ {
+ draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
+ return;
+ }
- const wxColour bg_clr = GetParent()->GetBackgroundColour();
+ const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0;
+ draw_band(dc, wxColour(Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band);
- wxColour clr = m_state == msSingleExtruder ? wxColour(colors[0]) : bg_clr;
- draw_band(dc, clr, main_band);
+ std::set<TICK_CODE>::const_iterator tick_it = m_ticks.begin();
- size_t i = 1;
- for (auto tick : m_ticks_)
+ while (tick_it != m_ticks.end())
{
- if ( (m_state == msSingleExtruder && tick.gcode != Slic3r::ColorChangeCode) ||
- (m_state == msMultiExtruder && tick.gcode != Slic3r::ExtruderChangeCode) )
- continue;
-
- const wxCoord pos = get_position_from_value(tick.tick);
- is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) :
- main_band.SetBottom(pos - 1);
-
- clr = (m_state == msMultiExtruder && tick.color.empty()) ? bg_clr :
- m_state == msMultiExtruder ? wxColour(colors[std::min<int>(colors_cnt - 1, tick.extruder-1)]) : wxColour(tick.color);
- draw_band(dc, clr, main_band);
- i++;
+ if ( (m_mode == t_mode::SingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) ||
+ (m_mode == t_mode::MultiAsSingle && (tick_it->gcode == Slic3r::ToolChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) )
+ {
+ const wxCoord pos = get_position_from_value(tick_it->tick);
+ is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) :
+ main_band.SetBottom(pos - 1);
+
+ const std::string clr_str = m_mode == t_mode::SingleExtruder ? tick_it->color :
+ tick_it->gcode == Slic3r::ToolChangeCode ?
+ get_color_for_tool_change_tick(tick_it) :
+ get_color_for_color_change_tick(tick_it);
+
+ if (!clr_str.empty())
+ draw_band(dc, wxColour(clr_str), main_band);
+ }
+ ++tick_it;
}
}
@@ -2903,7 +2925,7 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc)
void DoubleSlider::draw_revert_icon(wxDC& dc)
{
- if (m_ticks_.empty() || !m_is_enabled_tick_manipulation)
+ if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
return;
int width, height;
@@ -2921,7 +2943,7 @@ void DoubleSlider::draw_revert_icon(wxDC& dc)
void DoubleSlider::draw_cog_icon(wxDC& dc)
{
- if (m_state != msMultiExtruder)
+ if (m_mode != t_mode::MultiExtruder)
return;
int width, height;
@@ -2965,15 +2987,13 @@ void DoubleSlider::detect_selected_slider(const wxPoint& pt)
bool DoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
{
- if (rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() &&
- rect.GetTop() <= pt.y && pt.y <= rect.GetBottom())
- return true;
- return false;
+ return rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() &&
+ rect.GetTop() <= pt.y && pt.y <= rect.GetBottom();
}
int DoubleSlider::is_point_near_tick(const wxPoint& pt)
{
- for (auto tick : m_ticks_) {
+ for (auto tick : m_ticks) {
const wxCoord pos = get_position_from_value(tick.tick);
if (is_horizontal()) {
@@ -3034,10 +3054,10 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
if (!m_selection) m_selection = ssHigher;
- m_ticks_.clear();
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ m_ticks.clear();
+ post_ticks_changed_event();
}
- else if (is_point_in_rect(pos, m_rect_cog_icon) && m_state == msMultiExtruder) {
+ else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == t_mode::MultiExtruder) {
// show dialog for set extruder sequence
m_edit_extruder_sequence = true;
}
@@ -3107,17 +3127,18 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus)
else if (m_is_action_icon_focesed)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
- const auto tick_code_it = m_ticks_.find(TICK_CODE{tick});
- tooltip = tick_code_it == m_ticks_.end() ? (m_state == msSingleExtruder ?
- _(L("For add color change use left mouse button click")) :
- _(L("For add change extruder use left mouse button click"))) + "\n" +
- _(L("For add another code use right mouse button click")) :
- tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_state == msSingleExtruder ?
+ const auto tick_code_it = m_ticks.find(TICK_CODE{tick});
+ tooltip = tick_code_it == m_ticks.end() ? (m_mode == t_mode::MultiAsSingle ?
+ _(L("For add change extruder use left mouse button click")) :
+ _(L("For add color change use left mouse button click")) ) + "\n" +
+ _(L("For add another code use right mouse button click")) :
+ tick_code_it->gcode == Slic3r::ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ?
_(L("For Delete color change use left mouse button click\n"
"For Edit color use right mouse button click")) :
from_u8((boost::format(_utf8(L("Delete color change for Extruder %1%"))) % tick_code_it->extruder).str()) ):
-// tick_code_it->gcode == Slic3r::PausePrintCode ? _(L("Delete pause")) :
- tick_code_it->gcode == Slic3r::ExtruderChangeCode ?
+ tick_code_it->gcode == Slic3r::PausePrintCode ?
+ _(L("Delete pause")) :
+ tick_code_it->gcode == Slic3r::ToolChangeCode ?
from_u8((boost::format(_utf8(L("Delete extruder change to \"%1%\""))) % tick_code_it->extruder).str()) :
from_u8((boost::format(_utf8(L("For Delete \"%1%\" code use left mouse button click\n"
"For Edit \"%1%\" code use right mouse button click"))) % tick_code_it->gcode ).str());
@@ -3138,7 +3159,7 @@ void DoubleSlider::OnMotion(wxMouseEvent& event)
if (!m_is_left_down && !m_is_one_layer) {
m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action);
- if (!m_ticks_.empty() && is_point_in_rect(pos, m_rect_revert_icon))
+ if (!m_ticks.empty() && is_point_in_rect(pos, m_rect_revert_icon))
icon_focus = ifRevert;
else if (is_point_in_rect(pos, m_rect_cog_icon))
icon_focus = ifCog;
@@ -3173,6 +3194,67 @@ void DoubleSlider::OnMotion(wxMouseEvent& event)
}
}
+void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu)
+{
+ const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt();
+ if (extruders_cnt > 1)
+ {
+ const int initial_extruder = std::max<int>(1 , get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value));
+
+ wxMenu* change_extruder_menu = new wxMenu();
+
+ for (int i = 1; i <= extruders_cnt; i++)
+ {
+ const bool is_active_extruder = i == initial_extruder;
+ const wxString item_name = wxString::Format(_(L("Extruder %d")), i) +
+ (is_active_extruder ? " (" + _(L("active")) + ")" : "");
+
+ if (m_mode == t_mode::MultiAsSingle)
+ append_menu_item(change_extruder_menu, wxID_ANY, item_name, "",
+ [this, i](wxCommandEvent&) { change_extruder(i); }, "", menu,
+ [is_active_extruder]() { return !is_active_extruder; }, Slic3r::GUI::wxGetApp().plater());
+// append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "",
+// [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder);
+ }
+
+ const wxString change_extruder_menu_name = m_mode == t_mode::MultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)"));
+
+ wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder")));
+ change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, "change_extruder"));
+
+ Slic3r::GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) {
+ enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); },
+ change_extruder_menu_item->GetId());
+ }
+}
+
+void DoubleSlider::append_add_color_change_menu_item(wxMenu* menu)
+{
+ const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt();
+ if (extruders_cnt > 1)
+ {
+ std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
+
+ wxMenu* add_color_change_menu = new wxMenu();
+
+ for (int i = 1; i <= extruders_cnt; i++)
+ {
+ const bool is_used_extruder = used_extruders_for_tick.empty() ? true : // #ys_FIXME till used_extruders_for_tick doesn't filled correct for mmMultiExtruder
+ used_extruders_for_tick.find(i) != used_extruders_for_tick.end();
+ const wxString item_name = wxString::Format(_(L("Extruder %d")), i) +
+ (is_used_extruder ? " (" + _(L("used")) + ")" : "");
+
+ append_menu_item(add_color_change_menu, wxID_ANY, item_name, "",
+ [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", menu,
+ [is_used_extruder]() { return is_used_extruder; }, Slic3r::GUI::wxGetApp().plater());
+ }
+
+ const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str());
+ wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
+ add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m"));
+ }
+}
+
void DoubleSlider::OnLeftUp(wxMouseEvent& event)
{
if (!HasCapture())
@@ -3182,31 +3264,19 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event)
if (m_show_context_menu)
{
- if (m_state == msMultiExtruder)
+ if (m_mode == t_mode::SingleExtruder)
+ add_code(Slic3r::ColorChangeCode);
+ else
{
wxMenu menu;
- const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt();
- if (extruders_cnt > 1)
- {
- const int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
- wxMenu* change_extruder_menu = new wxMenu();
-
- for (int i = 0; i <= extruders_cnt; i++) {
- const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i);
-
- append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "",
- [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder);
- }
-
- wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, _(L("Change extruder")), _(L("Use another extruder")));
- change_extruder_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "change_extruder"));
- }
+ if (m_mode == t_mode::MultiAsSingle)
+ append_change_extruder_menu_item(&menu);
+ else
+ append_add_color_change_menu_item(&menu);
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu);
}
- else
- add_code(Slic3r::ColorChangeCode);
m_show_context_menu = false;
}
@@ -3266,15 +3336,15 @@ void DoubleSlider::action_tick(const TicksAction action)
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
- const auto it = m_ticks_.find(TICK_CODE{tick});
+ const auto it = m_ticks.find(TICK_CODE{tick});
- if (it != m_ticks_.end()) // erase this tick
+ if (it != m_ticks.end()) // erase this tick
{
if (action == taAdd)
return;
- m_ticks_.erase(TICK_CODE{tick});
+ m_ticks.erase(TICK_CODE{tick});
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ post_ticks_changed_event(it->gcode);
Refresh();
Update();
return;
@@ -3289,7 +3359,7 @@ void DoubleSlider::action_tick(const TicksAction action)
if (m_suppress_add_code)
return;
m_suppress_add_code = true;
- if (m_state != msMultiExtruder)
+ if (m_mode == t_mode::SingleExtruder) // if (m_mode != t_mode::MultiExtruder)
add_code(Slic3r::ColorChangeCode);
m_suppress_add_code = false;
return;
@@ -3376,14 +3446,14 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
- auto it = m_ticks_.find(TICK_CODE{ tick });
- if (it == m_ticks_.end())
+ auto it = m_ticks.find(TICK_CODE{ tick });
+ if (it == m_ticks.end())
{
// show context menu on OnRightUp()
m_show_context_menu = true;
return;
}
- if (it->gcode != Slic3r::ExtruderChangeCode)
+ if (it->gcode != Slic3r::ToolChangeCode)
{
// show "Edit" and "Delete" menu on OnRightUp()
m_show_edit_menu = true;
@@ -3410,17 +3480,77 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event)
int DoubleSlider::get_extruder_for_tick(int tick)
{
- if (m_ticks_.empty())
- return 0;
+ int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? m_only_extruder : 0;
+ if (m_ticks.empty())
+ return default_initial_extruder;
- auto it = m_ticks_.lower_bound(TICK_CODE{tick});
- while (it != m_ticks_.begin()) {
+ auto it = m_ticks.lower_bound(TICK_CODE{tick});
+ while (it != m_ticks.begin()) {
--it;
- if(it->gcode == Slic3r::ExtruderChangeCode)
+ if(it->gcode == Slic3r::ToolChangeCode)
return it->extruder;
}
- return 0;
+ return default_initial_extruder;
+}
+
+std::set<int> DoubleSlider::get_used_extruders_for_tick(int tick)
+{
+ if (m_mode == t_mode::MultiExtruder)
+ {
+ // #ys_FIXME: get tool ordering from _correct_ place
+ const Slic3r::ToolOrdering& tool_ordering = Slic3r::GUI::wxGetApp().plater()->fff_print().get_tool_ordering();
+
+ if (tool_ordering.empty())
+ return {};
+
+ std::set<int> used_extruders;
+
+ auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), Slic3r::LayerTools(m_values[tick]));
+ for (; it_layer_tools != tool_ordering.end(); it_layer_tools++)
+ {
+ const std::vector<unsigned>& extruders = it_layer_tools->extruders;
+ for (const auto& extruder : extruders)
+ used_extruders.emplace(extruder+1);
+ }
+
+ return used_extruders;
+ }
+
+ const int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? std::max(m_only_extruder, 1) : 1;
+ if (m_ticks.empty())
+ return {default_initial_extruder};
+
+ std::set<int> used_extruders;
+ auto it_start = m_ticks.lower_bound(TICK_CODE{tick});
+
+ auto it = it_start;
+ if (it == m_ticks.begin() && it->gcode == Slic3r::ToolChangeCode) {
+ used_extruders.emplace(it->extruder);
+ if (tick < it->tick)
+ used_extruders.emplace(default_initial_extruder);
+ }
+
+ while (it != m_ticks.begin()) {
+ --it;
+ if(it->gcode == Slic3r::ToolChangeCode)
+ {
+ used_extruders.emplace(it->extruder);
+ break;
+ }
+ }
+
+ if (it == m_ticks.begin() && used_extruders.empty())
+ used_extruders.emplace(default_initial_extruder);
+
+ it = it_start;
+ while (it != m_ticks.end()) {
+ if(it->gcode == Slic3r::ToolChangeCode)
+ used_extruders.emplace(it->extruder);
+ ++it;
+ }
+
+ return used_extruders;
}
void DoubleSlider::OnRightUp(wxMouseEvent& event)
@@ -3433,45 +3563,23 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
if (m_show_context_menu) {
wxMenu menu;
- if (m_state == msMultiExtruder)
+ if (m_mode == t_mode::SingleExtruder)
+ append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "",
+ [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu,
+ [](){return true;}, this);
+ else
{
- const int extruders_cnt = Slic3r::GUI::wxGetApp().extruders_edited_cnt();
- if (extruders_cnt > 1)
- {
- const int initial_extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
-
- wxMenu* change_extruder_menu = new wxMenu();
- wxMenu* add_color_change_menu = new wxMenu();
-
- for (int i = 0; i <= extruders_cnt; i++) {
- const wxString item_name = i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i);
-
- append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "",
- [this, i](wxCommandEvent&) { change_extruder(i); }, &menu)->Check(i == initial_extruder);
-
- if (i==0) // don't use M600 for default extruder, if multimaterial print is selected
- continue;
- append_menu_item(add_color_change_menu, wxID_ANY, item_name, "",
- [this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", &menu);
- }
-
- wxMenuItem* change_extruder_menu_item = menu.AppendSubMenu(change_extruder_menu, _(L("Change extruder")), _(L("Use another extruder")));
- change_extruder_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "change_extruder"));
-
- const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str());
- wxMenuItem* add_color_change_menu_item = menu.AppendSubMenu(add_color_change_menu, menu_name, "");
- add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m"));
- }
+ append_change_extruder_menu_item(&menu);
+ append_add_color_change_menu_item(&menu);
}
- else
- append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "",
- [this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu);
append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "",
- [this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu);
+ [this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu,
+ []() {return true; }, this);
append_menu_item(&menu, wxID_ANY, _(L("Add custom G-code")), "",
- [this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu);
+ [this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu,
+ []() {return true; }, this);
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu);
@@ -3480,7 +3588,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
else if (m_show_edit_menu) {
wxMenu menu;
- std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
+ std::set<TICK_CODE>::iterator it = m_ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
const bool is_color_change = it->gcode == Slic3r::ColorChangeCode;
append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) :
@@ -3552,74 +3660,69 @@ void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z doesn't exist tick
- auto it = m_ticks_.find(TICK_CODE{ tick });
- if (it == m_ticks_.end())
+ auto it = m_ticks.find(TICK_CODE{ tick });
+ if (it != m_ticks.end())
+ return;
+
+ std::string color;
+ const int extruder = selected_extruder > 0 ? selected_extruder : std::max<int>(1, m_only_extruder);
+
+ if (code == Slic3r::ColorChangeCode)
{
- std::string color = "";
- if (code == Slic3r::ColorChangeCode)
+ std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
+
+ if (m_ticks.empty())
+ color = colors[extruder-1];
+ else
{
- std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
-
- if (m_state == msSingleExtruder && !m_ticks_.empty()) {
- auto before_tick_it = std::lower_bound(m_ticks_.begin(), m_ticks_.end(), TICK_CODE{ tick });
- while (before_tick_it != m_ticks_.begin()) {
- --before_tick_it;
- if (before_tick_it->gcode == Slic3r::ColorChangeCode) {
- color = before_tick_it->color;
- break;
- }
+ auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick });
+ while (before_tick_it != m_ticks.begin()) {
+ --before_tick_it;
+ if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) {
+ color = before_tick_it->color;
+ break;
}
-
- if (color.empty())
- color = colors[0];
}
- else
- color = colors[selected_extruder > 0 ? selected_extruder-1 : 0];
- color = get_new_color(color);
if (color.empty())
- return;
- }
- else if (code == Slic3r::PausePrintCode)
- {
- /* PausePrintCode doesn't need a color, so
- * this field is used for save a short message shown on Printer display
- * */
- color = get_pause_print_msg(m_pause_print_msg, m_values[tick]);
- if (color.empty())
- return;
- m_pause_print_msg = color;
- }
- else if (code.empty())
- {
- code = get_custom_code(m_custom_gcode, m_values[tick]);
- if (code.empty())
- return;
- m_custom_gcode = code;
+ color = colors[extruder-1];
}
- int extruder = 1;
- if (m_state == msMultiExtruder) {
- if (code == Slic3r::ColorChangeCode && selected_extruder >= 0)
- extruder = selected_extruder;
- else
- extruder = get_extruder_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
- }
+ color = get_new_color(color);
+ if (color.empty())
+ return;
+ }
+ else if (code == Slic3r::PausePrintCode)
+ {
+ /* PausePrintCode doesn't need a color, so
+ * this field is used for save a short message shown on Printer display
+ * */
+ color = get_pause_print_msg(m_pause_print_msg, m_values[tick]);
+ if (color.empty())
+ return;
+ m_pause_print_msg = color;
+ }
+ else if (code.empty())
+ {
+ code = get_custom_code(m_custom_gcode, m_values[tick]);
+ if (code.empty())
+ return;
+ m_custom_gcode = code;
+ }
- m_ticks_.emplace(TICK_CODE{tick, code, extruder, color});
+ m_ticks.emplace(TICK_CODE{tick, code, extruder, color});
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
- Refresh();
- Update();
- }
+ post_ticks_changed_event(code);
+ Refresh();
+ Update();
}
void DoubleSlider::edit_tick()
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
// if on this Z exists tick
- std::set<TICK_CODE>::iterator it = m_ticks_.find(TICK_CODE{ tick });
- if (it != m_ticks_.end())
+ std::set<TICK_CODE>::iterator it = m_ticks.find(TICK_CODE{ tick });
+ if (it != m_ticks.end())
{
std::string edited_value;
if (it->gcode == Slic3r::ColorChangeCode)
@@ -3644,10 +3747,10 @@ void DoubleSlider::edit_tick()
changed_tick.gcode = edited_value;
}
- m_ticks_.erase(it);
- m_ticks_.emplace(changed_tick);
+ m_ticks.erase(it);
+ m_ticks.emplace(changed_tick);
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ post_ticks_changed_event(changed_tick.gcode);
}
}
@@ -3658,11 +3761,11 @@ void DoubleSlider::change_extruder(int extruder)
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
// if on this Y doesn't exist tick
- if (m_ticks_.find(TICK_CODE{tick}) == m_ticks_.end())
+ if (m_ticks.find(TICK_CODE{tick}) == m_ticks.end())
{
- m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]});
+ m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]});
- wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ post_ticks_changed_event(Slic3r::ToolChangeCode);
Refresh();
Update();
}
@@ -3680,10 +3783,10 @@ void DoubleSlider::edit_extruder_sequence()
m_extruders_sequence = from_dlg_val;
- auto it = m_ticks_.begin();
- while (it != m_ticks_.end()) {
- if (it->gcode == Slic3r::ExtruderChangeCode)
- it = m_ticks_.erase(it);
+ auto it = m_ticks.begin();
+ while (it != m_ticks.end()) {
+ if (it->gcode == Slic3r::ToolChangeCode)
+ it = m_ticks.erase(it);
else
++it;
}
@@ -3698,7 +3801,7 @@ void DoubleSlider::edit_extruder_sequence()
while (tick <= m_max_value)
{
int cur_extruder = m_extruders_sequence.extruders[extruder];
- m_ticks_.emplace(TICK_CODE{tick, Slic3r::ExtruderChangeCode, cur_extruder + 1, colors[cur_extruder]});
+ m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]});
extruder++;
if (extruder == extr_cnt)
@@ -3717,6 +3820,42 @@ void DoubleSlider::edit_extruder_sequence()
tick += m_extruders_sequence.interval_by_layers;
}
+ post_ticks_changed_event(Slic3r::ToolChangeCode);
+}
+
+void DoubleSlider::post_ticks_changed_event(const std::string& gcode /*= ""*/)
+{
+ if ( m_ticks_mode == m_mode ||
+ (gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) )
+ {
+ wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
+ return;
+ }
+
+ if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle)
+ {
+ }
+
+ if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder)
+ {
+ }
+
+ if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::SingleExtruder)
+ {
+ }
+
+ if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::MultiExtruder)
+ {
+ }
+
+ if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder)
+ {
+ }
+
+ if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle)
+ {
+ }
+
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
}
diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp
index 390dafab9..5b9f6db0b 100644
--- a/src/slic3r/GUI/wxExtensions.hpp
+++ b/src/slic3r/GUI/wxExtensions.hpp
@@ -782,6 +782,8 @@ public:
const wxString& name = wxEmptyString);
~DoubleSlider() {}
+ using t_mode = Slic3r::Model::CustomGCodeInfo::MODE;
+
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
* So, let use same value as a permissible error for layer height.
*/
@@ -805,33 +807,24 @@ public:
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetSelectionSpan(const int lower_val, const int higher_val);
void SetMaxValue(const int max_value);
- void SetKoefForLabels(const double koef) {
- m_label_koef = koef;
- }
- void SetSliderValues(const std::vector<double>& values) {
- m_values = values;
- }
+ void SetKoefForLabels(const double koef) { m_label_koef = koef; }
+ void SetSliderValues(const std::vector<double>& values) { m_values = values; }
void ChangeOneLayerLock();
- std::vector<Slic3r::Model::CustomGCode> GetTicksValues() const;
- void SetTicksValues(const std::vector<Slic3r::Model::CustomGCode> &heights);
- void EnableTickManipulation(bool enable = true) {
- m_is_enabled_tick_manipulation = enable;
- }
- void DisableTickManipulation() {
- EnableTickManipulation(false);
- }
+ Slic3r::Model::CustomGCodeInfo GetTicksValues() const;
+ void SetTicksValues(const Slic3r::Model::CustomGCodeInfo &custom_gcode_per_print_z);
+ void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
+ void DisableTickManipulation() { EnableTickManipulation(false); }
- enum ManipulationState {
- msSingleExtruder, // single extruder printer preset is selected
- msMultiExtruder // multiple extruder printer preset is selected, and "Whole print" is selected
- };
- void SetManipulationState(ManipulationState state) {
- m_state = state;
- }
- void SetManipulationState(int extruders_cnt) {
- m_state = extruders_cnt ==1 ? msSingleExtruder : msMultiExtruder;
+ void SetManipulationMode(t_mode mode) { m_mode = mode; }
+ t_mode GetManipulationMode() const { return m_mode; }
+
+ void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
+ {
+ m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
+ only_extruder < 0 ? t_mode::SingleExtruder :
+ t_mode::MultiAsSingle;
+ m_only_extruder = only_extruder;
}
- ManipulationState GetManipulationState() const { return m_state; }
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
bool is_one_layer() const { return m_is_one_layer; }
@@ -850,13 +843,23 @@ public:
void OnKeyUp(wxKeyEvent &event);
void OnChar(wxKeyEvent &event);
void OnRightDown(wxMouseEvent& event);
- int get_extruder_for_tick(int tick);
void OnRightUp(wxMouseEvent& event);
void add_code(std::string code, int selected_extruder = -1);
void edit_tick();
void change_extruder(int extruder);
void edit_extruder_sequence();
+ struct TICK_CODE
+ {
+ bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
+ bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
+
+ int tick = 0;
+ std::string gcode = Slic3r::ColorChangeCode;
+ int extruder = 0;
+ std::string color;
+ };
+
protected:
void render();
@@ -878,11 +881,12 @@ protected:
void detect_selected_slider(const wxPoint& pt);
void correct_lower_value();
void correct_higher_value();
- wxString get_tooltip(IconFocus icon_focus);
void move_current_thumb(const bool condition);
void action_tick(const TicksAction action);
void enter_window(wxMouseEvent& event, const bool enter);
+private:
+
bool is_point_in_rect(const wxPoint& pt, const wxRect& rect);
int is_point_near_tick(const wxPoint& pt);
@@ -894,8 +898,17 @@ protected:
wxSize get_size();
void get_size(int *w, int *h);
double get_double_value(const SelectedSlider& selection);
+ wxString get_tooltip(IconFocus icon_focus);
+
+ std::string get_color_for_tool_change_tick(std::set<TICK_CODE>::const_iterator it) const;
+ std::string get_color_for_color_change_tick(std::set<TICK_CODE>::const_iterator it) const;
+ int get_extruder_for_tick(int tick);
+ std::set<int> get_used_extruders_for_tick(int tick);
+
+ void post_ticks_changed_event(const std::string& gcode = "");
+ void append_change_extruder_menu_item(wxMenu*);
+ void append_add_color_change_menu_item(wxMenu*);
-private:
bool is_osx { false };
wxFont m_font;
int m_min_value;
@@ -914,7 +927,7 @@ private:
ScalableBitmap m_bmp_one_layer_unlock_off;
ScalableBitmap m_bmp_revert;
ScalableBitmap m_bmp_cog;
- SelectedSlider m_selection;
+ SelectedSlider m_selection;
bool m_is_left_down = false;
bool m_is_right_down = false;
bool m_is_one_layer = false;
@@ -926,9 +939,10 @@ private:
bool m_show_edit_menu = false;
bool m_edit_extruder_sequence = false;
bool m_suppress_add_code = false;
- ManipulationState m_state = msSingleExtruder;
+ t_mode m_mode = t_mode::SingleExtruder;
std::string m_custom_gcode = "";
std::string m_pause_print_msg;
+ int m_only_extruder = -1;
wxRect m_rect_lower_thumb;
wxRect m_rect_higher_thumb;
@@ -957,50 +971,18 @@ private:
std::vector<wxPen*> m_line_pens;
std::vector<wxPen*> m_segm_pens;
- std::set<int> m_ticks;
std::vector<double> m_values;
-
- struct TICK_CODE
- {
- bool operator<(const TICK_CODE& other) const { return other.tick > this->tick; }
- bool operator>(const TICK_CODE& other) const { return other.tick < this->tick; }
-
- int tick = 0;
- std::string gcode = Slic3r::ColorChangeCode;
- int extruder = 0;
- std::string color;
- };
-
- std::set<TICK_CODE> m_ticks_;
+ std::set<TICK_CODE> m_ticks;
+ t_mode m_ticks_mode;
public:
struct ExtrudersSequence
{
- bool is_mm_intervals;
- double interval_by_mm;
- int interval_by_layers;
- std::vector<size_t> extruders;
-
- ExtrudersSequence() :
- is_mm_intervals(true),
- interval_by_mm(3.0),
- interval_by_layers(10),
- extruders({ 0 }) {}
-
- ExtrudersSequence(const ExtrudersSequence& other) :
- is_mm_intervals(other.is_mm_intervals),
- interval_by_mm(other.interval_by_mm),
- interval_by_layers(other.interval_by_layers),
- extruders(other.extruders) {}
-
- ExtrudersSequence& operator=(const ExtrudersSequence& other) {
- this->is_mm_intervals = other.is_mm_intervals;
- this->interval_by_mm = other.interval_by_mm;
- this->interval_by_layers= other.interval_by_layers;
- this->extruders = other.extruders;
-
- return *this;
- }
+ bool is_mm_intervals = true;
+ double interval_by_mm = 3.0;
+ int interval_by_layers = 10;
+ std::vector<size_t> extruders = { 0 };
+
bool operator==(const ExtrudersSequence& other) const
{
return (other.is_mm_intervals == this->is_mm_intervals ) &&