diff --git a/resources/profiles/PrusaResearch/mk2.svg b/resources/profiles/PrusaResearch/mk2.svg
index b8fa8d0cd7..6214a55523 100644
--- a/resources/profiles/PrusaResearch/mk2.svg
+++ b/resources/profiles/PrusaResearch/mk2.svg
@@ -1 +1,885 @@
-
\ No newline at end of file
+
+
diff --git a/resources/profiles/PrusaResearch/mk3.svg b/resources/profiles/PrusaResearch/mk3.svg
index c8f53373b5..03b24d572b 100644
--- a/resources/profiles/PrusaResearch/mk3.svg
+++ b/resources/profiles/PrusaResearch/mk3.svg
@@ -1 +1,883 @@
-
\ No newline at end of file
+
+
diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp
index 3284bc39e4..10e8598482 100644
--- a/src/libslic3r/ExtrusionEntity.cpp
+++ b/src/libslic3r/ExtrusionEntity.cpp
@@ -318,7 +318,7 @@ std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
case erIroning : return L("Ironing");
case erBridgeInfill : return L("Bridge infill");
case erGapFill : return L("Gap fill");
- case erSkirt : return L("Skirt");
+ case erSkirt : return L("Skirt/Brim");
case erSupportMaterial : return L("Support material");
case erSupportMaterialInterface : return L("Support material interface");
case erWipeTower : return L("Wipe tower");
@@ -349,7 +349,7 @@ ExtrusionRole ExtrusionEntity::string_to_role(const std::string_view role)
return erBridgeInfill;
else if (role == L("Gap fill"))
return erGapFill;
- else if (role == L("Skirt"))
+ else if (role == L("Skirt") || role == L("Skirt/Brim")) // "Skirt" is for backward compatibility with 2.3.1 and earlier
return erSkirt;
else if (role == L("Support material"))
return erSupportMaterial;
diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp
index 7a17909714..006595eb7d 100644
--- a/src/libslic3r/GCode/GCodeProcessor.cpp
+++ b/src/libslic3r/GCode/GCodeProcessor.cpp
@@ -857,6 +857,12 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_time_processor.export_remaining_time_enabled = config.remaining_times.value;
m_use_volumetric_e = config.use_volumetric_e;
+
+#if ENABLE_START_GCODE_VISUALIZATION
+ const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height");
+ if (first_layer_height != nullptr)
+ m_first_layer_height = std::abs(first_layer_height->value);
+#endif // ENABLE_START_GCODE_VISUALIZATION
}
void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
@@ -1035,6 +1041,12 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
const ConfigOptionBool* use_volumetric_e = config.option("use_volumetric_e");
if (use_volumetric_e != nullptr)
m_use_volumetric_e = use_volumetric_e->value;
+
+#if ENABLE_START_GCODE_VISUALIZATION
+ const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height");
+ if (first_layer_height != nullptr)
+ m_first_layer_height = std::abs(first_layer_height->value);
+#endif // ENABLE_START_GCODE_VISUALIZATION
}
void GCodeProcessor::enable_stealth_time_estimator(bool enabled)
@@ -1060,6 +1072,9 @@ void GCodeProcessor::reset()
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_line_id = 0;
+#if ENABLE_SEAMS_VISUALIZATION
+ m_last_line_id = 0;
+#endif // ENABLE_SEAMS_VISUALIZATION
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
m_feedrate = 0.0f;
m_width = 0.0f;
@@ -1082,6 +1097,10 @@ void GCodeProcessor::reset()
m_filament_diameters = std::vector(Min_Extruder_Count, 1.75f);
m_extruded_last_z = 0.0f;
+#if ENABLE_START_GCODE_VISUALIZATION
+ m_first_layer_height = 0.0f;
+ m_processing_start_custom_gcode = false;
+#endif // ENABLE_START_GCODE_VISUALIZATION
m_g1_line_id = 0;
m_layer_id = 0;
m_cp_color.reset();
@@ -1443,6 +1462,13 @@ void GCodeProcessor::process_tags(const std::string_view comment)
// extrusion role tag
if (boost::starts_with(comment, reserved_tag(ETags::Role))) {
m_extrusion_role = ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()));
+#if ENABLE_SEAMS_VISUALIZATION
+ if (m_extrusion_role == erExternalPerimeter)
+ m_seams_detector.activate(true);
+#endif // ENABLE_SEAMS_VISUALIZATION
+#if ENABLE_START_GCODE_VISUALIZATION
+ m_processing_start_custom_gcode = (m_extrusion_role == erCustom && m_g1_line_id == 0);
+#endif // ENABLE_START_GCODE_VISUALIZATION
return;
}
@@ -2187,7 +2213,11 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
}
+#if ENABLE_START_GCODE_VISUALIZATION
+ if (type == EMoveType::Extrude && (m_width == 0.0f || m_height == 0.0f))
+#else
if (type == EMoveType::Extrude && (m_extrusion_role == erCustom || m_width == 0.0f || m_height == 0.0f))
+#endif // ENABLE_START_GCODE_VISUALIZATION
type = EMoveType::Travel;
// time estimate section
@@ -2303,13 +2333,13 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
// Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
float jerk =
(v_exit > v_entry) ?
- (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
+ ((v_entry > 0.0f || v_exit < 0.0f) ?
// coasting
(v_exit - v_entry) :
// axis reversal
std::max(v_exit, -v_entry)) :
// v_exit <= v_entry
- (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
+ ((v_entry < 0.0f || v_exit > 0.0f) ?
// coasting
(v_entry - v_exit) :
// axis reversal
@@ -2330,7 +2360,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
float vmax_junction_threshold = vmax_junction * 0.99f;
// Not coasting. The machine will stop and start the movements anyway, better to start the segment from start.
- if ((prev.safe_feedrate > vmax_junction_threshold) && (curr.safe_feedrate > vmax_junction_threshold))
+ if (prev.safe_feedrate > vmax_junction_threshold && curr.safe_feedrate > vmax_junction_threshold)
vmax_junction = curr.safe_feedrate;
}
@@ -2354,6 +2384,31 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line)
machine.calculate_time(TimeProcessor::Planner::queue_size);
}
+#if ENABLE_SEAMS_VISUALIZATION
+ // check for seam starting vertex
+ if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && m_seams_detector.is_active() && !m_seams_detector.has_first_vertex())
+ m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[m_extruder_id]);
+ // check for seam ending vertex and store the resulting move
+ else if ((type != EMoveType::Extrude || m_extrusion_role != erExternalPerimeter) && m_seams_detector.is_active()) {
+ auto set_end_position = [this](const Vec3f& pos) {
+ m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z();
+ };
+
+ assert(m_seams_detector.has_first_vertex());
+ const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]);
+ const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[m_extruder_id];
+ const std::optional first_vertex = m_seams_detector.get_first_vertex();
+ // the threshold value = 0.25 is arbitrary, we may find some smarter condition later
+ if ((new_pos - *first_vertex).norm() < 0.25f) {
+ set_end_position(0.5f * (new_pos + *first_vertex));
+ store_move_vertex(EMoveType::Seam);
+ set_end_position(curr_pos);
+ }
+
+ m_seams_detector.activate(false);
+ }
+#endif // ENABLE_SEAMS_VISUALIZATION
+
// store move
store_move_vertex(type);
}
@@ -2807,15 +2862,29 @@ void GCodeProcessor::process_T(const std::string_view command)
void GCodeProcessor::store_move_vertex(EMoveType type)
{
+#if ENABLE_SEAMS_VISUALIZATION
+ m_last_line_id = (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ?
+ m_line_id + 1 :
+ ((type == EMoveType::Seam) ? m_last_line_id : m_line_id);
+#endif // ENABLE_SEAMS_VISUALIZATION
+
MoveVertex vertex = {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
+#if ENABLE_SEAMS_VISUALIZATION
+ m_last_line_id,
+#else
(type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : m_line_id,
+#endif // ENABLE_SEAMS_VISUALIZATION
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
type,
m_extrusion_role,
m_extruder_id,
m_cp_color.current,
+#if ENABLE_START_GCODE_VISUALIZATION
+ Vec3f(m_end_position[X], m_end_position[Y], m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id],
+#else
Vec3f(m_end_position[X], m_end_position[Y], m_end_position[Z]) + m_extruder_offsets[m_extruder_id],
+#endif // ENABLE_START_GCODE_VISUALIZATION
m_end_position[E] - m_start_position[E],
m_feedrate,
m_width,
diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp
index cf55bf86e7..75ec1546b3 100644
--- a/src/libslic3r/GCode/GCodeProcessor.hpp
+++ b/src/libslic3r/GCode/GCodeProcessor.hpp
@@ -12,6 +12,9 @@
#include
#include
#include
+#if ENABLE_SEAMS_VISUALIZATION
+#include
+#endif // ENABLE_SEAMS_VISUALIZATION
namespace Slic3r {
@@ -20,6 +23,9 @@ namespace Slic3r {
Noop,
Retract,
Unretract,
+#if ENABLE_SEAMS_VISUALIZATION
+ Seam,
+#endif // ENABLE_SEAMS_VISUALIZATION
Tool_change,
Color_change,
Pause_Print,
@@ -370,8 +376,7 @@ namespace Slic3r {
#if ENABLE_GCODE_VIEWER_STATISTICS
int64_t time{ 0 };
- void reset()
- {
+ void reset() {
time = 0;
moves = std::vector();
bed_shape = Pointfs();
@@ -380,8 +385,7 @@ namespace Slic3r {
settings_ids.reset();
}
#else
- void reset()
- {
+ void reset() {
moves = std::vector();
bed_shape = Pointfs();
extruder_colors = std::vector();
@@ -391,6 +395,29 @@ namespace Slic3r {
#endif // ENABLE_GCODE_VIEWER_STATISTICS
};
+#if ENABLE_SEAMS_VISUALIZATION
+ class SeamsDetector
+ {
+ bool m_active{ false };
+ std::optional m_first_vertex;
+
+ public:
+ void activate(bool active) {
+ if (m_active != active) {
+ m_active = active;
+ if (m_active)
+ m_first_vertex.reset();
+ }
+ }
+
+ std::optional get_first_vertex() const { return m_first_vertex; }
+ void set_first_vertex(const Vec3f& vertex) { m_first_vertex = vertex; }
+
+ bool is_active() const { return m_active; }
+ bool has_first_vertex() const { return m_first_vertex.has_value(); }
+ };
+#endif // ENABLE_SEAMS_VISUALIZATION
+
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
struct DataChecker
{
@@ -476,6 +503,9 @@ namespace Slic3r {
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
unsigned int m_line_id;
+#if ENABLE_SEAMS_VISUALIZATION
+ unsigned int m_last_line_id;
+#endif // ENABLE_SEAMS_VISUALIZATION
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
float m_feedrate; // mm/s
float m_width; // mm
@@ -490,10 +520,17 @@ namespace Slic3r {
ExtruderTemps m_extruder_temps;
std::vector m_filament_diameters;
float m_extruded_last_z;
+#if ENABLE_START_GCODE_VISUALIZATION
+ float m_first_layer_height; // mm
+ bool m_processing_start_custom_gcode;
+#endif // ENABLE_START_GCODE_VISUALIZATION
unsigned int m_g1_line_id;
unsigned int m_layer_id;
CpColor m_cp_color;
bool m_use_volumetric_e;
+#if ENABLE_SEAMS_VISUALIZATION
+ SeamsDetector m_seams_detector;
+#endif // ENABLE_SEAMS_VISUALIZATION
enum class EProducer
{
diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp
index 86a6616ee2..ae800a5ff0 100644
--- a/src/libslic3r/GCode/WipeTower.cpp
+++ b/src/libslic3r/GCode/WipeTower.cpp
@@ -639,9 +639,11 @@ std::vector WipeTower::prime(
float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f);
box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f);
- // In case of a circular bed, place it so it goes across the diameter and hope it will fit
- if (m_bed_shape == CircularBed)
- cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f);
+ if (m_bed_shape == CircularBed) {
+ cleaning_box = box_coordinates(Vec2f(0.f, 0.f), prime_section_width, 100.f);
+ float total_width_half = tools.size() * prime_section_width / 2.f;
+ cleaning_box.translate(-total_width_half, -std::sqrt(std::max(0.f, std::pow(m_bed_width/2, 2.f) - std::pow(1.05f * total_width_half, 2.f))));
+ }
else
cleaning_box.translate(m_bed_bottom_left);
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index d48443181f..8b829fc138 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -833,18 +833,6 @@ indexed_triangle_set ModelObject::raw_indexed_triangle_set() const
return out;
}
-// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
-TriangleMesh ModelObject::full_raw_mesh() const
-{
- TriangleMesh mesh;
- for (const ModelVolume *v : this->volumes)
- {
- TriangleMesh vol_mesh(v->mesh());
- vol_mesh.transform(v->get_matrix());
- mesh.merge(vol_mesh);
- }
- return mesh;
-}
const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
{
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 868639ee80..50797aeeb5 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -289,8 +289,6 @@ public:
TriangleMesh raw_mesh() const;
// The same as above, but producing a lightweight indexed_triangle_set.
indexed_triangle_set raw_indexed_triangle_set() const;
- // Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
- TriangleMesh full_raw_mesh() const;
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
const BoundingBoxf3& raw_bounding_box() const;
diff --git a/src/libslic3r/Optimize/Optimizer.hpp b/src/libslic3r/Optimize/Optimizer.hpp
index 05191eba26..8ae55c61c5 100644
--- a/src/libslic3r/Optimize/Optimizer.hpp
+++ b/src/libslic3r/Optimize/Optimizer.hpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
namespace Slic3r { namespace opt {
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index cbf3e71ab7..458ff19ce6 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -2207,6 +2207,7 @@ std::vector PrintObject::slice_volumes(
TriangleMesh vol_mesh(model_volume.mesh());
vol_mesh.transform(model_volume.get_matrix(), true);
mesh.merge(vol_mesh);
+ mesh.repair(false);
}
if (mesh.stl.stats.number_of_facets > 0) {
mesh.transform(m_trafo, true);
diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp
index 303ffe9274..a28d23bcc3 100644
--- a/src/libslic3r/Technologies.hpp
+++ b/src/libslic3r/Technologies.hpp
@@ -59,6 +59,10 @@
#define ENABLE_EXTENDED_M73_LINES (1 && ENABLE_VALIDATE_CUSTOM_GCODE)
// Enable a modified version of automatic downscale on load of objects too big
#define ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG (1 && ENABLE_2_4_0_ALPHA0)
+// Enable visualization of start gcode as regular toolpaths
+#define ENABLE_START_GCODE_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0)
+// Enable visualization of seams in preview
+#define ENABLE_SEAMS_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0)
#endif // _prusaslicer_technologies_h_
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index f8fa1ca17f..c6d35b2c3a 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -357,10 +357,14 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
its_transform(its, t);
if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
- this->repair(false);
- stl_reverse_all_facets(&stl);
- this->its.clear();
- this->require_shared_vertices();
+ // As for the assert: the repair function would fix the normals, reversing would
+ // break them again. The caller should provide a mesh that does not need repair.
+ // The repair call is left here so things don't break more than they were.
+ assert(this->repaired);
+ this->repair(false);
+ stl_reverse_all_facets(&stl);
+ this->its.clear();
+ this->require_shared_vertices();
}
}
@@ -369,11 +373,12 @@ void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
stl_transform(&stl, m);
its_transform(its, m);
if (fix_left_handed && m.determinant() < 0.) {
- // Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
+ // See comments in function above.
+ assert(this->repaired);
this->repair(false);
stl_reverse_all_facets(&stl);
- this->its.clear();
- this->require_shared_vertices();
+ this->its.clear();
+ this->require_shared_vertices();
}
}
diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp
index eacf69c917..ca1617bc29 100644
--- a/src/slic3r/GUI/GCodeViewer.cpp
+++ b/src/slic3r/GUI/GCodeViewer.cpp
@@ -143,6 +143,9 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const
case EMoveType::Custom_GCode:
case EMoveType::Retract:
case EMoveType::Unretract:
+#if ENABLE_SEAMS_VISUALIZATION
+ case EMoveType::Seam:
+#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Extrude: {
// use rounding to reduce the number of generated paths
#if ENABLE_SPLITTED_VERTEX_BUFFER
@@ -540,6 +543,9 @@ const std::vector GCodeViewer::Extrusion_Role_Colors {{
const std::vector GCodeViewer::Options_Colors {{
{ 0.803f, 0.135f, 0.839f }, // Retractions
{ 0.287f, 0.679f, 0.810f }, // Unretractions
+#if ENABLE_SEAMS_VISUALIZATION
+ { 0.900f, 0.900f, 0.900f }, // Seams
+#endif // ENABLE_SEAMS_VISUALIZATION
{ 0.758f, 0.744f, 0.389f }, // ToolChanges
{ 0.856f, 0.582f, 0.546f }, // ColorChanges
{ 0.322f, 0.942f, 0.512f }, // PausePrints
@@ -582,11 +588,20 @@ GCodeViewer::GCodeViewer()
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
+#if ENABLE_SEAMS_VISUALIZATION
+ case EMoveType::Unretract:
+ case EMoveType::Seam: {
+ buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
+ buffer.vertices.format = VBuffer::EFormat::Position;
+ break;
+ }
+#else
case EMoveType::Unretract: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
buffer.vertices.format = VBuffer::EFormat::Position;
break;
}
+#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
@@ -796,10 +811,18 @@ void GCodeViewer::render() const
case EMoveType::Pause_Print:
case EMoveType::Custom_GCode:
case EMoveType::Retract:
+#if ENABLE_SEAMS_VISUALIZATION
+ case EMoveType::Unretract:
+ case EMoveType::Seam: {
+ buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
+ break;
+ }
+#else
case EMoveType::Unretract: {
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
break;
}
+#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Wipe:
case EMoveType::Extrude: {
buffer.shader = "gouraud_light";
@@ -938,6 +961,9 @@ unsigned int GCodeViewer::get_options_visibility_flags() const
flags = set_flag(flags, static_cast(Preview::OptionType::Wipe), is_toolpath_move_type_visible(EMoveType::Wipe));
flags = set_flag(flags, static_cast(Preview::OptionType::Retractions), is_toolpath_move_type_visible(EMoveType::Retract));
flags = set_flag(flags, static_cast(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(EMoveType::Unretract));
+#if ENABLE_SEAMS_VISUALIZATION
+ flags = set_flag(flags, static_cast(Preview::OptionType::Seams), is_toolpath_move_type_visible(EMoveType::Seam));
+#endif // ENABLE_SEAMS_VISUALIZATION
flags = set_flag(flags, static_cast(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(EMoveType::Tool_change));
flags = set_flag(flags, static_cast(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(EMoveType::Color_change));
flags = set_flag(flags, static_cast(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(EMoveType::Pause_Print));
@@ -958,6 +984,9 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags)
set_toolpath_move_type_visible(EMoveType::Wipe, is_flag_set(static_cast(Preview::OptionType::Wipe)));
set_toolpath_move_type_visible(EMoveType::Retract, is_flag_set(static_cast(Preview::OptionType::Retractions)));
set_toolpath_move_type_visible(EMoveType::Unretract, is_flag_set(static_cast(Preview::OptionType::Unretractions)));
+#if ENABLE_SEAMS_VISUALIZATION
+ set_toolpath_move_type_visible(EMoveType::Seam, is_flag_set(static_cast(Preview::OptionType::Seams)));
+#endif // ENABLE_SEAMS_VISUALIZATION
set_toolpath_move_type_visible(EMoveType::Tool_change, is_flag_set(static_cast(Preview::OptionType::ToolChanges)));
set_toolpath_move_type_visible(EMoveType::Color_change, is_flag_set(static_cast(Preview::OptionType::ColorChanges)));
set_toolpath_move_type_visible(EMoveType::Pause_Print, is_flag_set(static_cast(Preview::OptionType::PausePrints)));
@@ -1595,13 +1624,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
const std::array first_seg_v_offsets = convert_vertices_offset(vbuffer_size, { 0, 1, 2, 3, 4, 5, 6, 7 });
const std::array non_first_seg_v_offsets = convert_vertices_offset(vbuffer_size, { -4, 0, -2, 1, 2, 3, 4, 5 });
-#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
-
+ bool is_first_segment = (last_path.vertices_count() == 1);
+ if (is_first_segment || vbuffer_size == 0) {
+#else
if (last_path.vertices_count() == 1 || vbuffer_size == 0) {
+#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// 1st segment or restart into a new vertex buffer
// ===============================================
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
- if (last_path.vertices_count() == 1)
+ if (is_first_segment)
// starting cap triangles
append_starting_cap_triangles(indices, first_seg_v_offsets);
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
@@ -1679,7 +1710,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
if (next != nullptr && (curr.type != next->type || !last_path.matches(*next)))
// ending cap triangles
- append_ending_cap_triangles(indices, non_first_seg_v_offsets);
+ append_ending_cap_triangles(indices, is_first_segment ? first_seg_v_offsets : non_first_seg_v_offsets);
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
last_path.sub_paths.back().last = { ibuffer_id, indices.size() - 1, move_id, curr.position };
@@ -1714,7 +1745,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// for the gcode viewer we need to take in account all moves to correctly size the printbed
m_paths_bounding_box.merge(move.position.cast());
else {
+#if ENABLE_START_GCODE_VISUALIZATION
+ if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f)
+#else
if (move.type == EMoveType::Extrude && move.width != 0.0f && move.height != 0.0f)
+#endif // ENABLE_START_GCODE_VISUALIZATION
m_paths_bounding_box.merge(move.position.cast());
}
}
@@ -3163,6 +3198,9 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
case EMoveType::Custom_GCode: { color = Options_Colors[static_cast(EOptionsColors::CustomGCodes)]; break; }
case EMoveType::Retract: { color = Options_Colors[static_cast(EOptionsColors::Retractions)]; break; }
case EMoveType::Unretract: { color = Options_Colors[static_cast(EOptionsColors::Unretractions)]; break; }
+#if ENABLE_SEAMS_VISUALIZATION
+ case EMoveType::Seam: { color = Options_Colors[static_cast(EOptionsColors::Seams)]; break; }
+#endif // ENABLE_SEAMS_VISUALIZATION
case EMoveType::Extrude: {
if (!top_layer_only ||
m_sequential_view.current.last == global_endpoints.last ||
@@ -4557,7 +4595,12 @@ void GCodeViewer::render_legend() const
available(EMoveType::Pause_Print) ||
available(EMoveType::Retract) ||
available(EMoveType::Tool_change) ||
+#if ENABLE_SEAMS_VISUALIZATION
+ available(EMoveType::Unretract) ||
+ available(EMoveType::Seam);
+#else
available(EMoveType::Unretract);
+#endif // ENABLE_SEAMS_VISUALIZATION
};
auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
@@ -4575,6 +4618,9 @@ void GCodeViewer::render_legend() const
// items
add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions"));
add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions"));
+#if ENABLE_SEAMS_VISUALIZATION
+ add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams"));
+#endif // ENABLE_SEAMS_VISUALIZATION
add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes"));
add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes"));
add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses"));
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index 051260b72c..2ccda6f5de 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -46,6 +46,9 @@ class GCodeViewer
{
Retractions,
Unretractions,
+#if ENABLE_SEAMS_VISUALIZATION
+ Seams,
+#endif // ENABLE_SEAMS_VISUALIZATION
ToolChanges,
ColorChanges,
PausePrints,
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 97038723bb..6dcd30c291 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1,7 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "GLCanvas3D.hpp"
-#include "admesh/stl.h"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
@@ -1682,8 +1681,10 @@ void GLCanvas3D::render()
if (m_picking_enabled)
m_mouse.scene_position = _mouse_to_3d(m_mouse.position.cast());
- _render_current_gizmo();
+ // sidebar hints need to be rendered before the gizmos because the depth buffer
+ // could be invalidated by the following gizmo render methods
_render_selection_sidebar_hints();
+ _render_current_gizmo();
#if ENABLE_RENDER_PICKING_PASS
}
#endif // ENABLE_RENDER_PICKING_PASS
@@ -4998,8 +4999,9 @@ void GLCanvas3D::_render_background() const
if (!m_volumes.empty())
use_error_color &= _is_any_volume_outside();
else {
- BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
- use_error_color &= (test_volume.radius() > 0.0) ? !test_volume.contains(m_gcode_viewer.get_paths_bounding_box()) : false;
+ const BoundingBoxf3 test_volume = (m_config != nullptr) ? print_volume(*m_config) : BoundingBoxf3();
+ const BoundingBoxf3& paths_volume = m_gcode_viewer.get_paths_bounding_box();
+ use_error_color &= (test_volume.radius() > 0.0 && paths_volume.radius() > 0.0) ? !test_volume.contains(paths_volume) : false;
}
}
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index 15c4578d82..75e384fd96 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -2896,7 +2896,8 @@ void ObjectList::update_selections()
{
const auto item = GetSelection();
if (selection.is_single_full_object()) {
- if (m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itObject)
+ if (m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itObject &&
+ m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx() )
return;
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
}
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index e67ddb0452..ea289bb146 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -235,7 +235,7 @@ bool Preview::init(wxWindow* parent, Model* model)
_L("Ironing") + "|1|" +
_L("Bridge infill") + "|1|" +
_L("Gap fill") + "|1|" +
- _L("Skirt") + "|1|" +
+ _L("Skirt/Brim") + "|1|" +
_L("Support material") + "|1|" +
_L("Support material interface") + "|1|" +
_L("Wipe tower") + "|1|" +
@@ -250,6 +250,9 @@ bool Preview::init(wxWindow* parent, Model* model)
get_option_type_string(OptionType::Wipe) + "|0|" +
get_option_type_string(OptionType::Retractions) + "|0|" +
get_option_type_string(OptionType::Unretractions) + "|0|" +
+#if ENABLE_SEAMS_VISUALIZATION
+ get_option_type_string(OptionType::Seams) + "|0|" +
+#endif // ENABLE_SEAMS_VISUALIZATION
get_option_type_string(OptionType::ToolChanges) + "|0|" +
get_option_type_string(OptionType::ColorChanges) + "|0|" +
get_option_type_string(OptionType::PausePrints) + "|0|" +
@@ -1008,6 +1011,9 @@ wxString Preview::get_option_type_string(OptionType type) const
case OptionType::Wipe: { return _L("Wipe"); }
case OptionType::Retractions: { return _L("Retractions"); }
case OptionType::Unretractions: { return _L("Deretractions"); }
+#if ENABLE_SEAMS_VISUALIZATION
+ case OptionType::Seams: { return _L("Seams"); }
+#endif // ENABLE_SEAMS_VISUALIZATION
case OptionType::ToolChanges: { return _L("Tool changes"); }
case OptionType::ColorChanges: { return _L("Color changes"); }
case OptionType::PausePrints: { return _L("Print pauses"); }
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index 3bf0e21ae3..d49e6e7ac1 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -116,6 +116,9 @@ public:
Wipe,
Retractions,
Unretractions,
+#if ENABLE_SEAMS_VISUALIZATION
+ Seams,
+#endif // ENABLE_SEAMS_VISUALIZATION
ToolChanges,
ColorChanges,
PausePrints,
diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp
index 9c426dcd96..666e3327b1 100644
--- a/src/slic3r/GUI/MainFrame.cpp
+++ b/src/slic3r/GUI/MainFrame.cpp
@@ -1483,10 +1483,10 @@ void MainFrame::repair_stl()
output_file = dlg.GetPath();
}
- auto tmesh = new Slic3r::TriangleMesh();
- tmesh->ReadSTLFile(input_file.ToUTF8().data());
- tmesh->repair();
- tmesh->WriteOBJFile(output_file.ToUTF8().data());
+ Slic3r::TriangleMesh tmesh;
+ tmesh.ReadSTLFile(input_file.ToUTF8().data());
+ tmesh.repair();
+ tmesh.WriteOBJFile(output_file.ToUTF8().data());
Slic3r::GUI::show_info(this, L("Your file was repaired."), L("Repair"));
}
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 5db983f43a..c0cda00425 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -976,7 +976,6 @@ void Sidebar::sys_color_changed()
for (PlaterPresetComboBox* combo : p->combos_filament)
combo->msw_rescale();
- p->frequently_changed_parameters->msw_rescale();
p->object_list->msw_rescale();
p->object_list->sys_color_changed();
p->object_manipulation->sys_color_changed();
@@ -5085,6 +5084,30 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
return;
+ // Following lambda generates a combined mesh for export with normals pointing outwards.
+ auto mesh_to_export = [](const ModelObject* mo, bool instances) -> TriangleMesh {
+ TriangleMesh mesh;
+ for (const ModelVolume *v : mo->volumes)
+ if (v->is_model_part()) {
+ TriangleMesh vol_mesh(v->mesh());
+ vol_mesh.repair();
+ vol_mesh.transform(v->get_matrix(), true);
+ mesh.merge(vol_mesh);
+ }
+ mesh.repair();
+ if (instances) {
+ TriangleMesh vols_mesh(mesh);
+ mesh = TriangleMesh();
+ for (const ModelInstance *i : mo->instances) {
+ TriangleMesh m = vols_mesh;
+ m.transform(i->get_matrix(), true);
+ mesh.merge(m);
+ }
+ }
+ mesh.repair();
+ return mesh;
+ };
+
TriangleMesh mesh;
if (p->printer_technology == ptFFF) {
if (selection_only) {
@@ -5092,20 +5115,21 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection.get_mode() == Selection::Instance)
{
if (selection.is_single_full_object())
- mesh = model_object->mesh();
+ mesh = mesh_to_export(model_object, true);
else
- mesh = model_object->full_raw_mesh();
+ mesh = mesh_to_export(model_object, false);
}
else
{
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
mesh = model_object->volumes[volume->volume_idx()]->mesh();
- mesh.transform(volume->get_volume_transformation().get_matrix());
+ mesh.transform(volume->get_volume_transformation().get_matrix(), true);
mesh.translate(-model_object->origin_translation.cast());
}
}
else {
- mesh = p->model.mesh();
+ for (const ModelObject *o : p->model.objects)
+ mesh.merge(mesh_to_export(o, true));
}
}
else
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index 2acb8cb85b..fd68737493 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -1217,7 +1217,7 @@ void Selection::render_center(bool gizmo_is_dragging) const
if (!m_valid || is_empty() || m_quadric == nullptr)
return;
- Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
+ const Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
glsafe(::glDisable(GL_DEPTH_TEST));
@@ -1286,7 +1286,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
} else {
glsafe(::glTranslated(center(0), center(1), center(2)));
if (requires_local_axes()) {
- Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
+ const Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
glsafe(::glMultMatrixd(orient_matrix.data()));
}
}
@@ -1976,7 +1976,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
if (pos == std::string::npos)
return;
- double min_z = std::stod(field.substr(pos + 1));
+ const double min_z = std::stod(field.substr(pos + 1));
// extract type
field = field.substr(0, pos);
@@ -1984,7 +1984,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
if (pos == std::string::npos)
return;
- int type = std::stoi(field.substr(pos + 1));
+ const int type = std::stoi(field.substr(pos + 1));
const BoundingBoxf3& box = get_bounding_box();
@@ -1995,8 +1995,8 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
// view dependend order of rendering to keep correct transparency
bool camera_on_top = wxGetApp().plater()->get_camera().is_looking_downward();
- float z1 = camera_on_top ? min_z : max_z;
- float z2 = camera_on_top ? max_z : min_z;
+ const float z1 = camera_on_top ? min_z : max_z;
+ const float z2 = camera_on_top ? max_z : min_z;
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_CULL_FACE));
@@ -2004,7 +2004,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
::glBegin(GL_QUADS);
- if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
+ if ((camera_on_top && type == 1) || (!camera_on_top && type == 2))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
@@ -2015,7 +2015,7 @@ void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) co
glsafe(::glEnd());
::glBegin(GL_QUADS);
- if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
+ if ((camera_on_top && type == 2) || (!camera_on_top && type == 1))
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
else
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);