Merge remote-tracking branch 'upstream/main' into libvgcode

# Conflicts:
#	src/libslic3r/GCode/GCodeProcessor.cpp
#	src/libslic3r/GCode/GCodeProcessor.hpp
#	src/slic3r/CMakeLists.txt
#	src/slic3r/GUI/GCodeViewer.cpp
#	src/slic3r/GUI/GCodeViewer.hpp
#	src/slic3r/GUI/GLCanvas3D.cpp
#	src/slic3r/GUI/GLCanvas3D.hpp
#	src/slic3r/GUI/GUI_Preview.cpp
This commit is contained in:
Andrew Sun
2025-11-09 18:48:04 -05:00
2978 changed files with 1208720 additions and 66304 deletions

View File

@@ -668,7 +668,7 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
if (its_num_open_edges(new_objects[i]->volumes[j]->mesh().its) > 0) {
if (!is_showed_dialog) {
is_showed_dialog = true;
MessageDialog dlg(nullptr, _L("non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxCANCEL);
MessageDialog dlg(nullptr, _L("non-manifold edges be caused by cut tool, do you want to fix it now?"), "", wxYES | wxNO);
int ret = dlg.ShowModal();
if (ret == wxID_YES) {
user_fix_model = true;

View File

@@ -2873,10 +2873,10 @@ void GLGizmoEmboss::draw_advanced()
m_imgui->disabled_end(); // allowe_surface_distance
// slider for Clock-wise angle in degress
// slider for Clockwise angle in degress
// stored angle is optional CCW and in radians
// Convert stored value to degress
// minus create clock-wise roation from CCW
// minus create clockwise roation from CCW
float angle = current_style.angle.value_or(0.f);
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
float def_angle_deg_val =
@@ -2886,7 +2886,7 @@ void GLGizmoEmboss::draw_advanced()
&def_angle_deg_val : nullptr;
if (rev_slider(tr.rotation, angle_deg, def_angle_deg, _u8L("Undo rotation"),
limits.angle.min, limits.angle.max, u8"%.2f °",
_L("Rotate text Clock-wise."))) {
_L("Rotate text Clockwise."))) {
// convert back to radians and CCW
double angle_rad = -angle_deg * M_PI / 180.0;
Geometry::to_range_pi_pi(angle_rad);

View File

@@ -34,9 +34,7 @@ bool GLGizmoMeshBoolean::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
const ModelInstance* mi = mo->instances[m_parent.get_selection().get_instance_idx()];
std::vector<Transform3d> 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());
//}
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
}
const Camera& camera = wxGetApp().plater()->get_camera();
@@ -50,8 +48,7 @@ bool GLGizmoMeshBoolean::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
// 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_ptr());
if (mesh_raycaster.unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal,
if (m_c->raycaster()->raycasters()[mesh_id] ->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<double>()).squaredNorm();
@@ -181,6 +178,9 @@ void GLGizmoMeshBoolean::on_set_state()
CommonGizmosDataID GLGizmoMeshBoolean::on_get_requirements() const
{
if (m_c && m_c->raycaster_ptr()) {
m_c->raycaster_ptr()->set_only_support_model_part_flag(false);
}
return CommonGizmosDataID(
int(CommonGizmosDataID::SelectionInfo)
| int(CommonGizmosDataID::InstancesHider)

View File

@@ -58,21 +58,6 @@ bool GLGizmoMmuSegmentation::on_is_activable() const
return !selection.is_empty() && (selection.is_single_full_instance() || selection.is_any_volume()) && wxGetApp().filaments_cnt() > 1;
}
//BBS: use the global one in 3DScene.cpp
/*static std::vector<ColorRGBA> get_extruders_colors()
{
unsigned char rgb_color[3] = {};
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::vector<ColorRGBA> 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};
}
return colors_out;
}*/
static std::vector<int> get_extruder_id_for_volumes(const ModelObject &model_object)
{
std::vector<int> extruders_idx;
@@ -89,7 +74,7 @@ static std::vector<int> get_extruder_id_for_volumes(const ModelObject &model_obj
void GLGizmoMmuSegmentation::init_extruders_data()
{
m_extruders_colors = get_extruders_colors();
m_extruders_colors = wxGetApp().plater()->get_extruders_colors();
m_selected_extruder_idx = 0;
// keep remap table consistent with current extruder count
@@ -195,8 +180,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
// Reinitialize triangle selectors because of change of extruder count need also change the size of GLIndexedVertexArray
if (prev_extruders_count != wxGetApp().filaments_cnt())
this->init_model_triangle_selectors();
}
else if (get_extruders_colors() != m_extruders_colors) {
} else if (wxGetApp().plater()->get_extruders_colors() != m_extruders_colors) {
this->init_extruders_data();
this->update_triangle_selectors_colors();
}
@@ -635,7 +619,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc["height_range"] + ":");
ImGui::SameLine(height_max_width);
ImGui::PushItemWidth(sliders_width);
std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Heigh range," "Facet in [cursor z, cursor z + height] will be selected.");
std::string format_str = std::string("%.2f") + I18N::translate_utf8("mm", "Height range," "Facet in [cursor z, cursor z + height] will be selected.");
m_imgui->bbl_slider_float_style("##cursor_height", &m_cursor_height, CursorHeightMin, CursorHeightMax, format_str.data(), 1.0f, true);
ImGui::SameLine(drag_left_width + height_max_width);
ImGui::PushItemWidth(1.5 * slider_icon_width);
@@ -833,7 +817,7 @@ void GLGizmoMmuSegmentation::update_from_model_object(bool first_update)
// Extruder colors need to be reloaded before calling init_model_triangle_selectors to render painted triangles
// using colors from loaded 3MF and not from printer profile in Slicer.
if (int prev_extruders_count = int(m_extruders_colors.size());
prev_extruders_count != wxGetApp().filaments_cnt() || get_extruders_colors() != m_extruders_colors)
prev_extruders_count != wxGetApp().filaments_cnt() || wxGetApp().plater()->get_extruders_colors() != m_extruders_colors)
this->init_extruders_data();
this->init_model_triangle_selectors();
@@ -873,6 +857,9 @@ void GLGizmoMmuSegmentation::on_set_state()
ModelObject* mo = m_c->selection_info()->model_object();
if (mo) Slic3r::save_object_mesh(*mo);
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE));
if (m_current_tool == ImGui::GapFillIcon) {//exit gap fill
m_current_tool = ImGui::CircleButtonIcon;
}
}
}

View File

@@ -1504,7 +1504,7 @@ void GLGizmoSVG::draw_filename(){
m_volume_shape.svg_file = svg_file_new; // clear data
}
} else if (ImGui::IsItemHovered()) {
tooltip = _u8L("Change to another .svg file");
tooltip = _u8L("Change to another SVG file.");
}
std::string forget_path = _u8L("Forget the file path");
@@ -1586,7 +1586,7 @@ void GLGizmoSVG::draw_filename(){
}
} else if (ImGui::IsItemHovered()) {
tooltip = _u8L("Save as '.svg' file");
tooltip = _u8L("Save as SVG file.");
}
//draw(get_icon(m_icons, IconType::save));
@@ -1885,13 +1885,13 @@ void GLGizmoSVG::draw_rotation()
ImGui::SameLine(m_gui_cfg->input_offset);
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
// slider for Clock-wise angle in degress
// slider for Clockwise angle in degress
// stored angle is optional CCW and in radians
// Convert stored value to degress
// minus create clock-wise roation from CCW
// minus create clockwise roation from CCW
float angle = m_angle.value_or(0.f);
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
if (m_imgui->slider_float("##angle", &angle_deg, limits.angle.min, limits.angle.max, u8"%.2f °", 1.f, false, _L("Rotate text Clock-wise."))){
if (m_imgui->slider_float("##angle", &angle_deg, limits.angle.min, limits.angle.max, u8"%.2f °", 1.f, false, _L("Rotate text Clockwise."))){
// convert back to radians and CCW
double angle_rad = -angle_deg * M_PI / 180.0;
Geometry::to_range_pi_pi(angle_rad);

View File

@@ -59,6 +59,10 @@ InstancesHider* CommonGizmosDataPool::instances_hider() const
return inst_hider->is_valid() ? inst_hider : nullptr;
}
CommonGizmosDataObjects::Raycaster *CommonGizmosDataPool::raycaster_ptr() {
return dynamic_cast<Raycaster *>(m_data.at(CommonGizmosDataID::Raycaster).get());
}
Raycaster* CommonGizmosDataPool::raycaster() const
{
Raycaster* rc = dynamic_cast<Raycaster*>(m_data.at(CommonGizmosDataID::Raycaster).get());
@@ -220,8 +224,13 @@ void Raycaster::on_update()
std::vector<const TriangleMesh*> meshes;
const std::vector<ModelVolume*>& mvs = mo->volumes;
for (const ModelVolume* mv : mvs) {
if (mv->is_model_part())
if (m_only_support_model_part) {
if (mv->is_model_part()) {
meshes.push_back(&mv->mesh());
}
} else {
meshes.push_back(&mv->mesh());
}
}
if (meshes != m_old_meshes) {
@@ -246,6 +255,9 @@ std::vector<const MeshRaycaster*> Raycaster::raycasters() const
return mrcs;
}
void CommonGizmosDataObjects::Raycaster::set_only_support_model_part_flag(bool flag) {
m_only_support_model_part = flag;
}
void ObjectClipper::on_update()
{

View File

@@ -93,6 +93,7 @@ public:
CommonGizmosDataObjects::SelectionInfo* selection_info() const;
CommonGizmosDataObjects::InstancesHider* instances_hider() const;
// CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const;
CommonGizmosDataObjects::Raycaster * raycaster_ptr();
CommonGizmosDataObjects::Raycaster* raycaster() const;
CommonGizmosDataObjects::ObjectClipper* object_clipper() const;
// CommonGizmosDataObjects::SupportsClipper* supports_clipper() const;
@@ -211,6 +212,7 @@ public:
const MeshRaycaster* raycaster() const { assert(m_raycasters.size() == 1); return m_raycasters.front().get(); }
std::vector<const MeshRaycaster*> raycasters() const;
void set_only_support_model_part_flag(bool);
protected:
void on_update() override;
@@ -219,6 +221,7 @@ protected:
private:
std::vector<std::unique_ptr<MeshRaycaster>> m_raycasters;
std::vector<const TriangleMesh*> m_old_meshes;
bool m_only_support_model_part{true};
};

View File

@@ -183,8 +183,9 @@ void GLGizmosManager::switch_gizmos_icon_filename()
bool GLGizmosManager::init()
{
bool result = init_icon_textures();
if (!result) return result;
if (!m_gizmos.empty())
return true;
init_icon_textures();
m_background_texture.metadata.filename = m_is_dark ? "toolbar_background_dark.png" : "toolbar_background.png";
m_background_texture.metadata.left = 16;
@@ -241,9 +242,12 @@ bool GLGizmosManager::init()
return true;
}
std::map<int, void *> GLGizmosManager::icon_list = {};
bool GLGizmosManager::init_icon_textures()
{
if (icon_list.size() > 0) {
return true;
}
ImTextureID texture_id;
icon_list.clear();
@@ -277,6 +281,26 @@ bool GLGizmosManager::init_icon_textures()
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle.svg", 64, 64, texture_id))
icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE, texture_id));
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_hover.svg", 64, 64, texture_id))
icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_HOVER, texture_id));
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_dark.svg", 64, 64, texture_id))
icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_DARK, texture_id));
else
return false;
if (IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/axis_toggle_hover_dark.svg", 64, 64, texture_id))
icon_list.insert(std::make_pair((int) IC_AXIS_TOGGLE_DARK_HOVER, texture_id));
else
return false;
return true;
}

