diff --git a/resources/images/back_up_ts_bk.svg b/resources/images/back_up_ts_bk.svg
new file mode 100644
index 0000000000..75a6cbe0db
--- /dev/null
+++ b/resources/images/back_up_ts_bk.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/backup_current_use1.svg b/resources/images/backup_current_use1.svg
new file mode 100644
index 0000000000..c37817cfae
--- /dev/null
+++ b/resources/images/backup_current_use1.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/backup_current_use2.svg b/resources/images/backup_current_use2.svg
new file mode 100644
index 0000000000..30dfcdf41c
--- /dev/null
+++ b/resources/images/backup_current_use2.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/backup_tips_img.svg b/resources/images/backup_tips_img.svg
new file mode 100644
index 0000000000..0640f07390
--- /dev/null
+++ b/resources/images/backup_tips_img.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/resources/images/bar_publish.svg b/resources/images/bar_publish.svg
new file mode 100644
index 0000000000..51e5cb2d24
--- /dev/null
+++ b/resources/images/bar_publish.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/bbl_cali_lines.svg b/resources/images/bbl_cali_lines.svg
new file mode 100644
index 0000000000..a125cadd0b
--- /dev/null
+++ b/resources/images/bbl_cali_lines.svg
@@ -0,0 +1,17 @@
+
diff --git a/resources/images/block_notification_close.svg b/resources/images/block_notification_close.svg
new file mode 100644
index 0000000000..a55fe49f7c
--- /dev/null
+++ b/resources/images/block_notification_close.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/block_notification_close_hover.svg b/resources/images/block_notification_close_hover.svg
new file mode 100644
index 0000000000..afb1dc2a7d
--- /dev/null
+++ b/resources/images/block_notification_close_hover.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/block_notification_error.svg b/resources/images/block_notification_error.svg
new file mode 100644
index 0000000000..902027fae7
--- /dev/null
+++ b/resources/images/block_notification_error.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/go_last_plate.svg b/resources/images/go_last_plate.svg
new file mode 100644
index 0000000000..b5192f2774
--- /dev/null
+++ b/resources/images/go_last_plate.svg
@@ -0,0 +1,18 @@
+
diff --git a/resources/images/go_next_plate.svg b/resources/images/go_next_plate.svg
new file mode 100644
index 0000000000..cf7ee8a4cb
--- /dev/null
+++ b/resources/images/go_next_plate.svg
@@ -0,0 +1,18 @@
+
diff --git a/resources/images/link_more_error_close.svg b/resources/images/link_more_error_close.svg
new file mode 100644
index 0000000000..4fb473c659
--- /dev/null
+++ b/resources/images/link_more_error_close.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/link_more_error_open.svg b/resources/images/link_more_error_open.svg
new file mode 100644
index 0000000000..06abce1fb4
--- /dev/null
+++ b/resources/images/link_more_error_open.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/model_time.svg b/resources/images/model_time.svg
new file mode 100644
index 0000000000..0808f4545d
--- /dev/null
+++ b/resources/images/model_time.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/model_weight.svg b/resources/images/model_weight.svg
new file mode 100644
index 0000000000..31417e6569
--- /dev/null
+++ b/resources/images/model_weight.svg
@@ -0,0 +1,6 @@
+
diff --git a/resources/images/monitir_err_close.svg b/resources/images/monitir_err_close.svg
new file mode 100644
index 0000000000..745e129dac
--- /dev/null
+++ b/resources/images/monitir_err_close.svg
@@ -0,0 +1,5 @@
+
diff --git a/resources/images/monitir_err_open.svg b/resources/images/monitir_err_open.svg
new file mode 100644
index 0000000000..f396d2a8f7
--- /dev/null
+++ b/resources/images/monitir_err_open.svg
@@ -0,0 +1,5 @@
+
diff --git a/resources/images/plate_name_edit.svg b/resources/images/plate_name_edit.svg
new file mode 100644
index 0000000000..c9266a127f
--- /dev/null
+++ b/resources/images/plate_name_edit.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/plate_name_edit_dark.svg b/resources/images/plate_name_edit_dark.svg
new file mode 100644
index 0000000000..c9266a127f
--- /dev/null
+++ b/resources/images/plate_name_edit_dark.svg
@@ -0,0 +1,3 @@
+
diff --git a/resources/images/plate_name_edit_hover.svg b/resources/images/plate_name_edit_hover.svg
new file mode 100644
index 0000000000..9359cd74b5
--- /dev/null
+++ b/resources/images/plate_name_edit_hover.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/plate_name_edit_hover_dark.svg b/resources/images/plate_name_edit_hover_dark.svg
new file mode 100644
index 0000000000..a9840d5ca9
--- /dev/null
+++ b/resources/images/plate_name_edit_hover_dark.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/toolbar_meshboolean.svg b/resources/images/toolbar_meshboolean.svg
new file mode 100644
index 0000000000..ecfc8349d3
--- /dev/null
+++ b/resources/images/toolbar_meshboolean.svg
@@ -0,0 +1,13 @@
+
diff --git a/resources/images/toolbar_meshboolean_dark.svg b/resources/images/toolbar_meshboolean_dark.svg
new file mode 100644
index 0000000000..7643f71734
--- /dev/null
+++ b/resources/images/toolbar_meshboolean_dark.svg
@@ -0,0 +1,13 @@
+
diff --git a/resources/images/transparent.svg b/resources/images/transparent.svg
new file mode 100644
index 0000000000..ee71b59f7b
--- /dev/null
+++ b/resources/images/transparent.svg
@@ -0,0 +1,21 @@
+
diff --git a/resources/images/transparent_ams_item.svg b/resources/images/transparent_ams_item.svg
new file mode 100644
index 0000000000..6991cfa546
--- /dev/null
+++ b/resources/images/transparent_ams_item.svg
@@ -0,0 +1,21 @@
+
\ No newline at end of file
diff --git a/resources/images/transparent_ams_lib.svg b/resources/images/transparent_ams_lib.svg
new file mode 100644
index 0000000000..fa2a0b65f2
--- /dev/null
+++ b/resources/images/transparent_ams_lib.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/transparent_color_picker.svg b/resources/images/transparent_color_picker.svg
new file mode 100644
index 0000000000..5a41befa3f
--- /dev/null
+++ b/resources/images/transparent_color_picker.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/transparent_mapping_item.svg b/resources/images/transparent_mapping_item.svg
new file mode 100644
index 0000000000..f1e577439a
--- /dev/null
+++ b/resources/images/transparent_mapping_item.svg
@@ -0,0 +1,76 @@
+
diff --git a/resources/images/transparent_material_item.svg b/resources/images/transparent_material_item.svg
new file mode 100644
index 0000000000..9436fd87a9
--- /dev/null
+++ b/resources/images/transparent_material_item.svg
@@ -0,0 +1,11 @@
+
diff --git a/resources/images/ts_bitmap_cube.svg b/resources/images/ts_bitmap_cube.svg
new file mode 100644
index 0000000000..9a8403aff1
--- /dev/null
+++ b/resources/images/ts_bitmap_cube.svg
@@ -0,0 +1,4 @@
+
diff --git a/resources/images/ts_custom_color_picker.svg b/resources/images/ts_custom_color_picker.svg
new file mode 100644
index 0000000000..90b418a863
--- /dev/null
+++ b/resources/images/ts_custom_color_picker.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp
index c1fd07e3ca..72f58a1355 100644
--- a/src/BambuStudio.cpp
+++ b/src/BambuStudio.cpp
@@ -341,8 +341,9 @@ const float bed3d_ax3s_default_tip_length = 5.0f;
int CLI::run(int argc, char **argv)
{
// Mark the main thread for the debugger and for runtime checks.
- set_current_thread_name("bambustu_main");
-
+ set_current_thread_name("orcaslicer_main");
+ // Save the thread ID of the main thread.
+ save_main_thread_id();
#ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
// startup if gtk3 is used. This env var has to be set explicitly to
@@ -2993,7 +2994,7 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
#if defined(_MSC_VER) || defined(__MINGW32__)
extern "C" {
- __declspec(dllexport) int __stdcall bambustu_main(int argc, wchar_t **argv)
+ __declspec(dllexport) int __stdcall orcaslicer_main(int argc, wchar_t **argv)
{
// Convert wchar_t arguments to UTF8.
std::vector argv_narrow;
diff --git a/src/BambuStudio_app_msvc.cpp b/src/BambuStudio_app_msvc.cpp
index 1537f5cb68..b0509d1a9f 100644
--- a/src/BambuStudio_app_msvc.cpp
+++ b/src/BambuStudio_app_msvc.cpp
@@ -204,7 +204,7 @@ bool OpenGLVersionCheck::message_pump_exit = false;
extern "C" {
typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
- Slic3rMainFunc bambustu_main = nullptr;
+ Slic3rMainFunc orcaslicer_main = nullptr;
}
extern "C" {
@@ -292,19 +292,19 @@ int wmain(int argc, wchar_t **argv)
}
// resolve function address here
- bambustu_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
+ orcaslicer_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
#ifdef _WIN64
// there is just a single calling conversion, therefore no mangling of the function name.
- "bambustu_main"
+ "orcaslicer_main"
#else // stdcall calling convention declaration
"_bambustu_main@8"
#endif
);
- if (bambustu_main == nullptr) {
- printf("could not locate the function bambustu_main in OrcaSlicer.dll\n");
+ if (orcaslicer_main == nullptr) {
+ printf("could not locate the function orcaslicer_main in OrcaSlicer.dll\n");
return -1;
}
// argc minus the trailing nullptr of the argv
- return bambustu_main((int)argv_extended.size() - 1, argv_extended.data());
+ return orcaslicer_main((int)argv_extended.size() - 1, argv_extended.data());
}
}
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index cdb6275cec..1774eb28ac 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -193,6 +193,10 @@ namespace ImGui
const wchar_t CollapseBtn = 0x0831;
const wchar_t RevertBtn = 0x0832;
+ const wchar_t CloseBlockNotifButton = 0x0833;
+ const wchar_t CloseBlockNotifHoverButton = 0x0834;
+ const wchar_t BlockNotifErrorIcon = 0x0835;
+
// void MyFunction(const char* name, const MyMatrix44& v);
}
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index 0c5ea4a606..5c838b3673 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -461,6 +461,11 @@ public:
const PrintObjects& objects() const { return m_objects; }
// PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects
// in the notification center.
+ const SLAPrintObject* get_print_object_by_model_object_id(ObjectID object_id) const {
+ auto it = std::find_if(m_objects.begin(), m_objects.end(),
+ [object_id](const SLAPrintObject* obj) { return obj->model_object()->id() == object_id; });
+ return (it == m_objects.end()) ? nullptr : *it;
+ }
const SLAPrintObject* get_object(ObjectID object_id) const {
auto it = std::find_if(m_objects.begin(), m_objects.end(),
[object_id](const SLAPrintObject *obj) { return obj->id() == object_id; });
diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index fc1a43a27d..b1568646f6 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -137,6 +137,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Gizmos/GLGizmoSeam.hpp
GUI/Gizmos/GLGizmoText.cpp
GUI/Gizmos/GLGizmoText.hpp
+ GUI/Gizmos/GLGizmoMeshBoolean.cpp
+ GUI/Gizmos/GLGizmoMeshBoolean.hpp
GUI/GLSelectionRectangle.cpp
GUI/GLSelectionRectangle.hpp
GUI/Gizmos/GizmoObjectManipulation.cpp
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp
index 6198bf31db..06fec07eea 100644
--- a/src/slic3r/GUI/3DScene.cpp
+++ b/src/slic3r/GUI/3DScene.cpp
@@ -71,30 +71,34 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
// BBS
std::vector> get_extruders_colors()
{
- unsigned char rgb_color[3] = {};
- std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
+ unsigned char rgba_color[4] = {};
+ std::vector colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::vector> colors_out(colors.size());
- for (const std::string& color : colors) {
- Slic3r::GUI::BitmapCache::parse_color(color, rgb_color);
- size_t color_idx = &color - &colors.front();
- colors_out[color_idx] = { float(rgb_color[0]) / 255.f, float(rgb_color[1]) / 255.f, float(rgb_color[2]) / 255.f, 1.f };
+ for (const std::string &color : colors) {
+ Slic3r::GUI::BitmapCache::parse_color4(color, rgba_color);
+ size_t color_idx = &color - &colors.front();
+ colors_out[color_idx] = {
+ float(rgba_color[0]) / 255.f,
+ float(rgba_color[1]) / 255.f,
+ float(rgba_color[2]) / 255.f,
+ float(rgba_color[3]) / 255.f,
+ };
}
return colors_out;
}
-
-std::array adjust_color_for_rendering(const std::array& colors)
+float FullyTransparentMaterialThreshold = 0.1f;
+float FullTransparentModdifiedToFixAlpha = 0.3f;
+std::array adjust_color_for_rendering(const std::array &colors)
{
- if ((colors[0] < 0.1) && (colors[1] < 0.1) && (colors[2] < 0.1))
- {
- std::array new_color;
- new_color[0] = 0.1;
- new_color[1] = 0.1;
- new_color[2] = 0.1;
- new_color[3] = colors[3];
- return new_color;
- }
-
+ if (colors[3] < FullyTransparentMaterialThreshold) { // completely transparent
+ std::array new_color;
+ new_color[0] = 1;
+ new_color[1] = 1;
+ new_color[2] = 1;
+ new_color[3] = FullTransparentModdifiedToFixAlpha;
+ return new_color;
+ }
return colors;
}
@@ -514,8 +518,13 @@ void GLVolume::set_render_color()
}
}
- if (force_transparent)
- render_color[3] = color[3];
+ if (force_transparent) {
+ if (color[3] < FullyTransparentMaterialThreshold) {
+ render_color[3] = FullTransparentModdifiedToFixAlpha;
+ } else {
+ render_color[3] = color[3];
+ }
+ }
//BBS set unprintable color
if (!printable) {
@@ -1017,12 +1026,21 @@ void GLWipeTowerVolume::render(bool with_outline) const
}
this->iva_per_colors[i].render();
}
-
+
glsafe(::glPopMatrix());
if (this->is_left_handed())
glFrontFace(GL_CCW);
}
+bool GLWipeTowerVolume::IsTransparent() {
+ for (size_t i = 0; i < m_colors.size(); i++) {
+ if (m_colors[i][3] < 1.0f) {
+ return true;
+ }
+ }
+ return false;
+}
+
std::vector GLVolumeCollection::load_object(
const ModelObject *model_object,
int obj_idx,
@@ -1211,8 +1229,12 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
for (unsigned int i = 0; i < (unsigned int)volumes.size(); ++i) {
GLVolume* volume = volumes[i];
bool is_transparent = (volume->render_color[3] < 1.0f);
- if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) ||
- (type == GLVolumeCollection::ERenderType::Transparent && is_transparent) ||
+ auto tempGlwipeTowerVolume = dynamic_cast(volume);
+ if (tempGlwipeTowerVolume) {
+ is_transparent = tempGlwipeTowerVolume->IsTransparent();
+ }
+ if (((type == GLVolumeCollection::ERenderType::Opaque && !is_transparent) ||
+ (type == GLVolumeCollection::ERenderType::Transparent && is_transparent) ||
type == GLVolumeCollection::ERenderType::All) &&
(! filter_func || filter_func(*volume)))
list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0)));
@@ -1236,8 +1258,17 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
return list;
}
+int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_support) const
+{
+ const DynamicPrintConfig& glb_cfg = GUI::wxGetApp().preset_bundle->prints.get_edited_preset().config;
+ enable_support = glb_cfg.opt_bool("enable_support");
+ int support_threshold_angle = glb_cfg.opt_int("support_threshold_angle");
+ return support_threshold_angle ;
+}
+
//BBS: add outline drawing logic
-void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function filter_func, bool with_outline) const
+void GLVolumeCollection::render(
+ GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d &view_matrix, std::function filter_func, bool with_outline) const
{
GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func);
if (to_render.empty())
@@ -1305,10 +1336,16 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
//use -1 ad a invalid type
shader->set_uniform("print_volume.type", -1);
}
+
+ bool enable_support;
+ int support_threshold_angle = get_selection_support_threshold_angle(enable_support);
+
+ float normal_z = -::cos(Geometry::deg2rad((float) support_threshold_angle));
+
shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
- shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
+ shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower);
shader->set_uniform("slope.volume_world_normal_matrix", static_cast(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast()));
- shader->set_uniform("slope.normal_z", m_slope.normal_z);
+ shader->set_uniform("slope.normal_z", normal_z);
#if ENABLE_ENVIRONMENT_MAP
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
@@ -1496,34 +1533,35 @@ void GLVolumeCollection::reset_outside_state()
}
}
-void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config)
+void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig *config, bool is_update_alpha)
{
static const float inv_255 = 1.0f / 255.0f;
struct Color
{
std::string text;
- unsigned char rgb[3];
+ unsigned char rgba[4];
Color()
: text("")
{
- rgb[0] = 255;
- rgb[1] = 255;
- rgb[2] = 255;
+ rgba[0] = 255;
+ rgba[1] = 255;
+ rgba[2] = 255;
+ rgba[3] = 255;
}
- void set(const std::string& text, unsigned char* rgb)
+ void set(const std::string& text, unsigned char* rgba)
{
this->text = text;
- ::memcpy((void*)this->rgb, (const void*)rgb, 3 * sizeof(unsigned char));
+ ::memcpy((void*)this->rgba, (const void*)rgba, 4 * sizeof(unsigned char));
}
};
if (config == nullptr)
return;
- unsigned char rgb[3];
+ unsigned char rgba[4];
std::vector colors;
if (static_cast(config->opt_int("printer_technology")) == ptSLA)
@@ -1531,9 +1569,9 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
const std::string& txt_color = config->opt_string("material_colour").empty() ?
print_config_def.get("material_colour")->get_default_value()->value :
config->opt_string("material_colour");
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb)) {
+ if (Slic3r::GUI::BitmapCache::parse_color4(txt_color, rgba)) {
colors.resize(1);
- colors[0].set(txt_color, rgb);
+ colors[0].set(txt_color, rgba);
}
}
else
@@ -1549,8 +1587,8 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
for (unsigned int i = 0; i < colors_count; ++i) {
const std::string& txt_color = config->opt_string("filament_colour", i);
- if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
- colors[i].set(txt_color, rgb);
+ if (Slic3r::GUI::BitmapCache::parse_color4(txt_color, rgba))
+ colors[i].set(txt_color, rgba);
}
}
@@ -1564,8 +1602,14 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
const Color& color = colors[extruder_id];
if (!color.text.empty()) {
- for (int i = 0; i < 3; ++i) {
- volume->color[i] = (float)color.rgb[i] * inv_255;
+ for (int i = 0; i < 4; ++i) {
+ if (is_update_alpha == false) {
+ if (i < 3) {
+ volume->color[i] = (float) color.rgba[i] * inv_255;
+ }
+ continue;
+ }
+ volume->color[i] = (float) color.rgba[i] * inv_255;
}
}
}
diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp
index c61a4eb284..dcabb59946 100644
--- a/src/slic3r/GUI/3DScene.hpp
+++ b/src/slic3r/GUI/3DScene.hpp
@@ -31,7 +31,9 @@
#define glcheck()
#endif // HAS_GLSAFE
extern std::vector> get_extruders_colors();
-extern std::array adjust_color_for_rendering(const std::array& colors);
+extern float FullyTransparentMaterialThreshold;
+extern float FullTransparentModdifiedToFixAlpha;
+extern std::array adjust_color_for_rendering(const std::array &colors);
namespace Slic3r {
@@ -558,6 +560,7 @@ public:
virtual void render(bool with_outline = false) const;
std::vector iva_per_colors;
+ bool IsTransparent();
private:
std::vector> m_colors;
@@ -604,7 +607,8 @@ private:
struct Slope
{
// toggle for slope rendering
- bool active{ false };
+ bool active{ false };//local active
+ bool isGlobalActive{false};
float normal_z;
};
@@ -656,9 +660,14 @@ public:
GLVolume* new_toolpath_volume(const std::array& rgba, size_t reserve_vbo_floats = 0);
GLVolume* new_nontoolpath_volume(const std::array& rgba, size_t reserve_vbo_floats = 0);
+ int get_selection_support_threshold_angle(bool&) const;
// Render the volumes by OpenGL.
//BBS: add outline drawing logic
- void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function filter_func = std::function(), bool with_outline = true) const;
+ void render(ERenderType type,
+ bool disable_cullface,
+ const Transform3d & view_matrix,
+ std::function filter_func = std::function(),
+ bool with_outline = true) const;
// Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects
@@ -678,8 +687,10 @@ public:
void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
+ bool is_slope_GlobalActive() const { return m_slope.isGlobalActive; }
bool is_slope_active() const { return m_slope.active; }
void set_slope_active(bool active) { m_slope.active = active; }
+ void set_slope_GlobalActive(bool active) { m_slope.isGlobalActive = active; }
float get_slope_normal_z() const { return m_slope.normal_z; }
void set_slope_normal_z(float normal_z) { m_slope.normal_z = normal_z; }
@@ -691,7 +702,7 @@ public:
bool check_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const;
void reset_outside_state();
- void update_colors_by_extruder(const DynamicPrintConfig* config);
+ void update_colors_by_extruder(const DynamicPrintConfig *config, bool is_update_alpha = true);
// Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
std::vector get_current_print_zs(bool active_only) const;
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index f771b4d789..4bafdc7bf7 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -46,9 +46,10 @@ bool SlicingProcessCompletedEvent::critical_error() const
} catch (const Slic3r::SlicingError &) {
// Exception derived from SlicingError is non-critical.
return false;
- } catch (...) {
- }
- return true;
+ } catch (const Slic3r::SlicingErrors &) {
+ return false;
+ } catch (...) {}
+ return true;
}
bool SlicingProcessCompletedEvent::invalidate_plater() const
@@ -69,7 +70,7 @@ bool SlicingProcessCompletedEvent::invalidate_plater() const
return false;
}
-std::pair SlicingProcessCompletedEvent::format_error_message() const
+std::pair> SlicingProcessCompletedEvent::format_error_message() const
{
std::string error;
size_t monospace = 0;
@@ -88,12 +89,20 @@ std::pair SlicingProcessCompletedEvent::format_error_messag
} catch (SlicingError &ex) {
error = ex.what();
monospace = ex.objectId();
+ } catch (SlicingErrors &exs) {
+ std::vector ids;
+ for (auto &ex : exs.errors_) {
+ error = ex.what();
+ monospace = ex.objectId();
+ ids.push_back(monospace);
+ }
+ return std::make_pair(std::move(error), ids);
} catch (std::exception &ex) {
- error = ex.what();
- } catch (...) {
- error = "Unknown C++ exception.";
- }
- return std::make_pair(std::move(error), monospace);
+ error = ex.what();
+ } catch (...) {
+ error = "Unknown C++ exception.";
+ }
+ return std::make_pair(std::move(error), std::vector{monospace});
}
BackgroundSlicingProcess::BackgroundSlicingProcess()
@@ -308,6 +317,8 @@ void BackgroundSlicingProcess::thread_proc()
break;
// Process the background slicing task.
m_state = STATE_RUNNING;
+ //BBS: internal cancel
+ m_internal_cancelled = false;
lck.unlock();
std::exception_ptr exception;
#ifdef _WIN32
@@ -328,6 +339,10 @@ void BackgroundSlicingProcess::thread_proc()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": send SlicingProcessCompletedEvent to main, status %1%")%evt.status();
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
}
+ else {
+ //BBS: internal cancel
+ m_internal_cancelled = true;
+ }
m_print->restart();
lck.unlock();
// Let the UI thread wake up if it is waiting for the background task to finish.
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
index 90eebbbba8..b5b8ffcd7a 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp
@@ -60,7 +60,7 @@ public:
void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
// Produce a human readable message to be displayed by a notification or a message box.
// 2nd parameter defines whether the output should be displayed with a monospace font.
- std::pair format_error_message() const;
+ std::pair> format_error_message() const;
private:
StatusType m_status;
@@ -185,6 +185,7 @@ public:
//BBS: improve the finished logic, also judge the m_gcode_result
//bool finished() const { return m_print->finished(); }
bool finished() const { return m_print->finished() && !m_gcode_result->moves.empty(); }
+ bool is_internal_cancelled() { return m_internal_cancelled; }
//BBS: add Plater to friend class
//need to call stop_internal in ui thread
@@ -275,6 +276,7 @@ private:
//BBS: partplate related
GUI::PartPlate* m_current_plate;
PrinterTechnology m_printer_tech = ptUnknown;
+ bool m_internal_cancelled = false;
PrintState m_step_state;
bool set_step_started(BackgroundSlicingProcessStep step);
diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp
index 6c7cd77384..f1076069d0 100644
--- a/src/slic3r/GUI/BitmapCache.cpp
+++ b/src/slic3r/GUI/BitmapCache.cpp
@@ -375,7 +375,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
std::vector data(n_pixels * 4, 0);
// BBS: support resize by fill border
- if (scale_in_center > 0) {
+ if (scale_in_center > 0 && scale_in_center < svg_scale) {
int w = (int)(image->width * scale_in_center);
int h = (int)(image->height * scale_in_center);
::nsvgRasterize(rast, image, 0, 0, scale_in_center, data.data() + int(height - h) / 2 * width * 4 + int(width - w) / 2 * 4, w, h, width * 4);
@@ -433,6 +433,14 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
{
+ if (scolor.size() == 9) {
+ unsigned char rgba[4];
+ parse_color4(scolor, rgba);
+ rgb_out[0] = rgba[0];
+ rgb_out[1] = rgba[1];
+ rgb_out[2] = rgba[2];
+ return true;
+ }
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
if (scolor.size() != 7 || scolor.front() != '#')
return false;
@@ -444,6 +452,23 @@ bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
return false;
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
}
+
+ return true;
+}
+
+bool BitmapCache::parse_color4(const std::string& scolor, unsigned char* rgba_out)
+{
+ rgba_out[0] = rgba_out[1] = rgba_out[2] = 0; rgba_out[3] = 255;
+ if ((scolor.size() != 7 && scolor.size() != 9) || scolor.front() != '#')
+ return false;
+ const char* c = scolor.data() + 1;
+ for (size_t i = 0; i < scolor.size() / 2; ++i) {
+ int digit1 = hex_digit_to_int(*c++);
+ int digit2 = hex_digit_to_int(*c++);
+ if (digit1 == -1 || digit2 == -1)
+ return false;
+ rgba_out[i] = (unsigned char)(digit1 * 16 + digit2);
+ }
return true;
}
diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp
index 6d63b17e36..4803fa961d 100644
--- a/src/slic3r/GUI/BitmapCache.hpp
+++ b/src/slic3r/GUI/BitmapCache.hpp
@@ -48,6 +48,7 @@ public:
wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
+ static bool parse_color4(const std::string& scolor, unsigned char* rgba_out);
private:
std::map m_map;
diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp
index 2a3427ddfd..d66c136c82 100644
--- a/src/slic3r/GUI/GCodeViewer.hpp
+++ b/src/slic3r/GUI/GCodeViewer.hpp
@@ -835,10 +835,12 @@ public:
bool can_export_toolpaths() const;
std::vector get_plater_extruder();
+ const float get_max_print_height() const { return m_max_print_height; }
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
const BoundingBoxf3& get_shell_bounding_box() const { return m_shell_bounding_box; }
const std::vector& get_layers_zs() const { return m_layers.get_zs(); }
+ const std::array &get_layers_z_range() const { return m_layers_z_range; }
const SequentialView& get_sequential_view() const { return m_sequential_view; }
void update_sequential_view_current(unsigned int first, unsigned int last);
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 486d390025..1f1b60e8fc 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -748,7 +748,7 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_
}
// updates print order strings
- if (sorted_instances.size() > 1) {
+ if (sorted_instances.size() > 0) {
for (size_t i = 0; i < sorted_instances.size(); ++i) {
size_t id = sorted_instances[i]->id().id;
std::vector::iterator it = std::find_if(owners.begin(), owners.end(), [id](const Owner& owner) {
@@ -1296,6 +1296,15 @@ void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) {
m_gizmos.set_icon_dirty();
}
}
+ if (m_canvas_type == CanvasAssembleView) {
+ m_gizmos.on_change_color_mode(is_dark);
+ if (reinit) {
+ // reset svg
+ m_gizmos.switch_gizmos_icon_filename();
+ // set dirty to re-generate icon texture
+ m_gizmos.set_icon_dirty();
+ }
+ }
}
void GLCanvas3D::set_as_dirty()
@@ -1614,6 +1623,8 @@ void GLCanvas3D::enable_main_toolbar(bool enable)
void GLCanvas3D::reset_select_plate_toolbar_selection() {
if (m_sel_plate_toolbar.m_all_plates_stats_item)
m_sel_plate_toolbar.m_all_plates_stats_item->selected = false;
+ if (wxGetApp().mainframe)
+ wxGetApp().mainframe->update_slice_print_status(MainFrame::eEventSliceUpdate, true, true);
}
void GLCanvas3D::enable_select_plate_toolbar(bool enable)
@@ -1887,32 +1898,30 @@ void GLCanvas3D::render(bool only_init)
_render_selection();
if (!no_partplate)
_render_bed(!camera.is_looking_downward(), show_axes);
- //BBS: add outline logic
+ if (!no_partplate) //BBS: add outline logic
+ _render_platelist(!camera.is_looking_downward(), only_current, only_body, hover_id, true);
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
- if (!no_partplate)
- _render_platelist(!camera.is_looking_downward(), only_current, only_body, hover_id);
}
/* preview render */
else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) {
- //BBS: add outline logic
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
- //BBS: GUI refactor: add canvas size as parameters
- _render_gcode(cnv_size.get_width(), cnv_size.get_height());
_render_sla_slices();
_render_selection();
_render_bed(!camera.is_looking_downward(), show_axes);
_render_platelist(!camera.is_looking_downward(), only_current, true, hover_id);
+ // BBS: GUI refactor: add canvas size as parameters
+ _render_gcode(cnv_size.get_width(), cnv_size.get_height());
}
/* assemble render*/
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
//BBS: add outline logic
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
//_render_bed(!camera.is_looking_downward(), show_axes);
- //BBS: add outline logic
- _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
_render_plane();
//BBS: add outline logic insteadof selection under assemble view
//_render_selection();
+ // BBS: add outline logic
+ _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
}
_render_sequential_clearance();
@@ -2377,9 +2386,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
deleted_wipe_towers.emplace_back(volume, volume_id);
delete volume;
}
-
- // BBS
- m_explosion_ratio = 1.0;
}
else {
// This GLVolume will be reused.
@@ -2635,7 +2641,13 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
const float margin = 15.f;
BoundingBoxf3 plate_bbox = wxGetApp().plater()->get_partplate_list().get_plate(plate_id)->get_bounding_box();
+ coordf_t plate_bbox_x_max_local_coord = plate_bbox.max(0) - plate_origin(0);
coordf_t plate_bbox_y_max_local_coord = plate_bbox.max(1) - plate_origin(1);
+ if (x + margin + wipe_tower_size(0) > plate_bbox_x_max_local_coord) {
+ x = plate_bbox_x_max_local_coord - wipe_tower_size(0) - margin;
+ ConfigOptionFloat wt_x_opt(x);
+ dynamic_cast(proj_cfg.option("wipe_tower_x"))->set_at(&wt_x_opt, plate_id, 0);
+ }
if (y + margin + wipe_tower_size(1) > plate_bbox_y_max_local_coord) {
y = plate_bbox_y_max_local_coord - wipe_tower_size(1) - margin;
ConfigOptionFloat wt_y_opt(y);
@@ -2673,6 +2685,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
//BBS:exclude the assmble view
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
+ _set_warning_notification_if_needed(EWarning::GCodeConflict);
// checks for geometry outside the print volume to render it accordingly
if (!m_volumes.empty()) {
ModelInstanceEPrintVolumeState state;
@@ -2758,6 +2771,7 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co
if (wxGetApp().is_editor()) {
//BBS: always load shell at preview, do this in load_shells
//m_gcode_viewer.update_shells_color_by_extruder(m_config);
+ _set_warning_notification_if_needed(EWarning::ToolHeightOutside);
_set_warning_notification_if_needed(EWarning::ToolpathOutside);
_set_warning_notification_if_needed(EWarning::GCodeConflict);
}
@@ -2902,6 +2916,7 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
// BBS
//m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
+ _update_imgui_select_plate_toolbar();
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
m_dirty |= mouse3d_controller_applied;
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
@@ -3051,7 +3066,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#else /* __APPLE__ */
case WXK_CONTROL_Y:
#endif /* __APPLE__ */
- if (m_canvas_type == CanvasView3D) {
+ if (m_canvas_type == CanvasView3D || m_canvas_type == CanvasAssembleView) {
post_event(SimpleEvent(EVT_GLCANVAS_REDO));
}
break;
@@ -3062,7 +3077,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case WXK_CONTROL_Z:
#endif /* __APPLE__ */
// only support redu/undo in CanvasView3D
- if (m_canvas_type == CanvasView3D) {
+ if (m_canvas_type == CanvasView3D || m_canvas_type == CanvasAssembleView) {
post_event(SimpleEvent(EVT_GLCANVAS_UNDO));
}
break;
@@ -3477,7 +3492,10 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
}
else if (keyCode == WXK_CONTROL)
m_dirty = true;
- else if (m_gizmos.is_enabled() && !m_selection.is_empty() && m_canvas_type != CanvasAssembleView) {
+ else if (keyCode == WXK_TAB && evt.ShiftDown() && !evt.ControlDown() && !wxGetApp().is_gcode_viewer()) {
+ // Collapse side-panel with Shift+Tab
+ post_event(SimpleEvent(EVT_GLCANVAS_COLLAPSE_SIDEBAR));
+ } else if (m_gizmos.is_enabled() && !m_selection.is_empty() && m_canvas_type != CanvasAssembleView) {
auto _do_rotate = [this](double angle_z_rad) {
m_selection.start_dragging();
m_selection.rotate(Vec3d(0.0, 0.0, angle_z_rad), TransformationType(TransformationType::World_Relative_Joint));
@@ -3769,7 +3787,7 @@ void GLCanvas3D::on_gesture(wxGestureEvent &evt)
float z = 0;
const Vec3d &p2 = _mouse_to_3d({p.x, p.y}, &z);
const Vec3d &p1 = _mouse_to_3d({p.x - d.x, p.y - d.y}, &z);
- camera.set_target(camera.get_target() + p2 - p1);
+ camera.set_target(camera.get_target() + p1 - p2);
} else if (evt.GetEventType() == wxEVT_GESTURE_ZOOM) {
static float zoom_start = 1;
if (evt.IsGestureStart())
@@ -4151,7 +4169,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// if dragging over blank area with left button, rotate
if ((any_gizmo_active || m_hover_volume_idxs.empty()) && m_mouse.is_start_position_3D_defined()) {
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
- if (this->m_canvas_type == ECanvasType::CanvasAssembleView) {
+ if (this->m_canvas_type == ECanvasType::CanvasAssembleView || m_gizmos.get_current_type() == GLGizmosManager::FdmSupports ||
+ m_gizmos.get_current_type() == GLGizmosManager::Seam || m_gizmos.get_current_type() == GLGizmosManager::MmuSegmentation) {
//BBS rotate around target
Camera& camera = wxGetApp().plater()->get_camera();
Vec3d rotate_target = Vec3d::Zero();
@@ -4181,13 +4200,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
camera.recover_from_free_camera();
//BBS modify rotation
- if (m_gizmos.get_current_type() == GLGizmosManager::FdmSupports
- || m_gizmos.get_current_type() == GLGizmosManager::Seam
- || m_gizmos.get_current_type() == GLGizmosManager::MmuSegmentation) {
- //camera.rotate_local_with_target(Vec3d(rot.y(), rot.x(), 0.), rotate_target);
- camera.rotate_on_sphere_with_target(rot.x(), rot.y(), rotate_limit, rotate_target);
- }
- else if (evt.ControlDown() || evt.CmdDown()) {
+ //if (m_gizmos.get_current_type() == GLGizmosManager::FdmSupports
+ // || m_gizmos.get_current_type() == GLGizmosManager::Seam
+ // || m_gizmos.get_current_type() == GLGizmosManager::MmuSegmentation) {
+ // //camera.rotate_local_with_target(Vec3d(rot.y(), rot.x(), 0.), rotate_target);
+ // //camera.rotate_on_sphere_with_target(rot.x(), rot.y(), rotate_limit, rotate_target);
+ //}
+ //else
+ if (evt.ControlDown() || evt.CmdDown()) {
if ((m_rotation_center.x() == 0.f) && (m_rotation_center.y() == 0.f) && (m_rotation_center.z() == 0.f)) {
auto canvas_w = float(get_canvas_size().get_width());
auto canvas_h = float(get_canvas_size().get_height());
@@ -4280,7 +4300,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
wxGetApp().plater()->select_plate_by_hover_id(hover_idx);
//wxGetApp().plater()->get_partplate_list().select_plate_view();
//deselect all the objects
- if (m_hover_volume_idxs.empty())
+ if (m_gizmos.get_current_type() != GLGizmosManager::MeshBoolean && m_hover_volume_idxs.empty())
deselect_all();
}
else if (evt.RightUp() && !is_layers_editing_enabled()) {
@@ -5269,13 +5289,13 @@ bool GLCanvas3D::_render_orient_menu(float left, float right, float bottom, floa
if (imgui->checkbox(_L("Enable rotation"), settings.enable_rotation)) {
settings_out.enable_rotation = settings.enable_rotation;
- appcfg->set("orient", rot_key, settings_out.enable_rotation);
+ appcfg->set("orient", rot_key, settings_out.enable_rotation ? "1" : "0");
settings_changed = true;
}
if (imgui->checkbox(_L("Optimize support interface area"), settings.min_area)) {
settings_out.min_area = settings.min_area;
- appcfg->set("orient", key_min_area, settings_out.min_area);
+ appcfg->set("orient", key_min_area, settings_out.min_area ? "1" : "0");
settings_changed = true;
}
@@ -5292,8 +5312,8 @@ bool GLCanvas3D::_render_orient_menu(float left, float right, float bottom, floa
settings_out = OrientSettings{};
settings_out.overhang_angle = 60.f;
appcfg->set("orient", angle_key, std::to_string(settings_out.overhang_angle));
- appcfg->set("orient", rot_key, settings_out.enable_rotation );
- appcfg->set("orient", key_min_area, settings_out.min_area);
+ appcfg->set("orient", rot_key, settings_out.enable_rotation ? "1" : "0");
+ appcfg->set("orient", key_min_area, settings_out.min_area? "1" : "0");
settings_changed = true;
}
@@ -5644,7 +5664,8 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
curr_color[2] = vol->color[2];
curr_color[3] = vol->color[3];
- shader->set_uniform("uniform_color", curr_color);
+ std::array new_color = adjust_color_for_rendering(curr_color);
+ shader->set_uniform("uniform_color", new_color);
shader->set_uniform("volume_world_matrix", vol->world_matrix());
//BBS set all volume to orange
//shader->set_uniform("uniform_color", orange);
@@ -5683,6 +5704,8 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns
return;
bool multisample = OpenGLManager::can_multisample();
+ if (for_picking)
+ multisample = false;
//if (!multisample)
// glsafe(::glEnable(GL_MULTISAMPLE));
@@ -5789,6 +5812,8 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
return;
bool multisample = OpenGLManager::can_multisample();
+ if (for_picking)
+ multisample = false;
//if (!multisample)
// glsafe(::glEnable(GL_MULTISAMPLE));
@@ -6068,6 +6093,8 @@ bool GLCanvas3D::_init_main_toolbar()
wxGetApp().plater()->orient();
//BBS do not show orient menu
//_render_orient_menu(left, right, bottom, top);
+ NetworkAgent* agent = GUI::wxGetApp().getAgent();
+ if (agent) agent->track_update_property("auto_orient", std::to_string(++auto_orient_count));
}
};
if (!m_main_toolbar.add_item(item))
@@ -6664,9 +6691,9 @@ void GLCanvas3D::_render_bed_for_picking(bool bottom)
//m_bed.render_for_picking(*this, bottom, scale_factor);
}
-void GLCanvas3D::_render_platelist(bool bottom, bool only_current, bool only_body, int hover_id) const
+void GLCanvas3D::_render_platelist(bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali) const
{
- wxGetApp().plater()->get_partplate_list().render(bottom, only_current, only_body, hover_id);
+ wxGetApp().plater()->get_partplate_list().render(bottom, only_current, only_body, hover_id, render_cali);
}
void GLCanvas3D::_render_plates_for_picking() const
@@ -6739,7 +6766,10 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
else {
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
}
- m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances());
+ if (m_canvas_type == CanvasAssembleView)
+ m_volumes.set_show_sinking_contours(false);
+ else
+ m_volumes.set_show_sinking_contours(!m_gizmos.is_hiding_instances());
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
ECanvasType canvas_type = this->m_canvas_type;
@@ -7056,8 +7086,9 @@ void GLCanvas3D::_render_overlays()
if (m_layers_editing.last_object_id >= 0 && m_layers_editing.object_max_z() > 0.0f)
m_layers_editing.render_overlay(*this);
- const ConfigOptionEnum* opt = dynamic_cast*>(m_config->option>("print_sequence"));
- bool sequential_print = opt != nullptr && (opt->value == PrintSequence::ByObject);
+ auto curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
+ auto curr_print_seq = curr_plate->get_real_print_seq();
+ bool sequential_print = (curr_print_seq == PrintSequence::ByObject);
std::vector sorted_instances;
if (sequential_print) {
const Print* print = fff_print();
@@ -7230,9 +7261,6 @@ void GLCanvas3D::_render_gizmos_overlay()
const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale());
m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment
#endif /* __WXMSW__ */
- if (m_canvas_type == CanvasAssembleView)
- return;
-
m_gizmos.render_overlay();
if (m_gizmo_highlighter.m_render_arrow)
@@ -7394,7 +7422,6 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, scroll_col);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, button_active);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_hover);
- ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(128.0f, 128.0f, 128.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarSize, 10.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
@@ -7410,7 +7437,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
imgui.begin(_L("Select Plate"), ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse);
ImGui::SetWindowFontScale(1.2f);
- ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * f_scale);
ImVec2 size = ImVec2(button_width, button_height); // Size of the image we want to make visible
ImVec4 bg_col = ImVec4(128.0f, 128.0f, 128.0f, 0.0f);
@@ -7435,7 +7462,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
}
else {
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_hover);
- ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.42f, 0.42f, 0.42f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, button_hover);
}
}
@@ -7477,6 +7504,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImVec2 size = ImVec2(button_width, button_height * all_plates_stats_item->percent / 100.0f);
ImVec2 rect_start_pos = ImVec2(start_pos.x, start_pos.y + size.y);
ImVec2 rect_end_pos = ImVec2(start_pos.x + button_width, start_pos.y + button_height);
+ ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, rect_end_pos, IM_COL32(0, 0, 0, 10));
ImGui::GetForegroundDrawList()->AddRectFilled(rect_start_pos, rect_end_pos, IM_COL32(0, 0, 0, 80));
}
else if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICE_FAILED) {
@@ -7485,6 +7513,11 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(40, 1, 1, 64));
ImGui::GetForegroundDrawList()->AddRect(start_pos, end_pos, IM_COL32(208, 27, 27, 255), 0.0f, 0, 1.0f);
}
+ else if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICED) {
+ ImVec2 size = ImVec2(button_width, button_height);
+ ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y);
+ ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(0, 0, 0, 10));
+ }
// draw text
GImGui->FontSize = 15.0f;
@@ -7508,16 +7541,31 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImVec2 uv0 = ImVec2(0.0f, 1.0f); // UV coordinates for lower-left
ImVec2 uv1 = ImVec2(1.0f, 0.0f); // UV coordinates in our texture
+ auto button_pos = ImGui::GetCursorPos();
+ ImGui::SetCursorPos(button_pos + margin);
+
+ ImGui::Image(item->texture_id, size, uv0, uv1, tint_col);
+
+ ImGui::SetCursorPos(button_pos);
+
+ // invisible button
+ auto button_size = size + margin + margin + ImVec2(2 * frame_padding, 2 * frame_padding);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 2.0f * f_scale);
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
if (item->selected) {
- ImGui::PushStyleColor(ImGuiCol_Button, button_active);
- ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_active);
+ ImGui::PushStyleColor(ImGuiCol_Border, button_active);
}
else {
- ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(128.0f, 128.0f, 128.0f, 0.0f));
- ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.42f, 0.42f, 0.42f, 1.0f));
+ if (ImGui::IsMouseHoveringRect(button_pos, button_pos + button_size)) {
+ ImGui::PushStyleColor(ImGuiCol_Border, button_hover);
+ }
+ else {
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(.0f, .0f, .0f, .0f));
+ }
}
-
- if (ImGui::ImageButton2(item->texture_id, size, uv0, uv1, frame_padding, bg_col, tint_col, margin)) {
+ if(ImGui::Button("##invisible_button", button_size)){
if (m_process && !m_process->running()) {
all_plates_stats_item->selected = false;
item->selected = true;
@@ -7527,8 +7575,8 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
wxQueueEvent(wxGetApp().plater(), evt);
}
}
-
- ImGui::PopStyleColor(2);
+ ImGui::PopStyleColor(4);
+ ImGui::PopStyleVar();
ImVec2 start_pos = ImVec2(button_start_pos.x + frame_padding + margin.x, button_start_pos.y + frame_padding + margin.y);
if (item->slice_state == IMToolbarItem::SliceState::UNSLICED) {
@@ -7539,12 +7587,17 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImVec2 size = ImVec2(button_width, button_height * item->percent / 100.0f);
ImVec2 rect_start_pos = ImVec2(start_pos.x, start_pos.y + size.y);
ImVec2 rect_end_pos = ImVec2(start_pos.x + button_width, start_pos.y + button_height);
+ ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, rect_end_pos, IM_COL32(0, 0, 0, 10));
ImGui::GetForegroundDrawList()->AddRectFilled(rect_start_pos, rect_end_pos, IM_COL32(0, 0, 0, 80));
} else if (item->slice_state == IMToolbarItem::SliceState::SLICE_FAILED) {
ImVec2 size = ImVec2(button_width, button_height);
ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y);
ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(40, 1, 1, 64));
ImGui::GetForegroundDrawList()->AddRect(start_pos, end_pos, IM_COL32(208, 27, 27, 255), 0.0f, 0, 1.0f);
+ } else if (item->slice_state == IMToolbarItem::SliceState::SLICED) {
+ ImVec2 size = ImVec2(button_width, button_height);
+ ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y);
+ ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(0, 0, 0, 10));
}
// draw text
@@ -7554,7 +7607,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
ImGui::PopID();
}
ImGui::SetWindowFontScale(1.0f);
- ImGui::PopStyleColor(9);
+ ImGui::PopStyleColor(8);
ImGui::PopStyleVar(5);
if (ImGui::IsWindowHovered() || is_hovered) {
@@ -7645,6 +7698,8 @@ void GLCanvas3D::_render_return_toolbar() const
if (ImGui::ImageTextButton(real_size,_utf8(L("return")).c_str(), m_return_toolbar.get_return_texture_id(), button_icon_size, uv0, uv1, -1, bg_col, tint_col, margin)) {
if (m_canvas != nullptr)
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
+ const_cast(&m_gizmos)->reset_all_states();
+ wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().reset_all_states();
}
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(1);
@@ -7846,6 +7901,7 @@ void GLCanvas3D::_render_paint_toolbar() const
ImGui::BBLRenderArrow(draw_list, right_arrow_button.GetCenter() - ImVec2(draw_list->_Data->FontSize, draw_list->_Data->FontSize) * 0.5f, arrow_color, ImGuiDir_Right, 2.0f);
}
+ m_paint_toolbar_width = (ImGui::GetWindowWidth() + 50.0f * em_unit * f_scale);
imgui.end();
ImGui::PopStyleVar(3);
ImGui::PopStyleColor();
@@ -7858,6 +7914,10 @@ void GLCanvas3D::_render_assemble_control() const
GLVolume::explosion_ratio = m_explosion_ratio = 1.0;
return;
}
+ if (m_gizmos.get_current_type() == GLGizmosManager::EType::MmuSegmentation) {
+ m_gizmos.m_assemble_view_data->model_objects_clipper()->set_position(0.0, true);
+ return;
+ }
ImGuiWrapper* imgui = wxGetApp().imgui();
@@ -8845,15 +8905,22 @@ void GLCanvas3D::_set_warning_notification_if_needed(EWarning warning)
{
_set_current();
bool show = false;
- if (!m_volumes.empty())
+ if (!m_volumes.empty()) {
show = _is_any_volume_outside();
- else {
+ show &= m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
+ } else {
if (wxGetApp().is_editor()) {
- if (current_printer_technology() != ptSLA)
- if (warning == EWarning::ToolpathOutside)
- show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed();
- else if (warning==EWarning::GCodeConflict)
+ if (current_printer_technology() != ptSLA) {
+ unsigned int max_z_layer = m_gcode_viewer.get_layers_z_range().back();
+ if (warning == EWarning::ToolHeightOutside) // check if max z_layer height exceed max print height
+ show = m_gcode_viewer.has_data() && (m_gcode_viewer.get_layers_zs()[max_z_layer] - m_gcode_viewer.get_max_print_height() >= 1e-6);
+ else if (warning == EWarning::ToolpathOutside) { // check if max x,y coords exceed bed area
+ show = m_gcode_viewer.has_data() && !m_gcode_viewer.is_contained_in_bed() &&
+ (m_gcode_viewer.get_max_print_height() -m_gcode_viewer.get_layers_zs()[max_z_layer] >= 1e-6);
+ }
+ else if (warning == EWarning::GCodeConflict)
show = m_gcode_viewer.has_data() && m_gcode_viewer.is_contained_in_bed() && m_gcode_viewer.m_conflict_result.has_value();
+ }
}
}
@@ -8887,12 +8954,17 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
enum ErrorType{
PLATER_WARNING,
PLATER_ERROR,
+ SLICING_SERIOUS_WARNING,
SLICING_ERROR
};
std::string text;
ErrorType error = ErrorType::PLATER_WARNING;
+ const ModelObject* conflictObj=nullptr;
switch (warning) {
case EWarning::GCodeConflict: {
+ static std::string prevConflictText;
+ text = prevConflictText;
+ error = ErrorType::SLICING_SERIOUS_WARNING;
if (!m_gcode_viewer.m_conflict_result) { break; }
std::string objName1 = m_gcode_viewer.m_conflict_result.value()._objName1;
std::string objName2 = m_gcode_viewer.m_conflict_result.value()._objName2;
@@ -8901,10 +8973,13 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
text = (boost::format(_u8L("Conflicts of gcode paths have been found at layer %d, z = %.2lf mm. Please separate the conflicted objects farther (%s <-> %s).")) % layer %
height % objName1 % objName2)
.str();
- error = ErrorType::SLICING_ERROR;
+ prevConflictText = text;
+ const PrintObject *obj2 = reinterpret_cast(m_gcode_viewer.m_conflict_result.value()._obj2);
+ conflictObj = obj2->model_object();
break;
}
case EWarning::ObjectOutside: text = _u8L("An object is layed over the boundary of plate."); break;
+ case EWarning::ToolHeightOutside: text = _u8L("A G-code path goes beyond the max print height."); error = ErrorType::SLICING_ERROR; break;
case EWarning::ToolpathOutside: text = _u8L("A G-code path goes beyond the boundary of plate."); error = ErrorType::SLICING_ERROR; break;
// BBS: remove _u8L() for SLA
case EWarning::SlaSupportsOutside: text = ("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
@@ -8920,25 +8995,6 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
return;
auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
- if (warning == EWarning::GCodeConflict && m_gcode_viewer.m_conflict_result) {
- const PrintObject *obj2 = reinterpret_cast(m_gcode_viewer.m_conflict_result.value()._obj2);
- auto mo = obj2->model_object();
- ObjectID id = mo->id();
- auto action_fn = [id](wxEvtHandler *) {
- auto &objects = wxGetApp().model().objects;
- auto iter = id.id ? std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; }) : objects.end();
- if (iter != objects.end()) {
- wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
- wxGetApp().obj_list()->select_items({{*iter, nullptr}});
- }
- return false;
- };
- auto hypertext = _u8L("Jump to");
- hypertext += std::string(" [") + mo->name + "]";
- notification_manager.push_notification(NotificationType::PlaterError, NotificationManager::NotificationLevel::ErrorNotificationLevel, _u8L("ERROR:") + "\n" + text,
- hypertext, action_fn);
- return;
- }
switch (error)
{
case PLATER_WARNING:
@@ -8953,9 +9009,15 @@ void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
else
notification_manager.close_plater_error_notification(text);
break;
+ case SLICING_SERIOUS_WARNING:
+ if (state)
+ notification_manager.push_slicing_serious_warning_notification(text, {conflictObj});
+ else
+ notification_manager.close_slicing_serious_warning_notification(text);
+ break;
case SLICING_ERROR:
if (state)
- notification_manager.push_slicing_error_notification(text, nullptr);
+ notification_manager.push_slicing_error_notification(text, {conflictObj});
else
notification_manager.close_slicing_error_notification(text);
break;
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 8beb998384..1f2b090f39 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -373,7 +373,8 @@ class GLCanvas3D
SlaSupportsOutside,
SomethingNotShown,
ObjectClashed,
- GCodeConflict
+ GCodeConflict,
+ ToolHeightOutside
};
class RenderStats
@@ -439,6 +440,8 @@ class GLCanvas3D
bool is_enabled() const { return m_enabled; }
void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); }
bool is_used() const { return m_volumes.is_slope_active(); }
+ void globalUse(bool use) { m_volumes.set_slope_GlobalActive(m_enabled ? use : false); }
+ bool is_GlobalUsed() const { return m_volumes.is_slope_GlobalActive(); }
void set_normal_angle(float angle_in_deg) const {
m_volumes.set_slope_normal_z(-::cos(Geometry::deg2rad(90.0f - angle_in_deg)));
}
@@ -515,6 +518,7 @@ private:
mutable IMToolbar m_sel_plate_toolbar;
mutable GLToolbar m_assemble_view_toolbar;
mutable IMReturnToolbar m_return_toolbar;
+ mutable float m_paint_toolbar_width;
//BBS: add canvas type for assemble view usage
ECanvasType m_canvas_type;
@@ -619,6 +623,15 @@ private:
ArrangeSettings &get_arrange_settings() { return get_arrange_settings(this); }
+
+ //BBS:record key botton frequency
+ int auto_orient_count = 0;
+ int auto_arrange_count = 0;
+ int split_to_objects_count = 0;
+ int split_to_part_count = 0;
+ int custom_height_count = 0;
+ int custom_painting_count = 0;
+
public:
OrientSettings& get_orient_settings()
{
@@ -707,6 +720,7 @@ public:
bool init();
void post_event(wxEvent &&event);
+ void reset_explosion_ratio() { m_explosion_ratio = 1.0; }
void on_change_color_mode(bool is_dark, bool reinit = true);
const bool get_dark_mode_status() { return m_is_dark; }
void set_as_dirty();
@@ -716,6 +730,7 @@ public:
const GLVolumeCollection& get_volumes() const { return m_volumes; }
void reset_volumes();
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
+ bool is_all_plates_selected() { return m_sel_plate_toolbar.m_all_plates_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item->selected; }
const float get_scale() const;
//BBS
@@ -813,6 +828,7 @@ public:
float get_main_toolbar_width() { return m_main_toolbar.get_width();}
float get_assemble_view_toolbar_width() { return m_assemble_view_toolbar.get_width(); }
float get_assemble_view_toolbar_height() { return m_assemble_view_toolbar.get_height(); }
+ float get_assembly_paint_toolbar_width() { return m_paint_toolbar_width; }
float get_separator_toolbar_width() { return m_separator_toolbar.get_width(); }
float get_separator_toolbar_height() { return m_separator_toolbar.get_height(); }
float get_collapse_toolbar_width();
@@ -992,6 +1008,9 @@ public:
bool are_labels_shown() const { return m_labels.is_shown(); }
void show_labels(bool show) { m_labels.show(show); }
+ bool is_overhang_shown() const { return m_slope.is_GlobalUsed(); }
+ void show_overhang(bool show) { m_slope.globalUse(show); }
+
bool is_using_slope() const { return m_slope.is_used(); }
void use_slope(bool use) { m_slope.use(use); }
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
@@ -1093,7 +1112,7 @@ private:
void _render_bed(bool bottom, bool show_axes);
void _render_bed_for_picking(bool bottom);
//BBS: add part plate related logic
- void _render_platelist(bool bottom, bool only_current, bool only_body = false, int hover_id = -1) const;
+ void _render_platelist(bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false) const;
void _render_plates_for_picking() const;
//BBS: add outline drawing logic
void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true);
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index f55b3ccfce..7c72c79d16 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -3545,6 +3545,18 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio
}
}
+void ObjectList::add_objects_to_list(std::vector obj_idxs, bool call_selection_changed, bool notify_partplate, bool do_info_update)
+{
+#ifdef __WXOSX__
+ AssociateModel(nullptr);
+#endif
+ for (const size_t idx : obj_idxs) {
+ add_object_to_list(idx, call_selection_changed, notify_partplate, do_info_update);
+ }
+#ifdef __WXOSX__
+ AssociateModel(m_objects_model);
+#endif
+}
void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed, bool notify_partplate, bool do_info_update)
diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp
index 5793b59d3c..bafa0b5ba3 100644
--- a/src/slic3r/GUI/GUI_ObjectList.hpp
+++ b/src/slic3r/GUI/GUI_ObjectList.hpp
@@ -325,6 +325,8 @@ public:
void part_selection_changed();
// Add object to the list
+ // @param do_info_update: [Arthur] this function becomes slow as more functions are added, but I only need a fast version in FillBedJob, and I don't care about any info updates, so I pass a do_info_update param to skip all the uneccessary steps.
+ void add_objects_to_list(std::vector obj_idxs, bool call_selection_changed = true, bool notify_partplate = true, bool do_info_update = true);
void add_object_to_list(size_t obj_idx, bool call_selection_changed = true, bool notify_partplate = true, bool do_info_update = true);
// Add object's volumes to the list
// Return selected items, if add_to_selection is defined
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp
index dbc8281bf6..c851535d61 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoAdvancedCut.cpp
@@ -1297,7 +1297,7 @@ void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float b
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
unsigned int current_active_id = ImGui::GetActiveID();
- Vec3d rotation = {Geometry::rad2deg(m_rotation(0)), Geometry::rad2deg(m_rotation(1)), Geometry::rad2deg(m_rotation(2))};
+ Vec3d rotation = {Geometry::rad2deg(m_buffered_rotation(0)), Geometry::rad2deg(m_buffered_rotation(1)), Geometry::rad2deg(m_buffered_rotation(2))};
char buf[3][64];
float buf_size[3];
float vec_max = 0, unit_size = 0;
@@ -1450,6 +1450,10 @@ void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float b
m_imgui->disabled_begin(has_connectors);
m_imgui->bbl_checkbox(_L("Cut to parts"), m_cut_to_parts);
+ if (m_cut_to_parts) {
+ m_keep_upper = true;
+ m_keep_lower = true;
+ }
m_imgui->disabled_end();
#if 0
@@ -1585,7 +1589,9 @@ void GLGizmoAdvancedCut::render_connectors_input_window(float x, float y, float
if (render_combo(_u8L("Style"), connector_styles, m_connector_style))
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
m_imgui->disabled_end();
+ ImGuiWrapper::pop_combo_style();
+ ImGuiWrapper::push_combo_style(m_parent.get_scale());
if (render_combo(_u8L("Shape"), connector_shapes, m_connector_shape_id))
apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
ImGuiWrapper::pop_combo_style();
@@ -1728,11 +1734,13 @@ bool GLGizmoAdvancedCut::render_combo(const std::string &label, const std::vecto
bool GLGizmoAdvancedCut::render_slider_double_input(const std::string &label, float &value_in, float &tolerance_in)
{
+ // -------- [ ] -------- [ ]
+ // slider_with + item_in_gap + first_input_width + item_out_gap + slider_with + item_in_gap + second_input_width
double slider_with = 0.24 * m_editing_window_width; // m_control_width * 0.35;
double item_in_gap = 0.01 * m_editing_window_width;
- double item_out_gap = 0.02 * m_editing_window_width;
- double first_input_width = 0.33 * m_editing_window_width;
- double second_input_width = 0.15 * m_editing_window_width;
+ double item_out_gap = 0.01 * m_editing_window_width;
+ double first_input_width = 0.29 * m_editing_window_width;
+ double second_input_width = 0.29 * m_editing_window_width;
ImGui::AlignTextToFramePadding();
m_imgui->text(label);
@@ -1770,18 +1778,21 @@ bool GLGizmoAdvancedCut::render_slider_double_input(const std::string &label, fl
ImGui::SameLine(left_width);
ImGui::PushItemWidth(slider_with);
- float old_tolerance, tolerance = old_tolerance = tolerance_in * 100.f;
- std::string format_t = tolerance_in < 0.f ? " " : "%.f %%";
+ float tolerance = tolerance_in;
+ if (m_imperial_units)
+ tolerance *= float(units_mm_to_in);
+ float old_tolerance = tolerance;
+ //std::string format_t = tolerance_in < 0.f ? " " : "%.f %%";
float min_tolerance = tolerance_in < 0.f ? UndefMinVal : 0.f;
- m_imgui->bbl_slider_float_style(("##tolerance_" + label).c_str(), &tolerance, min_tolerance, 20.f, format_t.c_str(), 1.f, true, _L("Tolerance"));
+ m_imgui->bbl_slider_float_style(("##tolerance_" + label).c_str(), &tolerance, min_tolerance, 2.f, format.c_str(), 1.f, true, _L("Tolerance"));
left_width += (slider_with + item_in_gap);
ImGui::SameLine(left_width);
ImGui::PushItemWidth(second_input_width);
- ImGui::BBLDragFloat(("##tolerance_input_" + label).c_str(), &tolerance, 0.05f, min_tolerance, 20.f, format_t.c_str());
+ ImGui::BBLDragFloat(("##tolerance_input_" + label).c_str(), &tolerance, 0.05f, min_tolerance, 2.f, format.c_str());
- tolerance_in = tolerance * 0.01f;
+ tolerance_in = tolerance * float(m_imperial_units ? units_in_to_mm : 1.0);
return !is_approx(old_val, value) || !is_approx(old_tolerance, tolerance);
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
index ba8fd5280b..c725809bba 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp
@@ -191,6 +191,9 @@ public:
virtual std::string get_tooltip() const { return ""; }
+ int get_count() { return ++count; }
+ std::string get_gizmo_name() { return on_get_name(); }
+
protected:
float last_input_window_width = 0;
virtual bool on_init() = 0;
@@ -229,6 +232,7 @@ private:
// Flag for dirty visible state of Gizmo
// When True then need new rendering
bool m_dirty;
+ int count = 0;
};
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
index 06793ce7c0..c095c0915e 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp
@@ -186,7 +186,7 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
shader->set_uniform("volume_world_matrix", trafo_matrix);
shader->set_uniform("volume_mirrored", is_left_handed);
shader->set_uniform("slope.actived", m_parent.is_using_slope());
- shader->set_uniform("slope.volume_world_normal_matrix", static_cast(trafo_matrix.matrix().block(0, 0, 3, 3).inverse().transpose().cast()));
+ shader->set_uniform("slope.volume_world_normal_matrix", normal_matrix);
shader->set_uniform("slope.normal_z", normal_z);
m_triangle_selectors[mesh_id]->render(m_imgui);
@@ -290,7 +290,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0);
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
index 619cebb798..4ad8136bba 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp
@@ -141,6 +141,7 @@ void GLGizmoFlatten::update_planes()
// Following constants are used for discarding too small polygons.
const float minimal_area = 5.f; // in square mm (world coordinates)
const float minimal_side = 1.f; // mm
+ const float minimal_angle = 1.f; // degree, initial value was 10, but cause bugs
// Now we'll go through all the facets and append Points of facets sharing the same normal.
// This part is still performed in mesh coordinate system.
@@ -151,9 +152,9 @@ void GLGizmoFlatten::update_planes()
std::vector facet_visited(num_of_facets, false);
int facet_queue_cnt = 0;
const stl_normal* normal_ptr = nullptr;
+ int facet_idx = 0;
while (1) {
// Find next unvisited triangle:
- int facet_idx = 0;
for (; facet_idx < num_of_facets; ++ facet_idx)
if (!facet_visited[facet_idx]) {
facet_queue[facet_queue_cnt ++] = facet_idx;
@@ -235,7 +236,7 @@ void GLGizmoFlatten::update_planes()
discard = true;
else {
// We also check the inner angles and discard polygons with angles smaller than the following threshold
- const double angle_threshold = ::cos(10.0 * (double)PI / 180.0);
+ const double angle_threshold = ::cos(minimal_angle * (double)PI / 180.0);
for (unsigned int i = 0; i < polygon.size(); ++i) {
const Vec3d& prec = polygon[(i == 0) ? polygon.size() - 1 : i - 1];
@@ -250,7 +251,8 @@ void GLGizmoFlatten::update_planes()
}
if (discard) {
- m_planes.erase(m_planes.begin() + (polygon_id--));
+ m_planes[polygon_id--] = std::move(m_planes.back());
+ m_planes.pop_back();
continue;
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp
new file mode 100644
index 0000000000..10c2e32ce2
--- /dev/null
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.cpp
@@ -0,0 +1,466 @@
+#include "GLGizmoMeshBoolean.hpp"
+#include "slic3r/GUI/GLCanvas3D.hpp"
+#include "slic3r/GUI/ImGuiWrapper.hpp"
+#include "slic3r/GUI/GUI.hpp"
+#include "libslic3r/MeshBoolean.hpp"
+#include "slic3r/GUI/GUI_ObjectList.hpp"
+#include "slic3r/GUI/Plater.hpp"
+#include "slic3r/GUI/Camera.hpp"
+#include "slic3r/GUI/NotificationManager.hpp"
+#ifndef IMGUI_DEFINE_MATH_OPERATORS
+#define IMGUI_DEFINE_MATH_OPERATORS
+#endif
+#include
+namespace Slic3r {
+namespace GUI {
+
+static const std::string warning_text = _u8L("Unable to perform boolean operation on selected parts");
+
+GLGizmoMeshBoolean::GLGizmoMeshBoolean(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
+ : GLGizmoBase(parent, icon_filename, sprite_id)
+{
+}
+
+GLGizmoMeshBoolean::~GLGizmoMeshBoolean()
+{
+}
+
+bool GLGizmoMeshBoolean::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
+{
+ if (action == SLAGizmoEventType::LeftDown) {
+ const ModelObject* mo = m_c->selection_info()->model_object();
+ if (mo == nullptr)
+ return true;
+ const ModelInstance* mi = mo->instances[m_parent.get_selection().get_instance_idx()];
+ std::vector trafo_matrices;
+ for (const ModelVolume* mv : mo->volumes) {
+ //if (mv->is_model_part()) {
+ trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
+ //}
+ }
+
+ const Camera& camera = wxGetApp().plater()->get_camera();
+ Vec3f normal = Vec3f::Zero();
+ Vec3f hit = Vec3f::Zero();
+ size_t facet = 0;
+ Vec3f closest_hit = Vec3f::Zero();
+ Vec3f closest_normal = Vec3f::Zero();
+ double closest_hit_squared_distance = std::numeric_limits::max();
+ int closest_hit_mesh_id = -1;
+
+ // Cast a ray on all meshes, pick the closest hit and save it for the respective mesh
+ for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) {
+ MeshRaycaster mesh_raycaster = MeshRaycaster(mo->volumes[mesh_id]->mesh());
+ if (mesh_raycaster.unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal,
+ m_c->object_clipper()->get_clipping_plane(), &facet)) {
+ // Is this hit the closest to the camera so far?
+ double hit_squared_distance = (camera.get_position() - trafo_matrices[mesh_id] * hit.cast()).squaredNorm();
+ if (hit_squared_distance < closest_hit_squared_distance) {
+ closest_hit_squared_distance = hit_squared_distance;
+ closest_hit_mesh_id = mesh_id;
+ closest_hit = hit;
+ closest_normal = normal;
+ }
+ }
+ }
+
+ if (closest_hit == Vec3f::Zero() && closest_normal == Vec3f::Zero())
+ return true;
+
+ if (get_selecting_state() == MeshBooleanSelectingState::SelectTool) {
+ m_tool.trafo = trafo_matrices[closest_hit_mesh_id];
+ m_tool.volume_idx = closest_hit_mesh_id;
+ set_tool_volume(mo->volumes[closest_hit_mesh_id]);
+ return true;
+ }
+ if (get_selecting_state() == MeshBooleanSelectingState::SelectSource) {
+ m_src.trafo = trafo_matrices[closest_hit_mesh_id];
+ m_src.volume_idx = closest_hit_mesh_id;
+ set_src_volume(mo->volumes[closest_hit_mesh_id]);
+ m_selecting_state = MeshBooleanSelectingState::SelectTool;
+ return true;
+ }
+ }
+ return true;
+}
+
+bool GLGizmoMeshBoolean::on_init()
+{
+ m_shortcut_key = WXK_CONTROL_B;
+ return true;
+}
+
+std::string GLGizmoMeshBoolean::on_get_name() const
+{
+ return _u8L("Mesh Boolean");
+}
+
+bool GLGizmoMeshBoolean::on_is_activable() const
+{
+ return m_parent.get_selection().is_single_full_instance() && m_parent.get_selection().get_volume_idxs().size() > 1;
+}
+
+void GLGizmoMeshBoolean::on_render()
+{
+ if (m_parent.get_selection().get_object_idx() < 0)
+ return;
+ static ModelObject* last_mo = nullptr;
+ ModelObject* curr_mo = m_parent.get_selection().get_model()->objects[m_parent.get_selection().get_object_idx()];
+ if (last_mo != curr_mo) {
+ last_mo = curr_mo;
+ m_src.reset();
+ m_tool.reset();
+ m_operation_mode = MeshBooleanOperation::Union;
+ m_selecting_state = MeshBooleanSelectingState::SelectSource;
+ return;
+ }
+
+ BoundingBoxf3 src_bb;
+ BoundingBoxf3 tool_bb;
+ const ModelObject* mo = m_c->selection_info()->model_object();
+ const ModelInstance* mi = mo->instances[m_parent.get_selection().get_instance_idx()];
+ const Selection& selection = m_parent.get_selection();
+ const Selection::IndicesList& idxs = selection.get_volume_idxs();
+ for (unsigned int i : idxs) {
+ const GLVolume* volume = selection.get_volume(i);
+ if(volume->volume_idx() == m_src.volume_idx) {
+ src_bb = volume->transformed_convex_hull_bounding_box();
+ }
+ if (volume->volume_idx() == m_tool.volume_idx) {
+ tool_bb = volume->transformed_convex_hull_bounding_box();
+ }
+ }
+
+ float src_color[3] = { 1.0f, 1.0f, 1.0f };
+ float tool_color[3] = { 0.0f, 174.0f / 255.0f, 66.0f / 255.0f };
+ m_parent.get_selection().render_bounding_box(src_bb, src_color, m_parent.get_scale());
+ m_parent.get_selection().render_bounding_box(tool_bb, tool_color, m_parent.get_scale());
+}
+
+void GLGizmoMeshBoolean::on_set_state()
+{
+ if (m_state == EState::On) {
+ m_src.reset();
+ m_tool.reset();
+ bool m_diff_delete_input = false;
+ bool m_inter_delete_input = false;
+ m_operation_mode = MeshBooleanOperation::Union;
+ m_selecting_state = MeshBooleanSelectingState::SelectSource;
+ }
+ else if (m_state == EState::Off) {
+ m_src.reset();
+ m_tool.reset();
+ bool m_diff_delete_input = false;
+ bool m_inter_delete_input = false;
+ m_operation_mode = MeshBooleanOperation::Undef;
+ m_selecting_state = MeshBooleanSelectingState::Undef;
+ wxGetApp().notification_manager()->close_plater_warning_notification(warning_text);
+ }
+}
+
+CommonGizmosDataID GLGizmoMeshBoolean::on_get_requirements() const
+{
+ return CommonGizmosDataID(
+ int(CommonGizmosDataID::SelectionInfo)
+ | int(CommonGizmosDataID::InstancesHider)
+ | int(CommonGizmosDataID::Raycaster)
+ | int(CommonGizmosDataID::ObjectClipper));
+}
+
+void GLGizmoMeshBoolean::on_render_input_window(float x, float y, float bottom_limit)
+{
+ y = std::min(y, bottom_limit - ImGui::GetWindowHeight());
+
+ static float last_y = 0.0f;
+ static float last_w = 0.0f;
+
+ const float currt_scale = m_parent.get_scale();
+ ImGuiWrapper::push_toolbar_style(currt_scale);
+ GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 0.0f, 0.0f);
+ GizmoImguiBegin("MeshBoolean", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
+
+ const int max_tab_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(_L("Union").c_str()).x,
+ std::max(ImGui::CalcTextSize(_L("Difference").c_str()).x, ImGui::CalcTextSize(_L("Intersection").c_str()).x));
+ const int max_cap_length = ImGui::GetStyle().WindowPadding.x + ImGui::GetStyle().ItemSpacing.x + std::max(ImGui::CalcTextSize(_L("Source Volume").c_str()).x, ImGui::CalcTextSize(_L("Tool Volume").c_str()).x);
+ const int select_btn_length = 2 * ImGui::GetStyle().FramePadding.x + std::max(ImGui::CalcTextSize(("1 " + _L("selected")).c_str()).x, ImGui::CalcTextSize(_L("Select").c_str()).x);
+
+ auto selectable = [this](const wxString& label, bool selected, const ImVec2& size_arg) {
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 });
+
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ const ImVec2 label_size = ImGui::CalcTextSize(label.c_str(), NULL, true);
+ ImVec2 pos = window->DC.CursorPos;
+ ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + ImGui::GetStyle().FramePadding.x * 2.0f, label_size.y + ImGui::GetStyle().FramePadding.y * 2.0f);
+ bool hovered = ImGui::IsMouseHoveringRect(pos, pos + size);
+
+ if (selected || hovered) {
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Button, { 0, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f });
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f });
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f });
+ }
+ else {
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f });
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0, 174.0f / 255.0f, 66.0f / 255.0f, 1.0f });
+ }
+
+ bool res = ImGui::Button(label.c_str(), size_arg);
+
+ if (selected || hovered) {
+ ImGui::PopStyleColor(4);
+ }
+ else {
+ ImGui::PopStyleColor(2);
+ }
+
+ ImGui::PopStyleVar(1);
+ return res;
+ };
+
+ auto operate_button = [this](const wxString &label, bool enable) {
+ if (!enable) {
+ ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
+ if (m_is_dark_mode) {
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(108.0f / 255.0f, 108.0f / 255.0f, 108.0f / 255.0f, 1.0f));
+ }
+ else {
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(230.0f / 255.0f, 230.0f / 255.0f, 230.0f / 255.0f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(163.0f / 255.0f, 163.0f / 255.0f, 163.0f / 255.0f, 1.0f));
+ }
+ }
+
+ bool res = m_imgui->button(label.c_str());
+
+ if (!enable) {
+ ImGui::PopItemFlag();
+ ImGui::PopStyleColor(2);
+ }
+ return res;
+ };
+
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
+ if (selectable(_L("Union").c_str(), m_operation_mode == MeshBooleanOperation::Union, ImVec2(max_tab_length, 0.0f))) {
+ m_operation_mode = MeshBooleanOperation::Union;
+ }
+ ImGui::SameLine(0, 0);
+ if (selectable(_L("Difference").c_str(), m_operation_mode == MeshBooleanOperation::Difference, ImVec2(max_tab_length, 0.0f))) {
+ m_operation_mode = MeshBooleanOperation::Difference;
+ }
+ ImGui::SameLine(0, 0);
+ if (selectable(_L("Intersection").c_str(), m_operation_mode == MeshBooleanOperation::Intersection, ImVec2(max_tab_length, 0.0f))) {
+ m_operation_mode = MeshBooleanOperation::Intersection;
+ }
+ ImGui::PopStyleVar();
+
+ ImGui::AlignTextToFramePadding();
+ std::string cap_str1 = m_operation_mode != MeshBooleanOperation::Difference ? _u8L("Part 1") : _u8L("Subtract from");
+ m_imgui->text(cap_str1);
+ ImGui::SameLine(max_cap_length);
+ wxString select_src_str = m_src.mv ? "1 " + _L("selected") : _L("Select");
+ select_src_str << "##select_source_volume";
+ ImGui::PushItemWidth(select_btn_length);
+ if (selectable(select_src_str.c_str(), m_selecting_state == MeshBooleanSelectingState::SelectSource, ImVec2(select_btn_length, 0)))
+ m_selecting_state = MeshBooleanSelectingState::SelectSource;
+ ImGui::PopItemWidth();
+ if (m_src.mv) {
+ ImGui::SameLine();
+ ImGui::AlignTextToFramePadding();
+ m_imgui->text(m_src.mv->name);
+
+ ImGui::SameLine();
+ ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_Border, { 0, 0, 0, 0 });
+ if (ImGui::Button((into_u8(ImGui::TextSearchCloseIcon) + "##src").c_str(), {18, 18}))
+ {
+ m_src.reset();
+ }
+ ImGui::PopStyleColor(5);
+ }
+
+ ImGui::AlignTextToFramePadding();
+ std::string cap_str2 = m_operation_mode != MeshBooleanOperation::Difference ? _u8L("Part 2") : _u8L("Subtract with");
+ m_imgui->text(cap_str2);
+ ImGui::SameLine(max_cap_length);
+ wxString select_tool_str = m_tool.mv ? "1 " + _L("selected") : _L("Select");
+ select_tool_str << "##select_tool_volume";
+ ImGui::PushItemWidth(select_btn_length);
+ if (selectable(select_tool_str.c_str(), m_selecting_state == MeshBooleanSelectingState::SelectTool, ImVec2(select_btn_length, 0)))
+ m_selecting_state = MeshBooleanSelectingState::SelectTool;
+ ImGui::PopItemWidth();
+ if (m_tool.mv) {
+ ImGui::SameLine();
+ ImGui::AlignTextToFramePadding();
+ m_imgui->text(m_tool.mv->name);
+
+ ImGui::SameLine();
+ ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_Button));
+ ImGui::PushStyleColor(ImGuiCol_Border, { 0, 0, 0, 0 });
+ if (ImGui::Button((into_u8(ImGui::TextSearchCloseIcon) + "tool").c_str(), {18, 18}))
+ {
+ m_tool.reset();
+ }
+ ImGui::PopStyleColor(5);
+ }
+
+ bool enable_button = m_src.mv && m_tool.mv;
+ if (m_operation_mode == MeshBooleanOperation::Union)
+ {
+ if (operate_button(_L("Union") + "##btn", enable_button)) {
+ TriangleMesh temp_src_mesh = m_src.mv->mesh();
+ temp_src_mesh.transform(m_src.trafo);
+ TriangleMesh temp_tool_mesh = m_tool.mv->mesh();
+ temp_tool_mesh.transform(m_tool.trafo);
+ std::vector temp_mesh_resuls;
+ Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "UNION");
+ if (temp_mesh_resuls.size() != 0) {
+ generate_new_volume(true, *temp_mesh_resuls.begin());
+ wxGetApp().notification_manager()->close_plater_warning_notification(warning_text);
+ }
+ else {
+ wxGetApp().notification_manager()->push_plater_warning_notification(warning_text);
+ }
+ }
+ }
+ else if (m_operation_mode == MeshBooleanOperation::Difference) {
+ m_imgui->bbl_checkbox(_L("Delete input"), m_diff_delete_input);
+ if (operate_button(_L("Difference") + "##btn", enable_button)) {
+ TriangleMesh temp_src_mesh = m_src.mv->mesh();
+ temp_src_mesh.transform(m_src.trafo);
+ TriangleMesh temp_tool_mesh = m_tool.mv->mesh();
+ temp_tool_mesh.transform(m_tool.trafo);
+ std::vector temp_mesh_resuls;
+ Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "A_NOT_B");
+ if (temp_mesh_resuls.size() != 0) {
+ generate_new_volume(m_diff_delete_input, *temp_mesh_resuls.begin());
+ wxGetApp().notification_manager()->close_plater_warning_notification(warning_text);
+ }
+ else {
+ wxGetApp().notification_manager()->push_plater_warning_notification(warning_text);
+ }
+ }
+ }
+ else if (m_operation_mode == MeshBooleanOperation::Intersection){
+ m_imgui->bbl_checkbox(_L("Delete input"), m_inter_delete_input);
+ if (operate_button(_L("Intersection") + "##btn", enable_button)) {
+ TriangleMesh temp_src_mesh = m_src.mv->mesh();
+ temp_src_mesh.transform(m_src.trafo);
+ TriangleMesh temp_tool_mesh = m_tool.mv->mesh();
+ temp_tool_mesh.transform(m_tool.trafo);
+ std::vector temp_mesh_resuls;
+ Slic3r::MeshBoolean::mcut::make_boolean(temp_src_mesh, temp_tool_mesh, temp_mesh_resuls, "INTERSECTION");
+ if (temp_mesh_resuls.size() != 0) {
+ generate_new_volume(m_inter_delete_input, *temp_mesh_resuls.begin());
+ wxGetApp().notification_manager()->close_plater_warning_notification(warning_text);
+ }
+ else {
+ wxGetApp().notification_manager()->push_plater_warning_notification(warning_text);
+ }
+ }
+ }
+
+ float win_w = ImGui::GetWindowWidth();
+ if (last_w != win_w || last_y != y) {
+ // ask canvas for another frame to render the window in the correct position
+ m_imgui->set_requires_extra_frame();
+ m_parent.set_as_dirty();
+ m_parent.request_extra_frame();
+ if (last_w != win_w)
+ last_w = win_w;
+ if (last_y != y)
+ last_y = y;
+ }
+
+ GizmoImguiEnd();
+ ImGuiWrapper::pop_toolbar_style();
+}
+
+void GLGizmoMeshBoolean::on_load(cereal::BinaryInputArchive &ar)
+{
+ ar(m_enable, m_operation_mode, m_selecting_state, m_diff_delete_input, m_inter_delete_input, m_src, m_tool);
+ ModelObject *curr_model_object = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr;
+ m_src.mv = curr_model_object == nullptr ? nullptr : m_src.volume_idx < 0 ? nullptr : curr_model_object->volumes[m_src.volume_idx];
+ m_tool.mv = curr_model_object == nullptr ? nullptr : m_tool.volume_idx < 0 ? nullptr : curr_model_object->volumes[m_tool.volume_idx];
+}
+
+void GLGizmoMeshBoolean::on_save(cereal::BinaryOutputArchive &ar) const
+{
+ ar(m_enable, m_operation_mode, m_selecting_state, m_diff_delete_input, m_inter_delete_input, m_src, m_tool);
+}
+
+void GLGizmoMeshBoolean::generate_new_volume(bool delete_input, const TriangleMesh& mesh_result) {
+
+ wxGetApp().plater()->take_snapshot("Mesh Boolean");
+
+ ModelObject* curr_model_object = m_c->selection_info()->model_object();
+
+ // generate new volume
+ ModelVolume* new_volume = curr_model_object->add_volume(std::move(mesh_result));
+
+ // assign to new_volume from old_volume
+ ModelVolume* old_volume = m_src.mv;
+ std::string suffix;
+ switch (m_operation_mode)
+ {
+ case MeshBooleanOperation::Union:
+ suffix = "union";
+ break;
+ case MeshBooleanOperation::Difference:
+ suffix = "difference";
+ break;
+ case MeshBooleanOperation::Intersection:
+ suffix = "intersection";
+ break;
+ }
+ new_volume->name = old_volume->name + " - " + suffix;
+ new_volume->set_new_unique_id();
+ new_volume->config.apply(old_volume->config);
+ new_volume->set_type(old_volume->type());
+ new_volume->set_material_id(old_volume->material_id());
+ new_volume->set_transformation(old_volume->get_transformation());
+ //Vec3d translate_z = { 0,0, (new_volume->source.mesh_offset - old_volume->source.mesh_offset).z() };
+ //new_volume->translate(new_volume->get_transformation().get_matrix(true) * translate_z);
+ //new_volume->supported_facets.assign(old_volume->supported_facets);
+ //new_volume->seam_facets.assign(old_volume->seam_facets);
+ //new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets);
+
+ // delete old_volume
+ std::swap(curr_model_object->volumes[m_src.volume_idx], curr_model_object->volumes.back());
+ curr_model_object->delete_volume(curr_model_object->volumes.size() - 1);
+
+ if (delete_input) {
+ std::vector items;
+ auto obj_idx = m_parent.get_selection().get_object_idx();
+ items.emplace_back(ItemType::itVolume, obj_idx, m_tool.volume_idx);
+ wxGetApp().obj_list()->delete_from_model_and_list(items);
+ }
+
+ //bool sinking = curr_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD;
+ //if (!sinking)
+ // curr_model_object->ensure_on_bed();
+ //curr_model_object->sort_volumes(true);
+
+ wxGetApp().plater()->update();
+ wxGetApp().obj_list()->select_item([this, new_volume]() {
+ wxDataViewItem sel_item;
+
+ wxDataViewItemArray items = wxGetApp().obj_list()->reorder_volumes_and_get_selection(m_parent.get_selection().get_object_idx(), [new_volume](const ModelVolume* volume) { return volume == new_volume; });
+ if (!items.IsEmpty())
+ sel_item = items.front();
+
+ return sel_item;
+ });
+
+ m_src.reset();
+ m_tool.reset();
+ m_selecting_state = MeshBooleanSelectingState::SelectSource;
+}
+
+
+}}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp
new file mode 100644
index 0000000000..42fa97eede
--- /dev/null
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp
@@ -0,0 +1,88 @@
+#ifndef slic3r_GLGizmoMeshBoolean_hpp_
+#define slic3r_GLGizmoMeshBoolean_hpp_
+
+#include "GLGizmoBase.hpp"
+#include "GLGizmosCommon.hpp"
+#include "libslic3r/Model.hpp"
+
+namespace Slic3r {
+
+namespace GUI {
+
+enum class MeshBooleanSelectingState {
+ Undef,
+ SelectSource,
+ SelectTool,
+
+};
+enum class MeshBooleanOperation{
+ Undef,
+ Union,
+ Difference,
+ Intersection,
+};
+struct VolumeInfo {
+ ModelVolume* mv{ nullptr };
+ int volume_idx{-1};
+ Transform3d trafo;
+ void reset() {
+ mv = nullptr;
+ volume_idx = -1;
+ trafo = Transform3d::Identity();
+ };
+ template
+ void serialize(Archive& ar) {
+ ar(volume_idx, trafo);
+ }
+};
+class GLGizmoMeshBoolean : public GLGizmoBase
+{
+public:
+ GLGizmoMeshBoolean(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
+ ~GLGizmoMeshBoolean();
+
+ void set_enable(bool enable) { m_enable = enable; }
+ bool get_enable() { return m_enable; }
+ MeshBooleanSelectingState get_selecting_state() { return m_selecting_state; }
+ void set_src_volume(ModelVolume* mv) {
+ m_src.mv = mv;
+ if (m_src.mv == m_tool.mv)
+ m_tool.reset();
+ }
+ void set_tool_volume(ModelVolume* mv) {
+ m_tool.mv = mv;
+ if (m_tool.mv == m_src.mv)
+ m_src.reset();
+ }
+
+ bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
+
+protected:
+ virtual bool on_init() override;
+ virtual std::string on_get_name() const override;
+ virtual bool on_is_activable() const override;
+ virtual void on_render() override;
+ virtual void on_render_for_picking() override {}
+ virtual void on_set_state() override;
+ virtual CommonGizmosDataID on_get_requirements() const override;
+ virtual void on_render_input_window(float x, float y, float bottom_limit);
+
+ void on_load(cereal::BinaryInputArchive &ar) override;
+ void on_save(cereal::BinaryOutputArchive &ar) const override;
+
+private:
+ bool m_enable{ false };
+ MeshBooleanOperation m_operation_mode;
+ MeshBooleanSelectingState m_selecting_state;
+ bool m_diff_delete_input = false;
+ bool m_inter_delete_input = false;
+ VolumeInfo m_src;
+ VolumeInfo m_tool;
+
+ void generate_new_volume(bool delete_input, const TriangleMesh& mesh_result);
+};
+
+} // namespace GUI
+} // namespace Slic3r
+
+#endif // slic3r_GLGizmoMeshBoolean_hpp_
\ No newline at end of file
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
index 278d0d3758..8ad89a9f2d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp
@@ -212,7 +212,14 @@ void GLGizmoMmuSegmentation::render_triangles(const Selection &selection) const
++mesh_id;
- const Transform3d trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * mv->get_matrix();
+ Transform3d trafo_matrix;
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ trafo_matrix = mo->instances[selection.get_instance_idx()]->get_assemble_transformation().get_matrix() * mv->get_matrix();
+ trafo_matrix.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mo->instances[selection.get_instance_idx()]->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ }
+ else {
+ trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix()* mv->get_matrix();
+ }
bool is_left_handed = trafo_matrix.matrix().determinant() < 0.;
if (is_left_handed)
@@ -459,14 +466,14 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
if (m_selected_extruder_idx != extruder_idx) flags |= ImGuiColorEditFlags_NoBorder;
#ifdef __APPLE__
- ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0);
bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size);
ImGui::PopStyleVar(2);
ImGui::PopStyleColor(1);
#else
- ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0);
bool color_picked = ImGui::ColorButton(color_label.c_str(), color_vec, flags, button_size);
@@ -512,7 +519,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0);
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
index 8d00510c9c..6b421b1531 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
@@ -85,10 +85,15 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
continue;
++mesh_id;
-
- const Transform3d trafo_matrix =
- mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() *
- mv->get_matrix();
+
+ Transform3d trafo_matrix;
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ trafo_matrix = mo->instances[selection.get_instance_idx()]->get_assemble_transformation().get_matrix() * mv->get_matrix();
+ trafo_matrix.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mo->instances[selection.get_instance_idx()]->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ }
+ else {
+ trafo_matrix = mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix()* mv->get_matrix();
+ }
bool is_left_handed = trafo_matrix.matrix().determinant() < 0.;
if (is_left_handed)
@@ -124,7 +129,16 @@ void GLGizmoPainterBase::render_cursor() const
std::vector trafo_matrices;
for (const ModelVolume* mv : mo->volumes) {
if (mv->is_model_part())
- trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
+ {
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ Transform3d temp = mi->get_assemble_transformation().get_matrix() * mv->get_matrix();
+ temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ trafo_matrices.emplace_back(temp);
+ }
+ else {
+ trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
+ }
+ }
}
// Raycast and return if there's no hit.
update_raycast_cache(m_parent.get_local_mouse_position(), camera, trafo_matrices);
@@ -230,17 +244,35 @@ void GLGizmoPainterBase::render_cursor_height_range(const Transform3d& trafo) co
const BoundingBoxf3 box = bounding_box();
Vec3d hit_world = trafo * Vec3d(m_rr.hit(0), m_rr.hit(1), m_rr.hit(2));
float max_z = (float)box.max.z();
+ float min_z = (float)box.min.z();
- float cursor_z = std::clamp((float)hit_world.z(), 0.f, max_z);
- std::array zs = { cursor_z, std::clamp(cursor_z + m_cursor_height, 0.f, max_z) };
- for (int i = 0; i < zs.size(); i++) {
- update_contours(zs[i], max_z);
+ float cursor_z = std::clamp((float)hit_world.z(), min_z, max_z);
+ std::array zs = { cursor_z, std::clamp(cursor_z + m_cursor_height, min_z, max_z) };
+
+ const Selection& selection = m_parent.get_selection();
+ const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
+ const ModelInstance* mi = model_object->instances[selection.get_instance_idx()];
+ for (const ModelVolume* mv : model_object->volumes) {
+ TriangleMesh vol_mesh = mv->mesh();
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ Transform3d temp = mi->get_assemble_transformation().get_matrix() * mv->get_matrix();
+ temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ vol_mesh.transform(temp);
+ }
+ else {
+ vol_mesh.transform(mi->get_transformation().get_matrix() * mv->get_matrix());
+ }
+
+ for (int i = 0; i < zs.size(); i++) {
+ update_contours(vol_mesh, zs[i], max_z, min_z);
+
+ glsafe(::glPushMatrix());
+ glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
+ glsafe(::glLineWidth(2.0f));
+ m_cut_contours.contours.render();
+ glsafe(::glPopMatrix());
+ }
- glsafe(::glPushMatrix());
- glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z()));
- glsafe(::glLineWidth(2.0f));
- m_cut_contours.contours.render();
- glsafe(::glPopMatrix());
}
}
@@ -257,7 +289,7 @@ BoundingBoxf3 GLGizmoPainterBase::bounding_box() const
return ret;
}
-void GLGizmoPainterBase::update_contours(float cursor_z, float max_z) const
+void GLGizmoPainterBase::update_contours(const TriangleMesh& vol_mesh, float cursor_z, float max_z, float min_z) const
{
const Selection& selection = m_parent.get_selection();
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
@@ -266,33 +298,32 @@ void GLGizmoPainterBase::update_contours(float cursor_z, float max_z) const
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
const int instance_idx = selection.get_instance_idx();
- if (0.0 < cursor_z && cursor_z < max_z) {
- if (m_cut_contours.cut_z != cursor_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
- m_cut_contours.cut_z = cursor_z;
+ if (min_z < cursor_z && cursor_z < max_z) {
+ if (m_cut_contours.cut_z != cursor_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
+ m_cut_contours.cut_z = cursor_z;
- if (m_cut_contours.object_id != model_object->id())
- m_cut_contours.mesh = model_object->raw_mesh();
+ m_cut_contours.mesh = vol_mesh;
- m_cut_contours.position = box.center();
- m_cut_contours.shift = Vec3d::Zero();
- m_cut_contours.object_id = model_object->id();
- m_cut_contours.instance_idx = instance_idx;
- m_cut_contours.contours.reset();
+ m_cut_contours.position = box.center();
+ m_cut_contours.shift = Vec3d::Zero();
+ m_cut_contours.object_id = model_object->id();
+ m_cut_contours.instance_idx = instance_idx;
+ m_cut_contours.contours.reset();
- MeshSlicingParams slicing_params;
- slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix();
- const Polygons polys = slice_mesh(m_cut_contours.mesh.its, cursor_z, slicing_params);
- if (!polys.empty()) {
- m_cut_contours.contours.init_from(polys, static_cast(cursor_z));
- m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
+ MeshSlicingParams slicing_params;
+ slicing_params.trafo = Transform3d::Identity().matrix();
+ const Polygons polys = slice_mesh(m_cut_contours.mesh.its, cursor_z, slicing_params);
+ if (!polys.empty()) {
+ m_cut_contours.contours.init_from(polys, static_cast(cursor_z));
+ m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f });
+ }
+ }
+ else if (box.center() != m_cut_contours.position) {
+ m_cut_contours.shift = box.center() - m_cut_contours.position;
}
}
- else if (box.center() != m_cut_contours.position) {
- m_cut_contours.shift = box.center() - m_cut_contours.position;
- }
- }
- else
- m_cut_contours.contours.reset();
+ else
+ m_cut_contours.contours.reset();
}
bool GLGizmoPainterBase::is_mesh_point_clipped(const Vec3d& point, const Transform3d& trafo) const
@@ -451,8 +482,12 @@ std::vector GLGizmoPainterBase::get_pr
const Selection& selection = m_parent.get_selection();
const ModelObject* mo = m_c->selection_info()->model_object();
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
- const Transform3d instance_trafo = mi->get_transformation().get_matrix();
- const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
+ const Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix() :
+ mi->get_transformation().get_matrix();
+ const Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix(true) :
+ mi->get_transformation().get_matrix(true);
for (int mesh_idx = 0; mesh_idx < part_volumes.size(); mesh_idx++) {
if (mesh_idx == m_rr.mesh_id)
@@ -518,8 +553,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
- const Transform3d trafo_matrix_not_translate = mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
- const Transform3d trafo_matrix = mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
+ const Transform3d trafo_matrix_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true) :
+ mi->get_transformation().get_matrix(true) * mo->volumes[m_rr.mesh_id]->get_matrix(true);
+ const Transform3d trafo_matrix = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix() :
+ mi->get_transformation().get_matrix() * mo->volumes[m_rr.mesh_id]->get_matrix();
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), trafo_matrix_not_translate, this->get_clipping_plane_in_volume_coordinates(trafo_matrix), m_smart_fill_angle,
m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f, true);
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
@@ -581,8 +620,12 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
- const Transform3d instance_trafo = mi->get_transformation().get_matrix();
- const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
+ Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix() :
+ mi->get_transformation().get_matrix();
+ Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix(true) :
+ mi->get_transformation().get_matrix(true);
std::vector part_volumes;
// Precalculate transformations of individual meshes.
@@ -590,7 +633,14 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
std::vector trafo_matrices_not_translate;
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
- trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ Transform3d temp = instance_trafo * mv->get_matrix();
+ temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ trafo_matrices.emplace_back(temp);
+ }
+ else {
+ trafo_matrices.emplace_back(instance_trafo* mv->get_matrix());
+ }
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
part_volumes.push_back(mv);
}
@@ -713,15 +763,26 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const Selection &selection = m_parent.get_selection();
const ModelObject *mo = m_c->selection_info()->model_object();
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
- const Transform3d instance_trafo = mi->get_transformation().get_matrix();
- const Transform3d instance_trafo_not_translate = mi->get_transformation().get_matrix(true);
+ const Transform3d instance_trafo = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix() :
+ mi->get_transformation().get_matrix();
+ const Transform3d instance_trafo_not_translate = m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ mi->get_assemble_transformation().get_matrix(true) :
+ mi->get_transformation().get_matrix(true);
// Precalculate transformations of individual meshes.
std::vector trafo_matrices;
std::vector trafo_matrices_not_translate;
for (const ModelVolume *mv : mo->volumes)
if (mv->is_model_part()) {
- trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ Transform3d temp = instance_trafo * mv->get_matrix();
+ temp.translate(mv->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + mi->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0));
+ trafo_matrices.emplace_back(temp);
+ }
+ else {
+ trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
+ }
trafo_matrices_not_translate.emplace_back(instance_trafo_not_translate * mv->get_matrix(true));
}
@@ -811,7 +872,8 @@ void GLGizmoPainterBase::update_raycast_cache(const Vec2d& mouse_position,
hit,
normal,
m_c->object_clipper()->get_clipping_plane(),
- &facet))
+ &facet,
+ m_parent.get_canvas_type() != GLCanvas3D::CanvasAssembleView))
{
// In case this hit is clipped, skip it.
if (is_mesh_point_clipped(hit.cast(), trafo_matrices[mesh_id]))
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
index aa4554413c..db56d58656 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp
@@ -368,7 +368,7 @@ private:
mutable CutContours m_cut_contours;
BoundingBoxf3 bounding_box() const;
- void update_contours(float cursor_z, float max_z) const;
+ void update_contours(const TriangleMesh& vol_mesh, float cursor_z, float max_z, float min_z) const;
protected:
void on_set_state() override;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
index 3ea292e942..6729de6140 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp
@@ -241,7 +241,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
ImGui::PushStyleColor(ImGuiCol_Button, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f)); // r, g, b, a
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, m_is_dark_mode ? ImVec4(43 / 255.0f, 64 / 255.0f, 54 / 255.0f, 1.00f) : ImVec4(0.86f, 0.99f, 0.91f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0);
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
index 5c2096cffb..7b7cc2065d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
@@ -273,8 +273,8 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.81f, 0.81f, 0.81f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.81f, 0.81f, 0.81f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.81f, 0.81f, 0.81f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
if (m_imgui->bbl_sliderin("##ReductionLevel", &reduction, 0, 4, reduce_captions[reduction].c_str())) {
if (reduction < 0) reduction = 0;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
index b249b06cd8..907848e50a 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoText.cpp
@@ -26,6 +26,7 @@
namespace Slic3r {
namespace GUI {
+static const double PI = 3.141592653589793238;
static const wxColour FONT_TEXTURE_BG = wxColour(0, 0, 0, 0);
static const wxColour FONT_TEXTURE_FG = *wxWHITE;
static const int FONT_SIZE = 12;
@@ -560,7 +561,7 @@ void GLGizmoText::push_button_style(bool pressed) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(43 / 255.f, 64 / 255.f, 54 / 255.f, 1.f));
- ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 150 / 255.f, 136 / 255.f, 1.f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f));
}
else {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(45.f / 255.f, 45.f / 255.f, 49.f / 255.f, 1.f));
@@ -574,7 +575,7 @@ void GLGizmoText::push_button_style(bool pressed) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(219 / 255.f, 253 / 255.f, 231 / 255.f, 1.f));
- ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 150 / 255.f, 136 / 255.f, 1.f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.f, 174 / 255.f, 66 / 255.f, 1.f));
}
else {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 1.f));
@@ -595,10 +596,10 @@ void GLGizmoText::push_combo_style(const float scale) {
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale);
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG_DARK);
- ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.59f, 0.53f, 0.0f));
- ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
- ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG_DARK);
ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f });
}
@@ -606,10 +607,10 @@ void GLGizmoText::push_combo_style(const float scale) {
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 1.0f * scale);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f * scale);
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BG);
- ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
- ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.59f, 0.53f, 0.0f));
- ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
- ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.00f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 0.0f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, ImGuiWrapper::COL_WINDOW_BG);
ImGui::PushStyleColor(ImGuiCol_Button, { 1.00f, 1.00f, 1.00f, 0.0f });
}
@@ -1071,6 +1072,11 @@ bool GLGizmoText::update_text_positions(const std::vector& texts)
Vec3d rotation_axis;
Matrix3d rotation_matrix;
Geometry::rotation_from_two_vectors(m_cut_plane_dir, Vec3d::UnitZ(), rotation_axis, phi, &rotation_matrix);
+ if (abs(phi - PI) < 1e-6) {
+ Transform3d transform = Transform3d::Identity();
+ transform.rotate(Eigen::AngleAxisd(phi, m_mouse_normal_world));
+ rotation_matrix = transform.matrix().block<3, 3>(0, 0);
+ }
Transform3d transfo1;
transfo1.setIdentity();
@@ -1312,7 +1318,7 @@ bool GLGizmoText::update_text_positions(const std::vector& texts)
}
TriangleMesh mesh = slice_meshs;
- std::vector mesh_values(m_position_points.size(), 1'000'000'000);
+ std::vector mesh_values(m_position_points.size(), 1e9);
m_normal_points.resize(m_position_points.size());
auto point_in_triangle_delete_area = [](const Vec3d &point, const Vec3d &point0, const Vec3d &point1, const Vec3d &point2) {
Vec3d p0_p = point - point0;
@@ -1383,7 +1389,6 @@ TriangleMesh GLGizmoText::get_text_mesh(const char* text_str, const Vec3d &posit
new_text_dir.normalize();
Geometry::rotation_from_two_vectors(old_text_dir, new_text_dir, rotation_axis, phi, &rotation_matrix);
- static double const PI = 3.141592653589793238;
if (abs(phi - PI) < EPSILON)
rotation_axis = normal;
@@ -1466,6 +1471,9 @@ void GLGizmoText::generate_text_volume(bool is_temp)
mesh.merge(sub_mesh);
}
+ if (mesh.empty())
+ return;
+
Plater *plater = wxGetApp().plater();
if (!plater)
return;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
index 524264cd3d..4e29d10afb 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp
@@ -145,6 +145,11 @@ void InstancesHider::on_update()
const ModelObject* mo = get_pool()->selection_info()->model_object();
int active_inst = get_pool()->selection_info()->get_active_instance();
GLCanvas3D* canvas = get_pool()->get_canvas();
+ double z_min;
+ if (canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView)
+ z_min = std::numeric_limits::max();
+ else
+ z_min = -SINKING_Z_THRESHOLD;
if (mo && active_inst != -1) {
canvas->toggle_model_objects_visibility(false);
@@ -152,7 +157,7 @@ void InstancesHider::on_update()
canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst);
canvas->set_use_clipping_planes(true);
// Some objects may be sinking, do not show whatever is below the bed.
- canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
+ canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), z_min));
canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), std::numeric_limits::max()));
@@ -164,7 +169,7 @@ void InstancesHider::on_update()
m_clippers.clear();
for (const TriangleMesh* mesh : meshes) {
m_clippers.emplace_back(new MeshClipper);
- m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
+ m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), z_min));
m_clippers.back()->set_mesh(*mesh);
}
m_old_meshes = meshes;
@@ -404,18 +409,30 @@ void ObjectClipper::render_cut() const
return;
const SelectionInfo* sel_info = get_pool()->selection_info();
const ModelObject* mo = sel_info->model_object();
- Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
+ Geometry::Transformation inst_trafo;
+ bool is_assem_cnv = get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView;
+ inst_trafo = is_assem_cnv ?
+ mo->instances[sel_info->get_active_instance()]->get_assemble_transformation() :
+ mo->instances[sel_info->get_active_instance()]->get_transformation();
+ auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
size_t clipper_id = 0;
for (const ModelVolume* mv : mo->volumes) {
Geometry::Transformation vol_trafo = mv->get_transformation();
Geometry::Transformation trafo = inst_trafo * vol_trafo;
- trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
-
+ if (is_assem_cnv) {
+ trafo.set_offset(trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0) + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0));
+ }
+ else {
+ trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
+ }
auto& clipper = m_clippers[clipper_id];
clipper->set_plane(*m_clp);
clipper->set_transformation(trafo);
- clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
+ if (is_assem_cnv)
+ clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), std::numeric_limits::max()));
+ else
+ clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
glsafe(::glPushMatrix());
// BBS
glsafe(::glColor3f(0.25f, 0.25f, 0.25f));
@@ -438,14 +455,27 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
// camera_dir(2) = 0;
Vec3d normal = (keep_normal && m_clp) ? m_clp->get_normal() : /*-camera_dir;*/ -wxGetApp().plater()->get_camera().get_dir_forward();
- const Vec3d& center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift);
+ Vec3d center;
+
+ if (get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ const SelectionInfo* sel_info = get_pool()->selection_info();
+ auto trafo = mo->instances[sel_info->get_active_instance()]->get_assemble_transformation();
+ auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
+ center = trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0);
+ }
+ else {
+ center = mo->instances[active_inst]->get_offset() + Vec3d(0., 0., z_shift);
+ }
+
float dist = normal.dot(center);
if (pos < 0.)
pos = m_clp_ratio;
m_clp_ratio = pos;
- m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2*m_active_inst_bb_radius)));
+
+ m_clp.reset(new ClippingPlane(normal, (dist - (-m_active_inst_bb_radius) - m_clp_ratio * 2 * m_active_inst_bb_radius)));
+
get_pool()->get_canvas()->set_as_dirty();
}
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 7575d1dd7d..87c9a00c9e 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -23,6 +23,7 @@
#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp"
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
#include "slic3r/GUI/Gizmos/GLGizmoText.hpp"
+#include "slic3r/GUI/Gizmos/GLGizmoMeshBoolean.hpp"
#include "libslic3r/format.hpp"
#include "libslic3r/Model.hpp"
@@ -54,9 +55,16 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
std::vector GLGizmosManager::get_selectable_idxs() const
{
std::vector out;
- for (size_t i=0; iis_selectable())
- out.push_back(i);
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ for (size_t i = 0; i < m_gizmos.size(); ++i)
+ if (m_gizmos[i]->get_sprite_id() == (unsigned int)MmuSegmentation)
+ out.push_back(i);
+ }
+ else {
+ for (size_t i = 0; i < m_gizmos.size(); ++i)
+ if (m_gizmos[i]->is_selectable())
+ out.push_back(i);
+ }
return out;
}
@@ -78,6 +86,8 @@ size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
#if BBS_TOOLBAR_ON_TOP
//float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();;
float top_x = std::max(m_parent.get_main_toolbar_width() + border, 0.5f * (cnv_w - width + m_parent.get_main_toolbar_width() + m_parent.get_collapse_toolbar_width() - m_parent.get_assemble_view_toolbar_width()) + border);
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView)
+ top_x = 0.5f * cnv_w + 0.5f * (m_parent.get_assembly_paint_toolbar_width());
float top_y = 0;
float stride_x = m_layout.scaled_stride_x();
@@ -161,7 +171,11 @@ void GLGizmosManager::switch_gizmos_icon_filename()
case(EType::MmuSegmentation):
gizmo->set_icon_filename(m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg");
break;
+ case(EType::MeshBoolean):
+ gizmo->set_icon_filename(m_is_dark ? "toolbar_meshboolean_dark.svg" : "toolbar_meshboolean.svg");
+ break;
}
+
}
}
@@ -191,6 +205,7 @@ bool GLGizmosManager::init()
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, m_is_dark ? "toolbar_scale_dark.svg" : "toolbar_scale.svg", EType::Scale, &m_object_manipulation));
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, m_is_dark ? "toolbar_flatten_dark.svg" : "toolbar_flatten.svg", EType::Flatten));
m_gizmos.emplace_back(new GLGizmoAdvancedCut(m_parent, m_is_dark ? "toolbar_cut_dark.svg" : "toolbar_cut.svg", EType::Cut));
+ m_gizmos.emplace_back(new GLGizmoMeshBoolean(m_parent, m_is_dark ? "toolbar_meshboolean_dark.svg" : "toolbar_meshboolean.svg", EType::MeshBoolean));
m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, m_is_dark ? "toolbar_support_dark.svg" : "toolbar_support.svg", EType::FdmSupports));
m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam));
m_gizmos.emplace_back(new GLGizmoText(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Text));
@@ -629,6 +644,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
return dynamic_cast(m_gizmos[Text].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
else if (m_current == Cut)
return dynamic_cast(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
+ else if (m_current == MeshBoolean)
+ return dynamic_cast(m_gizmos[MeshBoolean].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
else
return false;
}
@@ -875,7 +892,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
if (evt.LeftDown() && (!control_down || grabber_contains_mouse())) {
if ((m_current == SlaSupports || m_current == Hollow || m_current == FdmSupports ||
- m_current == Seam || m_current == MmuSegmentation || m_current == Text || m_current == Cut)
+ m_current == Seam || m_current == MmuSegmentation || m_current == Text || m_current == Cut || m_current == MeshBoolean)
&& gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown()))
// the gizmo got the event and took some action, there is no need to do anything more
processed = true;
@@ -965,6 +982,17 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
update_on_off_state(mouse_pos);
update_data();
m_parent.set_as_dirty();
+ try {
+ if ((int)m_hover >= 0 && (int)m_hover < m_gizmos.size()) {
+ std::string name = get_name_from_gizmo_etype(m_hover);
+ int count = m_gizmos[m_hover]->get_count();
+ NetworkAgent* agent = GUI::wxGetApp().getAgent();
+ if (agent) {
+ agent->track_update_property(name, std::to_string(count));
+ }
+ }
+ }
+ catch (...) {}
}
}
else if (evt.MiddleDown()) {
@@ -1372,17 +1400,23 @@ void GLGizmosManager::do_render_overlay() const
float width = get_scaled_total_width();
float zoomed_border = m_layout.scaled_border() * inv_zoom;
- //BBS: GUI refactor: GLToolbar&&Gizmo adjust
+ float zoomed_top_x;
+ if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ zoomed_top_x = 0.5f * m_parent.get_assembly_paint_toolbar_width() * inv_zoom;
+ }
+ else {
+ //BBS: GUI refactor: GLToolbar&&Gizmo adjust
#if BBS_TOOLBAR_ON_TOP
- float main_toolbar_width = (float)m_parent.get_main_toolbar_width();
- float assemble_view_width = (float)m_parent.get_assemble_view_toolbar_width();
- float collapse_width = (float)m_parent.get_collapse_toolbar_width();
- //float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();
- //float zoomed_top_x = 0.5f *(cnv_w + main_toolbar_width - 2 * space_width - width) * inv_zoom;
+ float main_toolbar_width = (float)m_parent.get_main_toolbar_width();
+ float assemble_view_width = (float)m_parent.get_assemble_view_toolbar_width();
+ float collapse_width = (float)m_parent.get_collapse_toolbar_width();
+ //float space_width = GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale();
+ //float zoomed_top_x = 0.5f *(cnv_w + main_toolbar_width - 2 * space_width - width) * inv_zoom;
- float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width - collapse_width)) * inv_zoom;
- //float zoomed_top_x = 0.5f *(main_toolbar_width + collapse_width - width - assemble_view_width) * inv_zoom;
- float zoomed_top_x = main_toolbar_left + (main_toolbar_width) *inv_zoom;
+ float main_toolbar_left = std::max(-0.5f * cnv_w, -0.5f * (main_toolbar_width + get_scaled_total_width() + assemble_view_width - collapse_width)) * inv_zoom;
+ //float zoomed_top_x = 0.5f *(main_toolbar_width + collapse_width - width - assemble_view_width) * inv_zoom;
+ zoomed_top_x = main_toolbar_left + (main_toolbar_width)*inv_zoom;
+ }
float zoomed_top_y = 0.5f * cnv_h * inv_zoom;
#else
//float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom;
@@ -1653,5 +1687,28 @@ int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
return m_gizmos[type]->get_shortcut_key();
}
+std::string get_name_from_gizmo_etype(GLGizmosManager::EType type)
+{
+ switch (type) {
+ case GLGizmosManager::EType::Move:
+ return "Move";
+ case GLGizmosManager::EType::Rotate:
+ return "Rotate";
+ case GLGizmosManager::EType::Scale:
+ return "Scale";
+ case GLGizmosManager::EType::Flatten:
+ return "Flatten";
+ case GLGizmosManager::EType::FdmSupports:
+ return "FdmSupports";
+ case GLGizmosManager::EType::Seam:
+ return "Seam";
+ case GLGizmosManager::EType::Text:
+ return "Text";
+ default:
+ return "";
+ }
+ return "";
+}
+
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index 4d13c3d07f..fefb85b6b9 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -70,6 +70,7 @@ public:
Scale,
Flatten,
Cut,
+ MeshBoolean,
FdmSupports,
Seam,
// BBS
@@ -327,7 +328,7 @@ private:
bool grabber_contains_mouse() const;
};
-
+std::string get_name_from_gizmo_etype(GLGizmosManager::EType type);
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
index 7c7b158d08..2cdd8aac36 100644
--- a/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
+++ b/src/slic3r/GUI/Gizmos/GizmoObjectManipulation.cpp
@@ -452,6 +452,7 @@ void GizmoObjectManipulation::set_uniform_scaling(const bool new_value)
// all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
// Is the angle close to a multiple of 90 degrees?
+
if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) {
// Cannot apply scaling in the world coordinate system.
// BBS: remove tilt prompt dialog
diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp
index 6fd3a54b8e..cd9a617f4b 100644
--- a/src/slic3r/GUI/MeshUtils.cpp
+++ b/src/slic3r/GUI/MeshUtils.cpp
@@ -241,7 +241,7 @@ void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane,
- size_t* facet_idx) const
+ size_t* facet_idx, bool sinking_limit) const
{
Vec3d point;
Vec3d direction;
@@ -258,8 +258,8 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
// Also, remove anything below the bed (sinking objects).
for (i=0; i= SINKING_Z_THRESHOLD &&
- (! clipping_plane || ! clipping_plane->is_point_clipped(transformed_hit)))
+ if (transformed_hit.z() >= (sinking_limit ? SINKING_Z_THRESHOLD : -std::numeric_limits::max()) &&
+ (!clipping_plane || !clipping_plane->is_point_clipped(transformed_hit)))
break;
}
diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp
index 02c597da3c..123b8a7852 100644
--- a/src/slic3r/GUI/MeshUtils.hpp
+++ b/src/slic3r/GUI/MeshUtils.hpp
@@ -150,7 +150,8 @@ public:
Vec3f& position, // where to save the positibon of the hit (mesh coords)
Vec3f& normal, // normal of the triangle that was hit
const ClippingPlane* clipping_plane = nullptr, // clipping plane (if active)
- size_t* facet_idx = nullptr // index of the facet hit
+ size_t* facet_idx = nullptr, // index of the facet hit
+ bool sinking_limit = true
) const;
// Given a vector of points in woorld coordinates, this returns vector
diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp
index 9588a293e6..2e5686c3ca 100644
--- a/src/slic3r/GUI/NotificationManager.cpp
+++ b/src/slic3r/GUI/NotificationManager.cpp
@@ -306,6 +306,96 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
if (fading_pop)
ImGui::PopStyleColor(3);
}
+
+void NotificationManager::PopNotification::bbl_render_block_notification(GLCanvas3D &canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin)
+{
+ if (m_state == EState::Unknown)
+ init();
+
+ if (m_state == EState::Hidden) {
+ m_top_y = initial_y - GAP_WIDTH;
+ return;
+ }
+
+ if (m_state == EState::ClosePending || m_state == EState::Finished)
+ {
+ m_state = EState::Finished;
+ return;
+ }
+
+ Size cnv_size = canvas.get_canvas_size();
+ ImGuiWrapper& imgui = *wxGetApp().imgui();
+ float right_gap = right_margin + (move_from_overlay ? overlay_width + m_line_height * 5 : 0);
+ bool fading_pop = false;
+
+ if (m_line_height != ImGui::CalcTextSize("A").y)
+ init();
+
+ set_next_window_size(imgui);
+
+ // top y of window
+ m_top_y = initial_y + m_window_height;
+
+ ImVec2 win_pos(1.0f * (float) cnv_size.get_width() - right_gap, 1.0f * (float) cnv_size.get_height() - m_top_y);
+ imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
+ imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
+
+ // color change based on fading out
+ if (m_state == EState::FadingOut) {
+ push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity);
+ push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity);
+ push_style_color(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered), true, m_current_fade_opacity);
+ fading_pop = true;
+ }
+
+ bool bgrnd_color_pop = push_background_color();
+
+ // name of window indentifies window - has to be unique string
+ if (m_id == 0)
+ m_id = m_id_provider.allocate_id();
+ std::string name = "!!Ntfctn" + std::to_string(m_id);
+
+ use_bbl_theme();
+ if (m_data.level == NotificationLevel::SeriousWarningNotificationLevel)
+ {
+ push_style_color(ImGuiCol_Border, {245.f / 255.f, 155 / 255.f, 22 / 255.f, 1}, true, m_current_fade_opacity);
+ push_style_color(ImGuiCol_WindowBg, {245.f / 255.f, 155 / 255.f, 22 / 255.f, 1}, true, m_current_fade_opacity);
+ }
+ if (m_data.level == NotificationLevel::ErrorNotificationLevel) {
+ push_style_color(ImGuiCol_Border, {225.f / 255.f, 71 / 255.f, 71 / 255.f, 1}, true, m_current_fade_opacity);
+ push_style_color(ImGuiCol_WindowBg, {225.f / 255.f, 71 / 255.f, 71 / 255.f, 1}, true, m_current_fade_opacity);
+ }
+ push_style_color(ImGuiCol_Text, { 1,1,1,1 }, true, m_current_fade_opacity);
+
+ if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
+ ImVec2 win_size = ImGui::GetWindowSize();
+ ImVec2 win_pos = ImGui::GetWindowPos();
+ if (ImGui::IsMouseHoveringRect(win_pos, win_pos + win_size)) {
+ set_hovered();
+ }
+
+ //render left icon
+ bbl_render_block_notif_left_sign(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ bbl_render_block_notif_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ bbl_render_block_notif_buttons(imgui, win_size, win_pos);
+ //render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
+ //m_minimize_b_visible = false;
+ //if (m_multiline && m_lines_count > 3)
+ // render_minimize_button(imgui, win_pos.x, win_pos.y);
+ }
+ ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
+ imgui.end();
+
+ ImGui::PopStyleColor(3);
+ restore_default_theme();
+
+ if (bgrnd_color_pop)
+ ImGui::PopStyleColor();
+
+ if (fading_pop)
+ ImGui::PopStyleColor(3);
+}
+
bool NotificationManager::PopNotification::push_background_color()
{
if (m_is_gray) {
@@ -345,6 +435,10 @@ void NotificationManager::PopNotification::count_spaces()
// m_left_indentation = picture_width + m_line_height / 2;
//}
m_window_width_offset = m_left_indentation + m_line_height * 3.f;
+ if (m_data.level == NotificationLevel::ErrorNotificationLevel || m_data.level == NotificationLevel::SeriousWarningNotificationLevel) {
+ m_left_indentation = 32 + m_line_height;
+ m_window_width_offset = 90.f;
+ }
m_window_width = m_line_height * 25;
}
@@ -464,6 +558,68 @@ void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& im
m_window_height += 1 * m_line_height; // top and bottom
}
+void NotificationManager::PopNotification::bbl_render_block_notif_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
+{
+ float x_offset = m_left_indentation;
+ int last_end = 0;
+ float starting_y = (m_lines_count == 2 ? win_size_y / 2 - m_line_height : (m_lines_count == 1 ? win_size_y / 2 - m_line_height / 2 : m_line_height / 2));
+ float shift_y = m_line_height;
+ std::string line;
+
+ for (size_t i = 0; i < (m_multiline ? m_endlines.size() : std::min(m_endlines.size(), (size_t)2)); i++) {
+ assert(m_endlines.size() > i && m_text1.size() >= m_endlines[i]);
+ line.clear();
+ ImGui::SetCursorPosX(x_offset);
+ ImGui::SetCursorPosY(starting_y + i * shift_y);
+ if (m_endlines.size() > i && m_text1.size() >= m_endlines[i]) {
+ if (i == 1 && m_endlines.size() > 2 && !m_multiline) {
+ // second line with "more" hypertext
+ line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
+ while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x) {
+ line = line.substr(0, line.length() - 1);
+ }
+ line += "..";
+ }
+ else {
+ // regural line
+ line = m_text1.substr(last_end, m_endlines[i] - last_end);
+ }
+ last_end = m_endlines[i];
+ if (m_text1.size() > m_endlines[i])
+ last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0);
+
+ if (pos_start != string::npos && pos_end != string::npos && m_endlines[i] - line.length() >= pos_start && m_endlines[i] <= pos_end) {
+ push_style_color(ImGuiCol_Text, m_ErrorColor, m_state == EState::FadingOut, m_current_fade_opacity);
+ imgui.text(line.c_str());
+ ImGui::PopStyleColor();
+ }
+ else {
+ imgui.text(line.c_str());
+ }
+ }
+ }
+ //hyperlink text
+ if (!m_multiline && m_lines_count > 2) {
+ render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + " ").c_str()).x, starting_y + shift_y, _u8L("More"), true);
+ }
+ else if (!m_hypertext.empty()) {
+ const ImVec2 button_size = {52, 28};
+ ImVec2 cursor_pos = { win_size_x - m_line_height * 6.0f, win_size_y / 2 - button_size.y / 2 };
+ ImGui::SetCursorPos(cursor_pos);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2);
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.f, 1.f, 1.f, 1.f));
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.f, 1.f, 1.f, 0.f));
+ //if (imgui.button(_L("Jump"), button_size.x, button_size.y)) { if (on_text_click()) { close(); } }
+ ImGui::PopStyleColor(2);
+ ImGui::PopStyleVar(2);
+ render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + (line.empty() ? "" : " ")).c_str()).x, starting_y + (m_endlines.size() - 1) * shift_y, m_hypertext);
+ }
+
+ // text2 (text after hypertext) is not rendered for regular notifications
+ // its rendering is in HintNotification::render_text
+}
+
void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
float x_offset = m_left_indentation;
@@ -539,9 +695,18 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui,
ImGui::PopStyleColor(3);
//hover color
- ImVec4 HyperColor = m_HyperTextColor;
- if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
- HyperColor.y += 0.1f;
+ ImVec4 HyperColor = m_HyperTextColor;//ImVec4(150.f / 255.f, 100.f / 255.f, 0.f / 255.f, 1)
+ if (m_data.level == NotificationLevel::SeriousWarningNotificationLevel)
+ HyperColor = ImVec4(0.f, 0.f, 0.f, 0.4f);
+ if (m_data.level == NotificationLevel::ErrorNotificationLevel)
+ HyperColor = ImVec4(135.f / 255.f, 43 / 255.f, 43 / 255.f, 1);
+ if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
+ {
+ HyperColor.y += 0.1f;
+ if (m_data.level == NotificationLevel::SeriousWarningNotificationLevel || m_data.level == NotificationLevel::SeriousWarningNotificationLevel)
+ HyperColor.x += 0.2f;
+ }
+
//text
push_style_color(ImGuiCol_Text, HyperColor, m_state == EState::FadingOut, m_current_fade_opacity);
@@ -607,6 +772,64 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
ImGui::PopStyleColor(5);
}
+void NotificationManager::PopNotification::bbl_render_block_notif_buttons(ImGuiWrapper& imgui, ImVec2 win_size, ImVec2 win_pos)
+{
+ // close button
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
+ push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
+ push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
+
+ std::wstring button_text;
+ button_text = ImGui::CloseBlockNotifButton;
+ ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str());
+ ImVec2 button_size(button_pic_size.x * 2.f, button_pic_size.y * 2.f);
+
+ ImVec2 cursor_pos = { win_size.x - m_line_height * 2.0f, win_size.y / 2 - button_size.y / 2 };
+ ImGui::SetCursorPos(cursor_pos);
+ //if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y + win_size.y / 2 - button_pic_size.y),
+ // ImVec2(win_pos.x - win_size.x / 20.f, win_pos.y + win_size.y / 2 + button_pic_size.y),
+ // true))
+ if(ImGui::IsMouseHoveringRect(win_pos + cursor_pos, win_pos + cursor_pos + button_size))
+ {
+ button_text = ImGui::CloseBlockNotifHoverButton;
+ }
+ if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
+ {
+ close();
+ }
+ ImGui::PopStyleColor(5);
+
+
+ //// minimize button
+ //ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
+ //ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
+ //push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity);
+ //push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
+ //push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
+ ////button - if part if treggered
+ //std::wstring button_text;
+ //button_text = m_is_dark ? ImGui::MinimalizeDarkButton : ImGui::MinimalizeButton;
+ //if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1),
+ // ImVec2(win_pos_x, win_pos_y + m_window_height),
+ // true))
+ //{
+ // button_text = m_is_dark ? ImGui::MinimalizeHoverDarkButton : ImGui::MinimalizeHoverButton;
+ //}
+ //ImVec2 button_pic_size = ImGui::CalcTextSize(into_u8(button_text).c_str());
+ //ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
+ //ImGui::SetCursorPosX(m_window_width - m_line_height * 1.8f);
+ //ImGui::SetCursorPosY(m_window_height - button_size.y - 5);
+ //if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
+ //{
+ // m_multiline = false;
+ //}
+
+ //ImGui::PopStyleColor(5);
+ //m_minimize_b_visible = true;
+}
+
//void NotificationManager::PopNotification::render_multiline(ImGuiWrapper &imgui, const float win_pos_x, const float win_pos_y)
//{
// if (m_data.type == NotificationType::BBLObjectInfo)
@@ -615,6 +838,19 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
// }
//}
+void NotificationManager::PopNotification::bbl_render_block_notif_left_sign(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
+{
+ auto window = ImGui::GetCurrentWindow();
+ //window->DrawList->AddImage(user_texture_id, bb.Min + padding + margin, bb.Max - padding - margin, uv0, uv1, ImGui::GetColorU32(tint_col));
+
+ std::wstring text;
+ text = ImGui::BlockNotifErrorIcon;
+ ImGui::SetCursorPosX(m_line_height / 3);
+ ImGui::SetCursorPosY(m_window_height / 2 - m_line_height);
+ imgui.text(text.c_str());
+
+}
+
void NotificationManager::PopNotification::bbl_render_left_sign(ImGuiWrapper &imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImDrawList *draw_list = ImGui::GetWindowDrawList();
@@ -1630,19 +1866,39 @@ void NotificationManager::push_validate_error_notification(StringObjectException
set_slicing_progress_hidden();
}
-void NotificationManager::push_slicing_error_notification(const std::string &text, ModelObject const *obj)
+void NotificationManager::push_slicing_error_notification(const std::string &text, std::vector objs)
{
- auto callback = obj ? [id = obj->id()](wxEvtHandler *) {
+ std::vector ids;
+ for (auto optr : objs) {
+ if (optr)
+ ids.push_back(optr->id());
+ }
+ auto callback = !objs.empty() ? [ids](wxEvtHandler *) {
auto & objects = wxGetApp().model().objects;
- auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; });
- if (iter != objects.end()) {
- wxGetApp().obj_list()->select_items({{*iter, nullptr}});
+ std::vector ovs;
+ for (auto id : ids) {
+ auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; });
+ if (iter != objects.end()) { ovs.push_back({*iter, nullptr}); }
+ }
+ if (!ovs.empty()) {
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
+ wxGetApp().obj_list()->select_items(ovs);
}
return false;
} : std::function();
auto link = callback ? _u8L("Jump to") : "";
- if (obj) link += std::string(" [") + obj->name + "]";
+ if (!objs.empty()) {
+ link += " [";
+ for (auto obj : objs) {
+ if (obj)
+ link += obj->name + ", ";
+ }
+ if (!objs.empty()) {
+ link.pop_back();
+ link.pop_back();
+ }
+ link += "] ";
+ }
set_all_slicing_errors_gray(false);
push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("Error:") + "\n" + text, link, callback }, 0);
set_slicing_progress_hidden();
@@ -1653,8 +1909,8 @@ void NotificationManager::push_slicing_warning_notification(const std::string& t
auto & objects = wxGetApp().model().objects;
auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; });
if (iter != objects.end()) {
- wxGetApp().obj_list()->select_items({{*iter, nullptr}});
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
+ wxGetApp().obj_list()->select_items({{*iter, nullptr}});
}
return false;
} : std::function();
@@ -1869,6 +2125,53 @@ void NotificationManager::upload_job_notification_show_error(int id, const std::
}
}
+void NotificationManager::push_slicing_serious_warning_notification(const std::string &text, std::vector objs)
+{
+ std::vector ids;
+ for (auto optr : objs) {
+ if (optr) ids.push_back(optr->id());
+ }
+ auto callback = !objs.empty() ?
+ [ids](wxEvtHandler *) {
+ auto & objects = wxGetApp().model().objects;
+ std::vector ovs;
+ for (auto id : ids) {
+ auto iter = std::find_if(objects.begin(), objects.end(), [id](auto o) { return o->id() == id; });
+ if (iter != objects.end()) { ovs.push_back({*iter, nullptr}); }
+ }
+ if (!ovs.empty()) {
+ wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
+ wxGetApp().obj_list()->select_items(ovs);
+ }
+ return false;
+ } :
+ std::function();
+ auto link = callback ? _u8L("Jump to") : "";
+ if (!objs.empty()) {
+ link += " [";
+ for (auto obj : objs) {
+ if (obj) link += obj->name + ", ";
+ }
+ if (!objs.empty()) {
+ link.pop_back();
+ link.pop_back();
+ }
+ link += "] ";
+ }
+ set_all_slicing_warnings_gray(false);
+ push_notification_data({NotificationType::SlicingSeriousWarning, NotificationLevel::SeriousWarningNotificationLevel, 0, _u8L("Serious warning:") + "\n" + text, link,
+ callback},
+ 0);
+ set_slicing_progress_hidden();
+}
+
+void NotificationManager::close_slicing_serious_warning_notification(const std::string &text)
+{
+ for (std::unique_ptr ¬ification : m_pop_notifications) {
+ if (notification->get_type() == NotificationType::SlicingSeriousWarning && notification->compare_text(_u8L("Serious warning:") + "\n" + text)) { notification->close(); }
+ }
+}
+
void NotificationManager::init_slicing_progress_notification(std::function cancel_callback)
{
for (std::unique_ptr& notification : m_pop_notifications) {
@@ -2114,12 +2417,13 @@ bool NotificationManager::push_notification_data(std::unique_ptrget_type() == NotificationType::SlicingWarning) {
m_pop_notifications.back()->append(notification->get_data().ori_text);
- }
- else
- m_pop_notifications.back()->update(notification->get_data());
+ } else {
+ m_pop_notifications.back()->update(notification->get_data());
+ }
}
} else {
m_pop_notifications.emplace_back(std::move(notification));
+
retval = true;
}
if (!m_initialized)
@@ -2129,7 +2433,10 @@ bool NotificationManager::push_notification_data(std::unique_ptr notification, std::function condition_callback, int64_t initial_delay, int64_t delay_interval)
+void NotificationManager::push_delayed_notification_data(std::unique_ptr notification,
+ std::function condition_callback,
+ int64_t initial_delay,
+ int64_t delay_interval)
{
if (initial_delay == 0 && condition_callback()) {
if( push_notification_data(std::move(notification), 0))
@@ -2155,13 +2462,20 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay
{
sort_notifications();
- float last_y = bottom_margin * m_scale;
+ float bottom_up_last_y = bottom_margin * m_scale;
for (const auto& notification : m_pop_notifications) {
- if (notification->get_state() != PopNotification::EState::Hidden) {
- notification->render(canvas, last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
- if (notification->get_state() != PopNotification::EState::Finished)
- last_y = notification->get_top() + GAP_WIDTH;
+ if (notification->get_data().level == NotificationLevel::ErrorNotificationLevel || notification->get_data().level == NotificationLevel::SeriousWarningNotificationLevel) {
+ notification->bbl_render_block_notification(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
+ if (notification->get_state() != PopNotification::EState::Finished)
+ bottom_up_last_y = notification->get_top() + GAP_WIDTH;
+ }
+ else {
+ if (notification->get_state() != PopNotification::EState::Hidden) {
+ notification->render(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
+ if (notification->get_state() != PopNotification::EState::Finished)
+ bottom_up_last_y = notification->get_top() + GAP_WIDTH;
+ }
}
}
m_last_render = GLCanvas3D::timestamp_now();
@@ -2295,6 +2609,8 @@ void NotificationManager::set_in_preview(bool preview)
notification->hide(preview);
if (m_in_preview && notification->get_type() == NotificationType::DidYouKnowHint)
notification->close();
+ if (notification->get_type() == NotificationType::ValidateWarning)
+ notification->hide(preview);
}
}
diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp
index 9016a3df26..7127ce30e1 100644
--- a/src/slic3r/GUI/NotificationManager.hpp
+++ b/src/slic3r/GUI/NotificationManager.hpp
@@ -73,6 +73,8 @@ enum class NotificationType
// Slicing error produced by BackgroundSlicingProcess::validate() or by the BackgroundSlicingProcess background
// thread thowing a SlicingError exception.
SlicingError,
+ //Gcode conflict generates slicing severe warning
+ SlicingSeriousWarning,
// Slicing warnings, issued by the slicing process.
// Slicing warnings are registered for a particular Print milestone or a PrintObject and its milestone.
SlicingWarning,
@@ -162,6 +164,8 @@ public:
ImportantNotificationLevel,
// Warning, no fade-out.
WarningNotificationLevel,
+ // Serious warning, bold reminder
+ SeriousWarningNotificationLevel,
// Error, no fade-out. Top most position.
ErrorNotificationLevel,
};
@@ -191,8 +195,10 @@ public:
void set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage);
void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host);
void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host);
+ void push_slicing_serious_warning_notification(const std::string &text, std::vector objs);
+ void close_slicing_serious_warning_notification(const std::string &text);
// Creates Slicing Error notification with a custom text and no fade out.
- void push_slicing_error_notification(const std::string &text, ModelObject const *obj);
+ void push_slicing_error_notification(const std::string &text, std::vector objs);
// Creates Slicing Warning notification with a custom text and no fade out.
void push_slicing_warning_notification(const std::string &text, bool gray, ModelObject const *obj, ObjectID oid, int warning_step, int warning_msg_id);
// marks slicing errors as gray
@@ -375,6 +381,7 @@ private:
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler);
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin);
+ virtual void bbl_render_block_notification(GLCanvas3D &canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin);
// close will dissapear notification on next render
virtual void close() { m_state = EState::ClosePending; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);}
// data from newer notification of same type
@@ -384,6 +391,8 @@ private:
void reinit() { m_state = EState::Unknown; }
// returns top after movement
float get_top() const { return m_top_y; }
+ // returns bottom after movement
+ float get_bottom() const { return m_bottom_y; }
//returns top in actual frame
float get_current_top() const { return m_top_y; }
const NotificationType get_type() const { return m_data.type; }
@@ -420,6 +429,13 @@ private:
const float text_x, const float text_y,
const std::string text,
bool more = false);
+ virtual void bbl_render_block_notif_text(ImGuiWrapper& imgui,
+ const float win_size_x, const float win_size_y,
+ const float win_pos_x, const float win_pos_y);
+ virtual void bbl_render_block_notif_buttons(ImGuiWrapper& imgui,
+ ImVec2 win_size,
+ ImVec2 win_pos);
+ virtual void bbl_render_block_notif_left_sign(ImGuiWrapper &imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y);
// Left sign could be error or warning sign
virtual void bbl_render_left_sign(ImGuiWrapper &imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y);
@@ -511,6 +527,8 @@ private:
float m_window_width { 450.0f };
//Distance from bottom of notifications to top of this notification
float m_top_y { 0.0f };
+ //Distance from top of block notifications to bottom of this notification
+ float m_bottom_y { 0.0f };
// Height of text - Used as basic scaling unit!
float m_line_height;
// endlines for text1, hypertext excluded
diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp
index 95599ecb5f..cf758aae25 100644
--- a/src/slic3r/GUI/PartPlate.cpp
+++ b/src/slic3r/GUI/PartPlate.cpp
@@ -38,7 +38,7 @@
#include "format.hpp"
#include "slic3r/GUI/GUI.hpp"
#include
-
+#include
using boost::optional;
namespace fs = boost::filesystem;
@@ -577,7 +577,7 @@ void PartPlate::render_logo_texture(GLTexture &logo_texture, const GeometryBuffe
}
}
-void PartPlate::render_logo(bool bottom) const
+void PartPlate::render_logo(bool bottom, bool render_cali) const
{
if (!m_partplate_list->render_bedtype_logo) {
// render third-party printer texture logo
@@ -656,6 +656,7 @@ void PartPlate::render_logo(bool bottom) const
}
m_partplate_list->load_bedtype_textures();
+ m_partplate_list->load_cali_textures();
// btDefault should be skipped
auto curr_bed_type = get_bed_type();
@@ -665,6 +666,7 @@ void PartPlate::render_logo(bool bottom) const
curr_bed_type = proj_cfg.opt_enum(std::string("curr_bed_type"));
}
int bed_type_idx = (int)curr_bed_type;
+ // render bed textures
for (auto &part : m_partplate_list->bed_texture_info[bed_type_idx].parts) {
if (part.texture) {
if (part.buffer && part.buffer->get_vertices_count() > 0
@@ -681,6 +683,24 @@ void PartPlate::render_logo(bool bottom) const
}
}
}
+
+ // render cali texture
+ if (render_cali) {
+ for (auto& part : m_partplate_list->cali_texture_info.parts) {
+ if (part.texture) {
+ if (part.buffer && part.buffer->get_vertices_count() > 0) {
+ if (part.offset.x() != m_origin.x() || part.offset.y() != m_origin.y()) {
+ part.offset = Vec2d(m_origin.x(), m_origin.y());
+ part.update_buffer();
+ }
+ render_logo_texture(*(part.texture),
+ *(part.buffer),
+ bottom,
+ part.vbo_id);
+ }
+ }
+ }
+ }
}
void PartPlate::render_exclude_area(bool force_default_color) const {
@@ -1311,6 +1331,14 @@ std::vector PartPlate::get_extruders(bool conside_custom_gcode) const
plate_extruders.insert(plate_extruders.end(), volume_extruders.begin(), volume_extruders.end());
}
+ // layer range
+ for (auto layer_range : mo->layer_config_ranges) {
+ if (layer_range.second.has("extruder")) {
+ if (auto id = layer_range.second.option("extruder")->getInt(); id > 0)
+ plate_extruders.push_back(id);
+ }
+ }
+
bool obj_support = false;
const ConfigOption* obj_support_opt = mo->config.option("enable_support");
const ConfigOption *obj_raft_opt = mo->config.option("raft_layers");
@@ -1365,6 +1393,142 @@ std::vector PartPlate::get_extruders(bool conside_custom_gcode) const
return plate_extruders;
}
+std::vector PartPlate::get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const
+{
+ std::vector plate_extruders;
+
+ // if 3mf file
+ int glb_support_intf_extr = full_config.opt_int("support_interface_filament");
+ int glb_support_extr = full_config.opt_int("support_filament");
+ bool glb_support = full_config.opt_bool("enable_support");
+ glb_support |= full_config.opt_int("raft_layers") > 0;
+
+ for (std::set>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it)
+ {
+ int obj_id = it->first;
+ int instance_id = it->second;
+
+ if ((obj_id >= 0) && (obj_id < m_model->objects.size()))
+ {
+ ModelObject* object = m_model->objects[obj_id];
+ ModelInstance* instance = object->instances[instance_id];
+
+ if (!instance->printable)
+ continue;
+
+ for (ModelVolume* mv : object->volumes) {
+ std::vector volume_extruders = mv->get_extruders();
+ plate_extruders.insert(plate_extruders.end(), volume_extruders.begin(), volume_extruders.end());
+ }
+
+ // layer range
+ for (auto layer_range : object->layer_config_ranges) {
+ if (layer_range.second.has("extruder")) {
+ if (auto id = layer_range.second.option("extruder")->getInt(); id > 0)
+ plate_extruders.push_back(id);
+ }
+ }
+
+ bool obj_support = false;
+ const ConfigOption* obj_support_opt = object->config.option("enable_support");
+ const ConfigOption *obj_raft_opt = object->config.option("raft_layers");
+ if (obj_support_opt != nullptr || obj_raft_opt != nullptr) {
+ if (obj_support_opt != nullptr)
+ obj_support = obj_support_opt->getBool();
+ if (obj_raft_opt != nullptr)
+ obj_support |= obj_raft_opt->getInt() > 0;
+ }
+ else
+ obj_support = glb_support;
+
+ if (!obj_support)
+ continue;
+
+ int obj_support_intf_extr = 0;
+ const ConfigOption* support_intf_extr_opt = object->config.option("support_interface_filament");
+ if (support_intf_extr_opt != nullptr)
+ obj_support_intf_extr = support_intf_extr_opt->getInt();
+ if (obj_support_intf_extr != 0)
+ plate_extruders.push_back(obj_support_intf_extr);
+ else if (glb_support_intf_extr != 0)
+ plate_extruders.push_back(glb_support_intf_extr);
+
+ int obj_support_extr = 0;
+ const ConfigOption* support_extr_opt = object->config.option("support_filament");
+ if (support_extr_opt != nullptr)
+ obj_support_extr = support_extr_opt->getInt();
+ if (obj_support_extr != 0)
+ plate_extruders.push_back(obj_support_extr);
+ else if (glb_support_extr != 0)
+ plate_extruders.push_back(glb_support_extr);
+ }
+ }
+
+ if (conside_custom_gcode) {
+ //BBS
+ int nums_extruders = 0;
+ if (const ConfigOptionStrings *color_option = dynamic_cast(full_config.option("filament_colour"))) {
+ nums_extruders = color_option->values.size();
+ if (m_model->plates_custom_gcodes.find(m_plate_index) != m_model->plates_custom_gcodes.end()) {
+ for (auto item : m_model->plates_custom_gcodes.at(m_plate_index).gcodes) {
+ if (item.type == CustomGCode::Type::ToolChange && item.extruder <= nums_extruders)
+ plate_extruders.push_back(item.extruder);
+ }
+ }
+ }
+ }
+
+ std::sort(plate_extruders.begin(), plate_extruders.end());
+ auto it_end = std::unique(plate_extruders.begin(), plate_extruders.end());
+ plate_extruders.resize(std::distance(plate_extruders.begin(), it_end));
+ return plate_extruders;
+}
+
+std::vector PartPlate::get_extruders_without_support(bool conside_custom_gcode) const
+{
+ std::vector plate_extruders;
+ // if gcode.3mf file
+ if (m_model->objects.empty()) {
+ for (int i = 0; i < slice_filaments_info.size(); i++) {
+ plate_extruders.push_back(slice_filaments_info[i].id + 1);
+ }
+ return plate_extruders;
+ }
+
+ // if 3mf file
+ const DynamicPrintConfig& glb_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
+
+ for (int obj_idx = 0; obj_idx < m_model->objects.size(); obj_idx++) {
+ if (!contain_instance_totally(obj_idx, 0))
+ continue;
+
+ ModelObject* mo = m_model->objects[obj_idx];
+ for (ModelVolume* mv : mo->volumes) {
+ std::vector volume_extruders = mv->get_extruders();
+ plate_extruders.insert(plate_extruders.end(), volume_extruders.begin(), volume_extruders.end());
+ }
+ }
+
+ if (conside_custom_gcode) {
+ //BBS
+ int nums_extruders = 0;
+ if (const ConfigOptionStrings* color_option = dynamic_cast(wxGetApp().preset_bundle->project_config.option("filament_colour"))) {
+ nums_extruders = color_option->values.size();
+ if (m_model->plates_custom_gcodes.find(m_plate_index) != m_model->plates_custom_gcodes.end()) {
+ for (auto item : m_model->plates_custom_gcodes.at(m_plate_index).gcodes) {
+ if (item.type == CustomGCode::Type::ToolChange && item.extruder <= nums_extruders)
+ plate_extruders.push_back(item.extruder);
+ }
+ }
+ }
+ }
+
+ std::sort(plate_extruders.begin(), plate_extruders.end());
+ auto it_end = std::unique(plate_extruders.begin(), plate_extruders.end());
+ plate_extruders.resize(std::distance(plate_extruders.begin(), it_end));
+ return plate_extruders;
+}
+
std::vector PartPlate::get_used_extruders()
{
std::vector used_extruders;
@@ -1916,6 +2080,47 @@ void PartPlate::translate_all_instance(Vec3d position)
return;
}
+void PartPlate::duplicate_all_instance(unsigned int dup_count, bool need_skip, std::map& skip_objects)
+{
+ std::set> old_obj_list = obj_to_instance_set;
+ BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": plate_id %1%, dup_count %2%") % m_plate_index % dup_count;
+ for (std::set>::iterator it = old_obj_list.begin(); it != old_obj_list.end(); ++it)
+ {
+ int obj_id = it->first;
+ int instance_id = it->second;
+
+ if ((obj_id >= 0) && (obj_id < m_model->objects.size()))
+ {
+ ModelObject* object = m_model->objects[obj_id];
+ ModelInstance* instance = object->instances[instance_id];
+
+ if (need_skip)
+ {
+ if (skip_objects.find(instance->loaded_id) != skip_objects.end())
+ {
+ instance->printable = false;
+ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": skipped object, loaded_id %1%, name %2%, set to unprintable, no need to duplicate") % instance->loaded_id % object->name;
+ continue;
+ }
+ }
+ for (size_t index = 0; index < dup_count; index ++)
+ {
+ ModelObject* newObj = m_model->add_object(*object);
+ newObj->name = object->name +"_"+ std::to_string(index+1);
+ int new_obj_id = m_model->objects.size() - 1;
+ for ( size_t new_instance_id = 0; new_instance_id < object->instances.size(); new_instance_id++ )
+ {
+ obj_to_instance_set.emplace(std::pair(new_obj_id, new_instance_id));
+ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": duplicate object into plate: index_pair [%1%,%2%], obj_id %3%") % new_obj_id % new_instance_id % newObj->id().id;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+
//update instance exclude state
void PartPlate::update_instance_exclude_status(int obj_id, int instance_id, BoundingBoxf3* bounding_box)
@@ -2012,6 +2217,28 @@ bool PartPlate::has_printable_instances()
return result;
}
+bool PartPlate::is_all_instances_unprintable()
+{
+ bool result = true;
+
+ for (std::set>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it) {
+ int obj_id = it->first;
+ int instance_id = it->second;
+
+ if (obj_id >= m_model->objects.size()) continue;
+
+ ModelObject * object = m_model->objects[obj_id];
+ ModelInstance *instance = object->instances[instance_id];
+
+ if ((instance->printable)) {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+}
+
//move instances to left or right PartPlate
void PartPlate::move_instances_to(PartPlate& left_plate, PartPlate& right_plate, BoundingBoxf3* bounding_box)
{
@@ -2301,7 +2528,7 @@ bool PartPlate::intersects(const BoundingBoxf3& bb) const
return print_volume.intersects(bb);
}
-void PartPlate::render(bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id)
+void PartPlate::render(bool bottom, bool only_body, bool force_background_color, HeightLimitMode mode, int hover_id, bool render_cali)
{
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_BLEND));
@@ -2318,7 +2545,10 @@ void PartPlate::render(bool bottom, bool only_body, bool force_background_color,
render_grid(bottom);
if (!bottom && m_selected && !force_background_color) {
- render_logo(bottom);
+ if (m_partplate_list)
+ render_logo(bottom, m_partplate_list->render_cali_logo && render_cali);
+ else
+ render_logo(bottom);
}
render_height_limit(mode);
@@ -2838,6 +3068,7 @@ void PartPlateList::release_icon_textures()
}
//reset
PartPlateList::is_load_bedtype_textures = false;
+ PartPlateList::is_load_cali_texture = false;
for (int i = 0; i < btCount; i++) {
for (auto& part: bed_texture_info[i].parts) {
if (part.texture) {
@@ -3944,8 +4175,7 @@ bool PartPlateList::preprocess_nonprefered_areas(arrangement::ArrangePolygons& r
bool added = false;
std::vector nonprefered_regions;
- nonprefered_regions.emplace_back(Vec2d{ 45,0 }, Vec2d{ 225,25 }); // extrusion calibration region
- nonprefered_regions.emplace_back(Vec2d{ 25,0 }, Vec2d{ 50,60 }); // hand-eye calibration region
+ nonprefered_regions.emplace_back(Vec2d{ 18,0 }, Vec2d{ 240,15 }); // new extrusion & hand-eye calibration region
//has exclude areas
PartPlate* plate = m_plate_list[0];
@@ -4102,7 +4332,7 @@ void PartPlateList::postprocess_arrange_polygon(arrangement::ArrangePolygon& arr
/*rendering related functions*/
//render
-void PartPlateList::render(bool bottom, bool only_current, bool only_body, int hover_id)
+void PartPlateList::render(bool bottom, bool only_current, bool only_body, int hover_id, bool render_cali)
{
const std::lock_guard local_lock(m_plates_mutex);
std::vector::iterator it = m_plate_list.begin();
@@ -4127,15 +4357,15 @@ void PartPlateList::render(bool bottom, bool only_current, bool only_body, int h
if (current_index == m_current_plate) {
PartPlate::HeightLimitMode height_mode = (only_current)?PartPlate::HEIGHT_LIMIT_NONE:m_height_limit_mode;
if (plate_hover_index == current_index)
- (*it)->render(bottom, only_body, false, height_mode, plate_hover_action);
+ (*it)->render(bottom, only_body, false, height_mode, plate_hover_action, render_cali);
else
- (*it)->render(bottom, only_body, false, height_mode, -1);
+ (*it)->render(bottom, only_body, false, height_mode, -1, render_cali);
}
else {
if (plate_hover_index == current_index)
- (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action);
+ (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, plate_hover_action, render_cali);
else
- (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1);
+ (*it)->render(bottom, only_body, false, PartPlate::HEIGHT_LIMIT_NONE, -1, render_cali);
}
}
}
@@ -4323,14 +4553,23 @@ bool PartPlateList::is_all_slice_results_valid() const
//check whether all plates's slice result valid for print
bool PartPlateList::is_all_slice_results_ready_for_print() const
{
- for (unsigned int i = 0; i < (unsigned int)m_plate_list.size(); ++i)
- {
- if (!m_plate_list[i]->is_slice_result_ready_for_print()
- && m_plate_list[i]->has_printable_instances()
- )
- return false;
- }
- return true;
+ bool res = false;
+
+ for (unsigned int i = 0; i < (unsigned int) m_plate_list.size(); ++i) {
+ if (!m_plate_list[i]->empty()) {
+ if (m_plate_list[i]->is_all_instances_unprintable()) {
+ continue;
+ }
+ if (!m_plate_list[i]->is_slice_result_ready_for_print()) {
+ return false;
+ }
+ }
+ if (m_plate_list[i]->is_slice_result_ready_for_print()) {
+ res = true;
+ }
+ }
+
+ return res;
}
@@ -4564,6 +4803,7 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w
plate_data_item->gcode_prediction = std::to_string(
(int) m_plate_list[i]->get_slice_result()->print_statistics.modes[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].time);
plate_data_item->toolpath_outside = m_plate_list[i]->m_gcode_result->toolpath_outside;
+ plate_data_item->is_label_object_enabled = m_plate_list[i]->m_gcode_result->label_object_enabled;
Print *print = nullptr;
m_plate_list[i]->get_print((PrintBase **) &print, nullptr, nullptr);
if (print) {
@@ -4612,8 +4852,8 @@ int PartPlateList::load_from_3mf_structure(PlateDataPtrs& plate_data_list)
{
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":plate index %1% seems invalid, skip it")% plate_data_list[i]->plate_index;
}
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, gcode_file %2%, is_sliced_valid %3%, toolpath_outside %4%, is_support_used %5%")
- %i %plate_data_list[i]->gcode_file %plate_data_list[i]->is_sliced_valid %plate_data_list[i]->toolpath_outside %plate_data_list[i]->is_support_used;
+ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, gcode_file %2%, is_sliced_valid %3%, toolpath_outside %4%, is_support_used %5% is_label_object_enabled %6%")
+ %i %plate_data_list[i]->gcode_file %plate_data_list[i]->is_sliced_valid %plate_data_list[i]->toolpath_outside %plate_data_list[i]->is_support_used %plate_data_list[i]->is_label_object_enabled;
//load object and instance from 3mf
//just test for file correct or not, we will rebuild later
/*for (std::vector>::iterator it = plate_data_list[i]->objects_and_instances.begin(); it != plate_data_list[i]->objects_and_instances.end(); ++it)
@@ -4634,6 +4874,7 @@ int PartPlateList::load_from_3mf_structure(PlateDataPtrs& plate_data_list)
}
ps.total_used_filament *= 1000; //koef
gcode_result->toolpath_outside = plate_data_list[i]->toolpath_outside;
+ gcode_result->label_object_enabled = plate_data_list[i]->is_label_object_enabled;
m_plate_list[index]->slice_filaments_info = plate_data_list[i]->slice_filaments_info;
gcode_result->warnings = plate_data_list[i]->warnings;
if (m_plater && !plate_data_list[i]->thumbnail_file.empty()) {
@@ -4722,6 +4963,7 @@ void PartPlateList::print() const
}
bool PartPlateList::is_load_bedtype_textures = false;
+bool PartPlateList::is_load_cali_texture = false;
void PartPlateList::BedTextureInfo::TexturePart::update_buffer()
{
@@ -4812,5 +5054,39 @@ void PartPlateList::load_bedtype_textures()
PartPlateList::is_load_bedtype_textures = true;
}
+void PartPlateList::init_cali_texture_info()
+{
+ BedTextureInfo::TexturePart cali_line(18, 2, 224, 16, "bbl_cali_lines.svg");
+ cali_texture_info.parts.push_back(cali_line);
+
+ for (int j = 0; j < cali_texture_info.parts.size(); j++) {
+ cali_texture_info.parts[j].update_buffer();
+ }
+}
+
+void PartPlateList::load_cali_textures()
+{
+ if (PartPlateList::is_load_cali_texture) return;
+
+ init_cali_texture_info();
+ GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
+ GLint logo_tex_size = (max_tex_size < 2048) ? max_tex_size : 2048;
+ for (int i = 0; i < (unsigned int)btCount; ++i) {
+ for (int j = 0; j < cali_texture_info.parts.size(); j++) {
+ std::string filename = resources_dir() + "/images/" + cali_texture_info.parts[j].filename;
+ if (boost::filesystem::exists(filename)) {
+ PartPlateList::cali_texture_info.parts[j].texture = new GLTexture();
+ if (!PartPlateList::cali_texture_info.parts[j].texture->load_from_svg_file(filename, true, true, true, logo_tex_size)) {
+ BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": load cali texture from %1% failed!") % filename;
+ }
+ }
+ else {
+ BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": load cali texture from %1% failed!") % filename;
+ }
+ }
+ }
+ PartPlateList::is_load_cali_texture = true;
+}
+
}//end namespace GUI
}//end namespace slic3r
diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp
index 9c2617f0e4..cea321358d 100644
--- a/src/slic3r/GUI/PartPlate.hpp
+++ b/src/slic3r/GUI/PartPlate.hpp
@@ -170,10 +170,8 @@ private:
void calc_vertex_for_number(int index, bool one_number, GeometryBuffer &buffer);
void calc_vertex_for_icons(int index, GeometryBuffer &buffer);
void calc_vertex_for_icons_background(int icon_count, GeometryBuffer &buffer);
- //void calc_vertex_for_name_tex(GeometryBuffer &buffer);
-
void render_background(bool force_default_color = false) const;
- void render_logo(bool bottom) const;
+ void render_logo(bool bottom, bool render_cali = true) const;
void render_logo_texture(GLTexture& logo_texture, const GeometryBuffer& logo_buffer, bool bottom, unsigned int vbo_id) const;
void render_exclude_area(bool force_default_color) const;
//void render_background_for_picking(const float* render_color) const;
@@ -288,6 +286,8 @@ public:
Vec3d get_origin() { return m_origin; }
Vec3d estimate_wipe_tower_size(const double w, const double wipe_volume) const;
std::vector get_extruders(bool conside_custom_gcode = false) const;
+ std::vector get_extruders_under_cli(bool conside_custom_gcode, DynamicPrintConfig& full_config) const;
+ std::vector get_extruders_without_support(bool conside_custom_gcode = false) const;
std::vector get_used_extruders();
/* instance related operations*/
@@ -315,6 +315,9 @@ public:
//translate instance on the plate
void translate_all_instance(Vec3d position);
+ //duplicate all instance for count
+ void duplicate_all_instance(unsigned int dup_count, bool need_skip, std::map& skip_objects);
+
//update instance exclude state
void update_instance_exclude_status(int obj_id, int instance_id, BoundingBoxf3* bounding_box = nullptr);
@@ -328,6 +331,7 @@ public:
//whether it is has printable instances
bool has_printable_instances();
+ bool is_all_instances_unprintable();
//move instances to left or right PartPlate
void move_instances_to(PartPlate& left_plate, PartPlate& right_plate, BoundingBoxf3* bounding_box = nullptr);
@@ -340,7 +344,7 @@ public:
bool contains(const BoundingBoxf3& bb) const;
bool intersects(const BoundingBoxf3& bb) const;
- void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1);
+ void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false);
void render_for_picking() const { on_render_for_picking(); }
void set_selected();
void set_unselected();
@@ -400,7 +404,7 @@ public:
{
bool result = m_slice_result_valid;
if (result)
- result = m_gcode_result ? (!m_gcode_result->toolpath_outside && !m_gcode_result->conflict_result.has_value()) : false;
+ result = m_gcode_result ? (!m_gcode_result->toolpath_outside) : false;// && !m_gcode_result->conflict_result.has_value() gcode conflict can also print
return result;
}
@@ -524,6 +528,7 @@ class PartPlateList : public ObjectBase
// set render option
bool render_bedtype_logo = true;
bool render_plate_settings = true;
+ bool render_cali_logo = true;
bool m_is_dark = false;
@@ -587,6 +592,7 @@ public:
static const unsigned int MAX_PLATES_COUNT = MAX_PLATE_COUNT;
static GLTexture bed_textures[(unsigned int)btCount];
static bool is_load_bedtype_textures;
+ static bool is_load_cali_texture;
PartPlateList(int width, int depth, int height, Plater* platerObj, Model* modelObj, PrinterTechnology tech = ptFFF);
PartPlateList(Plater* platerObj, Model* modelObj, PrinterTechnology tech = ptFFF);
@@ -732,9 +738,10 @@ public:
/*rendering related functions*/
void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; }
- void render(bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1);
+ void render(bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false);
void render_for_picking_pass();
void set_render_option(bool bedtype_texture, bool plate_settings);
+ void set_render_cali(bool value = true) { render_cali_logo = value; }
BoundingBoxf3& get_bounding_box() { return m_bounding_box; }
//int select_plate_by_hover_id(int hover_id);
int select_plate_by_obj(int obj_index, int instance_index);
@@ -792,7 +799,12 @@ public:
void init_bed_type_info();
void load_bedtype_textures();
+ void show_cali_texture(bool show = true);
+ void init_cali_texture_info();
+ void load_cali_textures();
+
BedTextureInfo bed_texture_info[btCount];
+ BedTextureInfo cali_texture_info;
};
} // namespace GUI
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 3dcdb87cd4..6d64666327 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -60,6 +60,10 @@
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/ClipperUtils.hpp"
+// For stl export
+#include "libslic3r/CSGMesh/ModelToCSGMesh.hpp"
+#include "libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp"
+
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
@@ -169,6 +173,8 @@ wxDEFINE_EVENT(EVT_INSTALL_PLUGIN_HINT, wxCommandEvent);
wxDEFINE_EVENT(EVT_PREVIEW_ONLY_MODE_HINT, wxCommandEvent);
//BBS: change light/dark mode
wxDEFINE_EVENT(EVT_GLCANVAS_COLOR_MODE_CHANGED, SimpleEvent);
+//BBS: print
+wxDEFINE_EVENT(EVT_PRINT_FROM_SDCARD_VIEW, SimpleEvent);
bool Plater::has_illegal_filename_characters(const wxString& wxs_name)
@@ -528,8 +534,8 @@ Sidebar::Sidebar(Plater *parent)
p->m_text_printer_settings = new Label(p->m_panel_printer_title, _L("Printer"), LB_PROPAGATE_MOUSE_EVENT);
p->m_printer_icon->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
- auto wizard_t = new ConfigWizard(wxGetApp().mainframe);
- wizard_t->run(ConfigWizard::RR_USER, ConfigWizard::SP_CUSTOM);
+ //auto wizard_t = new ConfigWizard(wxGetApp().mainframe);
+ //wizard_t->run(ConfigWizard::RR_USER, ConfigWizard::SP_CUSTOM);
});
@@ -619,11 +625,8 @@ Sidebar::Sidebar(Plater *parent)
m_bed_type_list = new ComboBox(p->m_panel_printer_content, wxID_ANY, wxString(""), wxDefaultPosition, {-1, FromDIP(30)}, 0, nullptr, wxCB_READONLY);
const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type");
if (bed_type_def && bed_type_def->enum_keys_map) {
- for (auto item : *bed_type_def->enum_keys_map) {
- if (item.first == "Default Plate")
- continue;
-
- m_bed_type_list->AppendString(_L(item.first));
+ for (auto item : bed_type_def->enum_labels) {
+ m_bed_type_list->AppendString(_L(item));
}
}
@@ -1628,6 +1631,10 @@ bool Sidebar::show_object_list(bool show) const
{
if (!p->m_object_list->Show(show))
return false;
+ if (!show)
+ p->object_layers->Show(false);
+ else
+ p->m_object_list->part_selection_changed();
p->scrolled->Layout();
return true;
}
@@ -1731,6 +1738,7 @@ struct Plater::priv
bool m_slice_all{false};
bool m_is_slicing {false};
bool m_is_publishing {false};
+ int m_is_RightClickInLeftUI{-1};
int m_cur_slice_plate;
//BBS: m_slice_all in .gcode.3mf file case, set true when slice all
bool m_slice_all_only_has_gcode{ false };
@@ -1906,6 +1914,12 @@ struct Plater::priv
bool are_view3D_labels_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->are_labels_shown(); }
void show_view3D_labels(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_labels(show); }
+ bool is_view3D_overhang_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_overhang_shown(); }
+ void show_view3D_overhang(bool show)
+ {
+ if (current_panel == view3D) view3D->get_canvas3d()->show_overhang(show);
+ }
+
bool is_sidebar_collapsed() const { return sidebar->is_collapsed(); }
void collapse_sidebar(bool collapse);
@@ -2115,6 +2129,7 @@ struct Plater::priv
//void show_action_buttons(const bool is_ready_to_slice) const;
bool show_publish_dlg(bool show = true);
void update_publish_dialog_status(wxString &msg, int percent = -1);
+ void on_action_print_plate_from_sdcard(SimpleEvent&);
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
// triangulate the bed and store the triangles into m_bed.m_triangles,
@@ -2227,6 +2242,9 @@ private:
std::vector> current_warnings;
bool show_warning_dialog { false };
+ //record print preset
+ void record_start_print_preset(std::string action);
+
};
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf)", std::regex::icase);
@@ -2499,6 +2517,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
assemble_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this);
assemble_canvas->Bind(EVT_GLVIEWTOOLBAR_3D, [q](SimpleEvent&) { q->select_view_3D("3D"); });
assemble_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this);
+ assemble_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); });
+ assemble_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); });
}
if (wxGetApp().is_editor()) {
@@ -2512,6 +2532,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
q->Bind(EVT_GLTOOLBAR_SLICE_PLATE, &priv::on_action_slice_plate, this);
q->Bind(EVT_GLTOOLBAR_SLICE_ALL, &priv::on_action_slice_all, this);
q->Bind(EVT_GLTOOLBAR_PRINT_PLATE, &priv::on_action_print_plate, this);
+ q->Bind(EVT_PRINT_FROM_SDCARD_VIEW, &priv::on_action_print_plate_from_sdcard, this);
q->Bind(EVT_GLTOOLBAR_SELECT_SLICED_PLATE, &priv::on_action_select_sliced_plate, this);
q->Bind(EVT_GLTOOLBAR_PRINT_ALL, &priv::on_action_print_all, this);
q->Bind(EVT_GLTOOLBAR_EXPORT_GCODE, &priv::on_action_export_gcode, this);
@@ -3701,12 +3722,13 @@ std::vector Plater::priv::load_files(const std::vector& input_
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs);
- Selection& selection = view3D->get_canvas3d()->get_selection();
- selection.clear();
- for (size_t idx : obj_idxs) {
- selection.add_object((unsigned int)idx, false);
+ if (!load_config) {
+ Selection& selection = view3D->get_canvas3d()->get_selection();
+ selection.clear();
+ for (size_t idx : obj_idxs) {
+ selection.add_object((unsigned int)idx, false);
+ }
}
-
// BBS: update object list selection
this->sidebar->obj_list()->update_selections();
@@ -3776,17 +3798,15 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode
const double max_ratio = std::max(ratio(0), ratio(1));
if (max_ratio > 10000) {
MessageDialog dlg(q, _L("Your object appears to be too large, Do you want to scale it down to fit the heat bed automatically?"), _L("Object too large"),
- wxICON_QUESTION | wxYES_NO);
+ wxICON_QUESTION | wxYES);
int answer = dlg.ShowModal();
- if (answer == wxID_YES) {
- // the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
- // so scale down the mesh
- object->scale_mesh_after_creation(1. / max_ratio);
- object->origin_translation = Vec3d::Zero();
- object->center_around_origin();
- scaled_down = true;
- break;
- }
+ // the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
+ // so scale down the mesh
+ object->scale_mesh_after_creation(1. / max_ratio);
+ object->origin_translation = Vec3d::Zero();
+ object->center_around_origin();
+ scaled_down = true;
+ break;
}
else if (max_ratio > 10) {
MessageDialog dlg(q, _L("Your object appears to be too large, Do you want to scale it down to fit the heat bed automatically?"), _L("Object too large"),
@@ -3836,8 +3856,14 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode
for (auto& instance : new_instances) {
auto offset = instance->get_offset();
auto start_point = this->bed.build_volume().bounding_volume2d().center();
- auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({ start_point(0),start_point(1) });
- Vec3d displacement = { empty_cell.x(),empty_cell.y(),offset(2)};
+ bool plate_empty = partplate_list.get_curr_plate()->empty();
+ Vec3d displacement;
+ if (plate_empty)
+ displacement = {start_point(0), start_point(1), offset(2)};
+ else {
+ auto empty_cell = wxGetApp().plater()->canvas3D()->get_nearest_empty_cell({start_point(0), start_point(1)});
+ displacement = {empty_cell.x(), empty_cell.y(), offset(2)};
+ }
instance->set_offset(displacement);
}
#endif
@@ -3852,9 +3878,7 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& mode
//}
notification_manager->close_notification_of_type(NotificationType::UpdatedItemsInfo);
- for (const size_t idx : obj_idxs) {
- wxGetApp().obj_list()->add_object_to_list(idx);
- }
+ wxGetApp().obj_list()->add_objects_to_list(obj_idxs);
update();
// Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(),
@@ -4166,6 +4190,7 @@ void Plater::priv::reset(bool apply_presets_change)
if (view3D->is_layers_editing_enabled())
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
+ view3D->get_canvas3d()->reset_all_gizmos();
reset_gcode_toolpaths();
//BBS: update gcode to current partplate's
@@ -4185,6 +4210,7 @@ void Plater::priv::reset(bool apply_presets_change)
// Stop and reset the Print content.
this->background_process.reset();
model.clear_objects();
+ assemble_view->get_canvas3d()->reset_explosion_ratio();
update();
//BBS
@@ -4505,13 +4531,13 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
if (invalidated != Print::APPLY_STATUS_UNCHANGED && was_running && ! this->background_process.running() &&
(return_state & UPDATE_BACKGROUND_PROCESS_RESTART) == 0) {
- // The background processing was killed and it will not be restarted.
- // Post the "canceled" callback message, so that it will be processed after any possible pending status bar update messages.
- SlicingProcessCompletedEvent evt(EVT_PROCESS_COMPLETED, 0,
- SlicingProcessCompletedEvent::Cancelled, nullptr);
- BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%, post an EVT_PROCESS_COMPLETED to main, status %2%")%__LINE__ %evt.status();
- wxQueueEvent(q, evt.Clone());
- }
+ // The background processing was killed and it will not be restarted.
+ // Post the "canceled" callback message, so that it will be processed after any possible pending status bar update messages.
+ SlicingProcessCompletedEvent evt(EVT_PROCESS_COMPLETED, 0,
+ SlicingProcessCompletedEvent::Cancelled, nullptr);
+ BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%, post an EVT_PROCESS_COMPLETED to main, status %2%")%__LINE__ %evt.status();
+ wxQueueEvent(q, evt.Clone());
+ }
if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
{
@@ -4636,7 +4662,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
return;
- show_warning_dialog = false;
+ show_warning_dialog = true;
if (! output_path.empty()) {
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
notification_manager->push_delayed_notification(NotificationType::ExportOngoing, []() {return true; }, 1000, 0);
@@ -4668,7 +4694,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
return;
- show_warning_dialog = false;
+ show_warning_dialog = true;
if (! output_path.empty()) {
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
notification_manager->push_delayed_notification(NotificationType::ExportOngoing, []() {return true; }, 1000, 0);
@@ -5103,7 +5129,7 @@ void Plater::priv::reload_from_disk()
if (has_source && old_volume->source.object_idx < int(new_model.objects.size())) {
const ModelObject *obj = new_model.objects[old_volume->source.object_idx];
if (old_volume->source.volume_idx < int(obj->volumes.size())) {
- if (obj->volumes[old_volume->source.volume_idx]->name == old_volume->name) {
+ if (obj->volumes[old_volume->source.volume_idx]->source.input_file == old_volume->source.input_file) {
new_volume_idx = old_volume->source.volume_idx;
new_object_idx = old_volume->source.object_idx;
match_found = true;
@@ -5574,15 +5600,16 @@ void Plater::priv::on_select_bed_type(wxCommandEvent &evt)
{
ComboBox* combo = static_cast(evt.GetEventObject());
int selection = combo->GetSelection();
- wxString bed_type_name = combo->GetString(selection);
+ std::string bed_type_name = print_config_def.get("curr_bed_type")->enum_values[selection];
+ PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
DynamicPrintConfig& proj_config = wxGetApp().preset_bundle->project_config;
const t_config_enum_values* keys_map = print_config_def.get("curr_bed_type")->enum_keys_map;
if (keys_map) {
BedType new_bed_type = btCount;
for (auto item : *keys_map) {
- if (_L(item.first) == bed_type_name) {
+ if (item.first == bed_type_name) {
new_bed_type = (BedType)item.second;
break;
}
@@ -5924,21 +5951,24 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
// This bool stops showing export finished notification even when process_completed_with_error is false
bool has_error = false;
if (evt.error()) {
- std::pair message = evt.format_error_message();
+ auto message = evt.format_error_message();
if (evt.critical_error()) {
if (q->m_tracking_popup_menu) {
// We don't want to pop-up a message box when tracking a pop-up menu.
// We postpone the error message instead.
q->m_tracking_popup_menu_error_message = message.first;
} else {
- show_error(q, message.first, message.second != 0);
+ show_error(q, message.first, message.second.size() != 0 && message.second[0] != 0);
notification_manager->set_slicing_progress_hidden();
}
} else {
- ModelObject const *model_object = nullptr;
- const PrintObject *print_object = this->background_process.m_fff_print->get_object(ObjectID(message.second));
- if (print_object) model_object = print_object->model_object();
- notification_manager->push_slicing_error_notification(message.first, model_object);
+ std::vector ptrs;
+ for (auto oid : message.second)
+ {
+ const PrintObject *print_object = this->background_process.m_fff_print->get_object(ObjectID(oid));
+ if (print_object) { ptrs.push_back(print_object->model_object()); }
+ }
+ notification_manager->push_slicing_error_notification(message.first, ptrs);
}
if (evt.invalidate_plater())
{
@@ -6219,6 +6249,18 @@ void Plater::priv::on_action_print_plate(SimpleEvent&)
m_select_machine_dlg->ShowModal();
}
+void Plater::priv::on_action_print_plate_from_sdcard(SimpleEvent&)
+{
+ if (q != nullptr) {
+ BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ":received print plate event\n";
+ }
+
+ //BBS
+ if (!m_select_machine_dlg) m_select_machine_dlg = new SelectMachineDialog(q);
+ m_select_machine_dlg->prepare(0);
+ m_select_machine_dlg->ShowModal();
+}
+
void Plater::priv::on_action_send_to_printer(bool isall)
{
@@ -7278,18 +7320,19 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name, const UndoRed
tower.rotation = proj_cfg.opt_float("wipe_tower_rotation_angle");
}
}
- const GLGizmosManager& gizmos = view3D->get_canvas3d()->get_gizmos_manager();
+ const GLGizmosManager& gizmos = get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : view3D->get_canvas3d()->get_gizmos_manager();
if (snapshot_type == UndoRedo::SnapshotType::ProjectSeparator)
this->undo_redo_stack().clear();
- this->undo_redo_stack().take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), partplate_list, snapshot_data);
+ this->undo_redo_stack().take_snapshot(snapshot_name, model, get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_selection() : view3D->get_canvas3d()->get_selection(), gizmos, partplate_list, snapshot_data);
if (snapshot_type == UndoRedo::SnapshotType::LeavingGizmoWithAction) {
// Filter all but the last UndoRedo::SnapshotType::GizmoAction in a row between the last UndoRedo::SnapshotType::EnteringGizmo and UndoRedo::SnapshotType::LeavingGizmoWithAction.
// The remaining snapshot will be renamed to a more generic name,
// depending on what gizmo is being left.
- assert(gizmos.get_current() != nullptr);
- std::string new_name = gizmos.get_current()->get_action_snapshot_name();
- this->undo_redo_stack().reduce_noisy_snapshots(new_name);
+ if (gizmos.get_current() != nullptr) {
+ std::string new_name = gizmos.get_current()->get_action_snapshot_name();
+ this->undo_redo_stack().reduce_noisy_snapshots(new_name);
+ }
} else if (snapshot_type == UndoRedo::SnapshotType::ProjectSeparator) {
// Reset the "dirty project" flag.
m_undo_redo_stack_main.mark_current_as_saved();
@@ -7311,6 +7354,13 @@ void Plater::priv::undo()
// BBS: undo-redo until modify record
while (--it_current != snapshots.begin() && !snapshot_modifies_project(*it_current));
if (it_current == snapshots.begin()) return;
+ if (get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) {
+ if (it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::GizmoAction &&
+ it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::EnteringGizmo &&
+ it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::LeavingGizmoNoAction &&
+ it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::LeavingGizmoWithAction)
+ return;
+ }
this->undo_redo_to(it_current);
}
@@ -7413,8 +7463,8 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator
const UndoRedo::Snapshot snapshot_copy = *it_snapshot;
// Do the jump in time.
if (it_snapshot->timestamp < this->undo_redo_stack().active_snapshot_time() ?
- this->undo_redo_stack().undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, top_snapshot_data, it_snapshot->timestamp) :
- this->undo_redo_stack().redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, it_snapshot->timestamp)) {
+ this->undo_redo_stack().undo(model, get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_selection() : this->view3D->get_canvas3d()->get_selection(), get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, top_snapshot_data, it_snapshot->timestamp) :
+ this->undo_redo_stack().redo(model, get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, it_snapshot->timestamp)) {
if (printer_technology_changed) {
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
AppConfig *app_config = wxGetApp().app_config;
@@ -7491,7 +7541,7 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator
void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool /* temp_snapshot_was_taken */)
{
- this->view3D->get_canvas3d()->get_selection().clear();
+ get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_selection().clear() : this->view3D->get_canvas3d()->get_selection().clear();
// Update volumes from the deserializd model, always stop / update the background processing (for both the SLA and FFF technologies).
this->update((unsigned int)UpdateParams::FORCE_BACKGROUND_PROCESSING_UPDATE | (unsigned int)UpdateParams::POSTPONE_VALIDATION_ERROR_MESSAGE);
// Release old snapshots if the memory allocated is excessive. This may remove the top most snapshot if jumping to the very first snapshot.
@@ -7500,8 +7550,12 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo
// triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size.
this->undo_redo_stack().release_least_recently_used();
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
- this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances);
- this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot);
+ get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ assemble_view->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances) :
+ this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances);
+ get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ?
+ assemble_view->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot) :
+ this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot);
wxGetApp().obj_list()->update_after_undo_redo();
@@ -7653,6 +7707,7 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_
//get_partplate_list().update_slice_context_to_current_plate(p->background_process);
//p->preview->update_gcode_result(p->partplate_list.get_current_slice_result());
reset(transfer_preset_changes);
+ reset_project_dirty_after_save();
reset_project_dirty_initial_presets();
wxGetApp().update_saved_preset_from_current_preset();
update_project_dirty_from_presets();
@@ -7777,6 +7832,9 @@ void Plater::load_project(wxString const& filename2,
p->camera.requires_zoom_to_plate = REQUIRES_ZOOM_TO_ALL_PLATE;
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
}
+ else {
+ p->partplate_list.select_plate_view();
+ }
if (previous_gcode)
collapse_sidebar(false);
@@ -7814,7 +7872,7 @@ int Plater::save_project(bool saveAs)
return wxID_CANCEL;
//BBS export 3mf without gcode
- if (export_3mf(into_path(filename), SaveStrategy::SplitModel) < 0) {
+ if (export_3mf(into_path(filename), SaveStrategy::SplitModel | SaveStrategy::ShareMesh) < 0) {
MessageDialog(this, _L("Failed to save the project.\nPlease check whether the folder exists online or if other programs open the project file."),
_L("Save project"), wxOK | wxICON_WARNING).ShowModal();
return wxID_CANCEL;
@@ -7828,7 +7886,7 @@ int Plater::save_project(bool saveAs)
up_to_date(true, true);
wxGetApp().update_saved_preset_from_current_preset();
- p->dirty_state.reset_after_save();
+ reset_project_dirty_after_save();
return wxID_YES;
}
@@ -7839,9 +7897,9 @@ void Plater::import_model_id(const std::string& download_info)
std::string filename;
std::string download_origin_url = wxGetApp().url_decode(download_info);
- fs::path download_path = fs::path(download_origin_url);
- download_url = download_origin_url;
- filename = download_path.filename().string();
+ fs::path download_path = fs::path(download_origin_url);
+ download_url = download_origin_url;
+ filename = download_path.filename().string();
bool download_ok = false;
@@ -7937,7 +7995,8 @@ void Plater::import_model_id(const std::string& download_info)
}
//target_path /= (boost::format("%1%_%2%.3mf") % filename % unique).str();
- target_path /= filename.c_str();
+ target_path /= fs::path(wxString(filename).wc_str());
+
fs::path tmp_path = target_path;
tmp_path += format(".%1%", ".download");
@@ -8048,11 +8107,11 @@ void Plater::add_model(bool imperial_units/* = false*/, std::string fname/* = "
std::vector paths;
if(fname.empty()){
- wxArrayString input_files;
+ wxArrayString input_files;
wxGetApp().import_model(this, input_files);
if (input_files.empty())
return;
-
+
for (const auto &file : input_files)
paths.emplace_back(into_path(file));
}
@@ -8659,6 +8718,16 @@ void Plater::load_gcode(const wxString& filename)
}
*current_result = std::move(processor.extract_result());
//current_result->filename = filename;
+
+ BedType bed_type = current_result->bed_type;
+ if (bed_type != BedType::btCount) {
+ DynamicPrintConfig &proj_config = wxGetApp().preset_bundle->project_config;
+ proj_config.set_key_value("curr_bed_type", new ConfigOptionEnum(bed_type));
+ on_bed_type_change(bed_type);
+ }
+
+ current_print.apply(this->model(), wxGetApp().preset_bundle->full_config());
+
current_print.set_gcode_file_ready();
// show results
@@ -9402,6 +9471,9 @@ bool Plater::is_view3D_shown() const { return p->is_view3D_shown(); }
bool Plater::are_view3D_labels_shown() const { return p->are_view3D_labels_shown(); }
void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); }
+bool Plater::is_view3D_overhang_shown() const { return p->is_view3D_overhang_shown(); }
+void Plater::show_view3D_overhang(bool show) { p->show_view3D_overhang(show); }
+
bool Plater::is_sidebar_collapsed() const { return p->is_sidebar_collapsed(); }
void Plater::collapse_sidebar(bool show) { p->collapse_sidebar(show); }
@@ -9446,8 +9518,12 @@ int GUI::Plater::close_with_confirm(std::function second_check)
wxGetApp().app_config->set("save_project_choise", result == wxID_YES ? "yes" : "no");
if (result == wxID_YES) {
result = save_project();
- if (result == wxID_CANCEL)
- return result;
+ if (result == wxID_CANCEL) {
+ if (choise.empty())
+ return result;
+ else
+ result = wxID_NO;
+ }
}
}
@@ -9938,38 +10014,92 @@ void Plater::export_core_3mf()
export_3mf(path_u8, SaveStrategy::Silence);
}
+// Following lambda generates a combined mesh for export with normals pointing outwards.
+TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, std::function notify_func)
+{
+ TriangleMesh mesh;
+
+ std::vector csgmesh;
+ csgmesh.reserve(2 * mo.volumes.size());
+ bool has_splitable_volume = csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
+ csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits);
+
+ if (csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }) == csgmesh.end()) {
+ try {
+ MeshBoolean::mcut::McutMeshPtr meshPtr = csg::perform_csgmesh_booleans_mcut(Range{ std::begin(csgmesh), std::end(csgmesh) });
+ mesh = MeshBoolean::mcut::mcut_to_triangle_mesh(*meshPtr);
+ }
+ catch (...) {}
+#if 0
+ // if mcut fails, try again with CGAL
+ if (mesh.empty()) {
+ try {
+ auto meshPtr = csg::perform_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) });
+ mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*meshPtr);
+ }
+ catch (...) {}
+ }
+#endif
+ }
+
+ if (mesh.empty()) {
+ if (notify_func)
+ notify_func(_u8L("Unable to perform boolean operation on model meshes. "
+ "Only positive parts will be exported."));
+
+ for (const ModelVolume* v : mo.volumes)
+ if (v->is_model_part()) {
+ TriangleMesh vol_mesh(v->mesh());
+ vol_mesh.transform(v->get_matrix(), true);
+ mesh.merge(vol_mesh);
+ }
+ }
+
+ if (instance_id == -1) {
+ 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);
+ }
+ }
+ else if (0 <= instance_id && instance_id < int(mo.instances.size()))
+ mesh.transform(mo.instances[instance_id]->get_matrix(), true);
+ return mesh;
+}
+
+// BBS export with/without boolean, however, stil merge mesh
+#define EXPORT_WITH_BOOLEAN 0
void Plater::export_stl(bool extended, bool selection_only)
{
if (p->model.objects.empty()) { return; }
- wxBusyCursor wait;
-
- const auto &selection = p->get_selection();
-
- // BBS support mulity objects
- // const auto obj_idx = selection.get_object_idx();
- // if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
- // return;
-
- if (selection_only && selection.is_wipe_tower())
- return;
-
- //BBS
- if (selection_only) {
- // only support selection single full object and mulitiple full object
- if (!selection.is_single_full_object() && !selection.is_multiple_full_object())
- return;
- }
-
wxString path = p->get_export_file(FT_STL);
if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
+ wxBusyCursor wait;
+ const auto& selection = p->get_selection();
+ const auto obj_idx = selection.get_object_idx();
+
+#if EXPORT_WITH_BOOLEAN
+ if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
+ return;
+#else
+ // BBS support selecting multiple objects
+ if (selection_only && selection.is_wipe_tower()) return;
+
+ // BBS
+ if (selection_only) {
+ // only support selection single full object and mulitiple full object
+ if (!selection.is_single_full_object() && !selection.is_multiple_full_object()) return;
+ }
// Following lambda generates a combined mesh for export with normals pointing outwards.
- auto mesh_to_export = [](const ModelObject& mo, int instance_id) {
+ auto mesh_to_export_fff_no_boolean = [](const ModelObject &mo, int instance_id) {
TriangleMesh mesh;
- for (const ModelVolume* v : mo.volumes)
+ for (const ModelVolume *v : mo.volumes)
if (v->is_model_part()) {
TriangleMesh vol_mesh(v->mesh());
vol_mesh.transform(v->get_matrix(), true);
@@ -9978,125 +10108,72 @@ void Plater::export_stl(bool extended, bool selection_only)
if (instance_id == -1) {
TriangleMesh vols_mesh(mesh);
mesh = TriangleMesh();
- for (const ModelInstance* i : mo.instances) {
+ for (const ModelInstance *i : mo.instances) {
TriangleMesh m = vols_mesh;
m.transform(i->get_matrix(), true);
mesh.merge(m);
}
- }
- else if (0 <= instance_id && instance_id < int(mo.instances.size()))
+ } else if (0 <= instance_id && instance_id < int(mo.instances.size()))
mesh.transform(mo.instances[instance_id]->get_matrix(), true);
return mesh;
};
+#endif
+ auto mesh_to_export_sla = [&, this](const ModelObject& mo, int instance_id) {
+ TriangleMesh mesh;
- TriangleMesh mesh;
- if (p->printer_technology == ptFFF) {
- if (selection_only) {
- if (selection.is_single_full_object()) {
- const auto obj_idx = selection.get_object_idx();
- const ModelObject* model_object = p->model.objects[obj_idx];
- if (selection.get_mode() == Selection::Instance)
- {
- mesh = std::move(mesh_to_export(*model_object, ( model_object->instances.size() > 1) ? -1 : selection.get_instance_idx()));
- }
- 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(), true);
- }
+ const SLAPrintObject *object = this->p->sla_print.get_print_object_by_model_object_id(mo.id());
- if (model_object->instances.size() == 1)
- mesh.translate(-model_object->origin_translation.cast());
- }
- else if (selection.is_multiple_full_object()) {
- const std::set>& instances_idxs = p->get_selection().get_selected_object_instances();
- for (const std::pair& i : instances_idxs)
- {
- ModelObject* object = p->model.objects[i.first];
- mesh.merge(mesh_to_export(*object, i.second));
- }
- }
- }
+ if (auto m = object->get_mesh_to_print(); m.empty())
+ mesh = combine_mesh_fff(mo, instance_id, [this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); });
else {
- for (const ModelObject *o : p->model.objects)
- mesh.merge(mesh_to_export(*o, -1));
- }
- }
- else
- {
- // This is SLA mode, all objects have only one volume.
- // However, we must have a look at the backend to load
- // hollowed mesh and/or supports
- const auto obj_idx = selection.get_object_idx();
- const PrintObjects& objects = p->sla_print.objects();
- for (const SLAPrintObject* object : objects)
- {
- const ModelObject* model_object = object->model_object();
- if (selection_only) {
- if (model_object->id() != p->model.objects[obj_idx]->id())
- continue;
- }
- Transform3d mesh_trafo_inv = object->trafo().inverse();
- bool is_left_handed = object->is_left_handed();
+ const Transform3d mesh_trafo_inv = object->trafo().inverse();
+ const bool is_left_handed = object->is_left_handed();
- TriangleMesh pad_mesh;
- bool has_pad_mesh = extended && object->has_mesh(slaposPad);
- if (has_pad_mesh)
- {
- pad_mesh = object->get_mesh(slaposPad);
- pad_mesh.transform(mesh_trafo_inv);
- }
+ auto pad_mesh = extended? object->pad_mesh() : TriangleMesh{};
+ pad_mesh.transform(mesh_trafo_inv);
+
+ auto supports_mesh = extended ? object->support_mesh() : TriangleMesh{};
+ supports_mesh.transform(mesh_trafo_inv);
- TriangleMesh supports_mesh;
- bool has_supports_mesh = extended && object->has_mesh(slaposSupportTree);
- if (has_supports_mesh)
- {
- supports_mesh = object->get_mesh(slaposSupportTree);
- supports_mesh.transform(mesh_trafo_inv);
- }
const std::vector& obj_instances = object->instances();
- for (const SLAPrintObject::Instance& obj_instance : obj_instances)
- {
- auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
- [&obj_instance](const ModelInstance *mi) { return mi->id() == obj_instance.instance_id; });
- assert(it != model_object->instances.end());
+ for (const SLAPrintObject::Instance& obj_instance : obj_instances) {
+ auto it = std::find_if(object->model_object()->instances.begin(), object->model_object()->instances.end(),
+ [&obj_instance](const ModelInstance *mi) { return mi->id() == obj_instance.instance_id; });
+ assert(it != object->model_object()->instances.end());
- if (it != model_object->instances.end())
- {
- bool one_inst_only = selection_only && ! selection.is_single_full_object();
+ if (it != object->model_object()->instances.end()) {
+ const bool one_inst_only = selection_only && ! selection.is_single_full_object();
- int instance_idx = it - model_object->instances.begin();
+ const int instance_idx = it - object->model_object()->instances.begin();
const Transform3d& inst_transform = one_inst_only
- ? Transform3d::Identity()
- : object->model_object()->instances[instance_idx]->get_transformation().get_matrix();
+ ? Transform3d::Identity()
+ : object->model_object()->instances[instance_idx]->get_transformation().get_matrix();
TriangleMesh inst_mesh;
- if (has_pad_mesh)
- {
+ if (!pad_mesh.empty()) {
TriangleMesh inst_pad_mesh = pad_mesh;
inst_pad_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_pad_mesh);
}
- if (has_supports_mesh)
- {
+ if (!supports_mesh.empty()) {
TriangleMesh inst_supports_mesh = supports_mesh;
inst_supports_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_supports_mesh);
}
- TriangleMesh inst_object_mesh = object->get_mesh_to_slice();
+ TriangleMesh inst_object_mesh = object->get_mesh_to_print();
+
inst_object_mesh.transform(mesh_trafo_inv);
inst_object_mesh.transform(inst_transform, is_left_handed);
inst_mesh.merge(inst_object_mesh);
- // ensure that the instance lays on the bed
- inst_mesh.translate(0.0f, 0.0f, -inst_mesh.bounding_box().min[2]);
+ // ensure that the instance lays on the bed
+ inst_mesh.translate(0.0f, 0.0f, -inst_mesh.bounding_box().min.z());
- // merge instance with global mesh
+ // merge instance with global mesh
mesh.merge(inst_mesh);
if (one_inst_only)
@@ -10104,6 +10181,50 @@ void Plater::export_stl(bool extended, bool selection_only)
}
}
}
+
+ return mesh;
+ };
+
+ std::function
+ mesh_to_export;
+
+ if (p->printer_technology == ptFFF)
+#if EXPORT_WITH_BOOLEAN
+ mesh_to_export = [this](const ModelObject& mo, int instance_id) {return Plater::combine_mesh_fff(mo, instance_id,
+ [this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); }); };
+#else
+ mesh_to_export = mesh_to_export_fff_no_boolean;
+#endif
+ else
+ mesh_to_export = mesh_to_export_sla;
+
+ TriangleMesh mesh;
+ if (selection_only) {
+ if (selection.is_single_full_object()) {
+ const auto obj_idx = selection.get_object_idx();
+ const ModelObject* model_object = p->model.objects[obj_idx];
+ if (selection.get_mode() == Selection::Instance)
+ mesh = mesh_to_export(*model_object, (model_object->instances.size() > 1) ? -1 : selection.get_instance_idx());
+ 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(), true);
+ }
+
+ if (model_object->instances.size() == 1) mesh.translate(-model_object->origin_translation.cast());
+ }
+ else if (selection.is_multiple_full_object()) {
+ const std::set>& instances_idxs = p->get_selection().get_selected_object_instances();
+ for (const std::pair& i : instances_idxs) {
+ ModelObject* object = p->model.objects[i.first];
+ mesh.merge(mesh_to_export(*object, i.second));
+ }
+ }
+ }
+ else {
+ for (const ModelObject* o : p->model.objects) {
+ mesh.merge(mesh_to_export(*o, -1));
+ }
}
Slic3r::store_stl(path_u8.c_str(), &mesh, true);
@@ -11038,7 +11159,7 @@ std::vector Plater::get_colors_for_color_print(const GCodeProcessor
return colors;
}
-
+
wxString Plater::get_project_filename(const wxString& extension) const
{
return p->get_project_filename(extension);
@@ -11469,7 +11590,8 @@ int Plater::select_plate(int plate_index, bool need_slice)
{
if (need_slice) { //from preview's thumbnail
if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) || (gcode_result->moves.empty())){
- //part_plate->update_slice_result_valid_state(false);
+ if (invalidated & PrintBase::APPLY_STATUS_INVALIDATED)
+ part_plate->update_slice_result_valid_state(false);
p->process_completed_with_error = -1;
p->m_slice_all = false;
reset_gcode_toolpaths();
@@ -11897,11 +12019,23 @@ void Plater::show_object_info()
{
NotificationManager *notify_manager = get_notification_manager();
const Selection& selection = get_selection();
+ int selCount = selection.get_volume_idxs().size();
ModelObjectPtrs objects = model().objects;
int obj_idx = selection.get_object_idx();
std::string info_text;
- if (objects.empty() || (obj_idx < 0) || (obj_idx >= objects.size()) ||
+ if (selCount > 1 && !selection.is_single_full_object()) {
+ notify_manager->bbl_close_objectsinfo_notification();
+ if (selection.get_mode() == Selection::EMode::Volume) {
+ info_text += (boost::format(_utf8(L("Number of currently selected parts: %1%\n"))) % selCount).str();
+ } else if (selection.get_mode() == Selection::EMode::Instance) {
+ int content_count = selection.get_content().size();
+ info_text += (boost::format(_utf8(L("Number of currently selected objects: %1%\n"))) % content_count).str();
+ }
+ notify_manager->bbl_show_objectsinfo_notification(info_text, false, !(p->current_panel == p->view3D));
+ return;
+ }
+ else if (objects.empty() || (obj_idx < 0) || (obj_idx >= objects.size()) ||
objects[obj_idx]->volumes.empty() ||// hack to avoid crash when deleting the last object on the bed
(selection.is_single_full_object() && objects[obj_idx]->instances.size()> 1) ||
!(selection.is_single_full_instance() || selection.is_single_volume()))
@@ -11939,12 +12073,12 @@ void Plater::show_object_info()
size = vol->get_convex_hull().transformed_bounding_box(t).size();
}
else {
- int obj_idx, vol_idx;
- wxGetApp().obj_list()->get_selected_item_indexes(obj_idx, vol_idx);
- if (obj_idx < 0) {
- //corner case when merge/split/remove
- return;
- }
+ //int obj_idx, vol_idx;
+ //wxGetApp().obj_list()->get_selected_item_indexes(obj_idx, vol_idx);
+ //if (obj_idx < 0) {
+ // //corner case when merge/split/remove
+ // return;
+ //}
info_text += (boost::format(_utf8(L("Object name: %1%\n"))) % model_object->name).str();
face_count = static_cast(model_object->facets_count());
size = model_object->instance_convex_hull_bounding_box(inst_idx).size();
@@ -12277,7 +12411,8 @@ wxMenu* Plater::default_menu() { return p->menus.default_menu();
wxMenu* Plater::instance_menu() { return p->menus.instance_menu(); }
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
-
+int Plater::GetPlateIndexByRightMenuInLeftUI() { return p->m_is_RightClickInLeftUI; }
+void Plater::SetPlateIndexByRightMenuInLeftUI(int index) { p->m_is_RightClickInLeftUI = index; }
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
{
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index a1ba2e827b..0796b69a32 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -288,6 +288,9 @@ public:
bool are_view3D_labels_shown() const;
void show_view3D_labels(bool show);
+ bool is_view3D_overhang_shown() const;
+ void show_view3D_overhang(bool show);
+
bool is_sidebar_collapsed() const;
void collapse_sidebar(bool show);
@@ -332,6 +335,7 @@ public:
void export_gcode_3mf(bool export_all = false);
void send_gcode_finish(wxString name);
void export_core_3mf();
+ static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function notify_func = {});
void export_stl(bool extended = false, bool selection_only = false);
//BBS: remove amf
//void export_amf();
@@ -686,7 +690,8 @@ public:
wxMenu* instance_menu();
wxMenu* layer_menu();
wxMenu* multi_selection_menu();
-
+ int GetPlateIndexByRightMenuInLeftUI();
+ void SetPlateIndexByRightMenuInLeftUI(int);
static bool has_illegal_filename_characters(const wxString& name);
static bool has_illegal_filename_characters(const std::string& name);
static void show_illegal_characters_warning(wxWindow* parent);
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index d82834e2c8..c9e8fb9b4c 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -1961,7 +1961,9 @@ void Selection::update_type()
unsigned int sels_cntr = 0;
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
{
- const ModelObject* model_object = m_model->objects[it->first];
+ bool is_wipe_tower = it->first >= 1000;
+ int actual_obj_id = is_wipe_tower ? it->first - 1000 : it->first;
+ const ModelObject *model_object = m_model->objects[actual_obj_id];
unsigned int volumes_count = (unsigned int)model_object->volumes.size();
unsigned int instances_count = (unsigned int)model_object->instances.size();
sels_cntr += volumes_count * instances_count;
@@ -2710,9 +2712,14 @@ void Selection::paste_objects_from_clipboard()
displacement = {empty_cell.x() + point_offset.x(), empty_cell.y() + point_offset.y(), start_offset(2)};
}
- for (ModelInstance* inst : dst_object->instances)
+ for (ModelInstance* inst : dst_object->instances) {
inst->set_offset(displacement);
+ //BBS init asssmble transformation
+ Geometry::Transformation t = inst->get_transformation();
+ inst->set_assemble_transformation(t);
+ }
+
object_idxs.push_back(m_model->objects.size() - 1);
#ifdef _DEBUG
check_model_ids_validity(*m_model);
diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp
index 5c1669b1b9..bfee49bd2b 100644
--- a/src/slic3r/GUI/Selection.hpp
+++ b/src/slic3r/GUI/Selection.hpp
@@ -362,6 +362,11 @@ public:
bool requires_local_axes() const;
+ void render_bounding_box(const BoundingBoxf3& box, float* color, float scale) {
+ m_scale_factor = scale;
+ render_bounding_box(box, color);
+ }
+
//BBS
void cut_to_clipboard();
void copy_to_clipboard();