View File

@@ -147,7 +147,7 @@ private:
void on_set_color_timer(wxTimerEvent& evt);
// key MENU_ICON_NAME, value = ImtextureID
std::map<int, void*> icon_list;
static std::map<int, void*> icon_list;
bool m_is_dark = false;
@@ -170,6 +170,10 @@ public:
IC_TOOLBAR_TOOLTIP,
IC_TOOLBAR_TOOLTIP_HOVER,
IC_NAME_COUNT,
IC_AXIS_TOGGLE,
IC_AXIS_TOGGLE_HOVER,
IC_AXIS_TOGGLE_DARK,
IC_AXIS_TOGGLE_DARK_HOVER,
};
explicit GLGizmosManager(GLCanvas3D& parent);

View File

@@ -124,6 +124,9 @@ void GizmoObjectManipulation::update_settings_value(const Selection &selection)
else {//if (is_local_coordinates()) {//for scale
auto tran = selection.get_first_volume()->get_instance_transformation();
m_new_position = tran.get_matrix().inverse() * cs_center;
if (is_instance_coordinates()) {
m_new_position = Vec3d::Zero();
}
m_new_size = selection.get_bounding_box_in_current_reference_system().first.size();
m_unscale_size = selection.get_full_unscaled_instance_local_bounding_box().size();
m_new_scale = m_new_size.cwiseQuotient(m_unscale_size) * 100.0;
@@ -887,7 +890,13 @@ void GizmoObjectManipulation::do_render_move_window(ImGuiWrapper *imgui_wrapper,
index = 1;
index_unit = 1;
ImGui::AlignTextToFramePadding();
imgui_wrapper->text(_L("Position"));
if (selection.is_single_full_instance() && is_instance_coordinates()) {
imgui_wrapper->text(_L("Translate(Relative)"));
}
else {
imgui_wrapper->text(_L("Position"));
}
ImGui::SameLine(caption_max + index * space_size);
ImGui::PushItemWidth(unit_size);
ImGui::BBLInputDouble(label_values[0][0], &display_position[0], 0.0f, 0.0f, "%.2f");