diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 6b9151ff8..c10e90bdb 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -661,6 +661,23 @@ void ModelObject::delete_volume(size_t idx) ModelVolumePtrs::iterator i = this->volumes.begin() + idx; delete *i; this->volumes.erase(i); + + if (this->volumes.size() == 1) + { + // only one volume left + // center it and update the instances accordingly + // rationale: the volume may be shifted with respect to the object center and this may lead to wrong rotation and scaling + // when modifying the instance matrix of the derived GLVolume + ModelVolume* v = this->volumes.front(); + v->center_geometry(); + const Vec3d& vol_offset = v->get_offset(); + for (ModelInstance* inst : this->instances) + { + inst->set_offset(inst->get_offset() + inst->get_matrix(true) * vol_offset); + } + v->set_offset(Vec3d::Zero()); + } + this->invalidate_bounding_box(); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 3bbdf9246..ce952c549 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2471,15 +2471,6 @@ void PrintConfigDef::init_sla_params() def->min = 0; def->default_value = new ConfigOptionFloat(0.2); - def = this->add("support_head_back_radius", coFloat); - def->label = L("Support head back radius"); - def->category = L("Supports"); - def->tooltip = L("Radius of the back side of the 3d arrow"); - def->sidetext = L("mm"); - def->cli = ""; - def->min = 0; - def->default_value = new ConfigOptionFloat(0.5); - def = this->add("support_head_width", coFloat); def->label = L("Support head width"); def->category = L("Supports"); @@ -2496,7 +2487,19 @@ void PrintConfigDef::init_sla_params() def->sidetext = L("mm"); def->cli = ""; def->min = 0; - def->default_value = new ConfigOptionFloat(0.8); + def->default_value = new ConfigOptionFloat(0.5); + + def = this->add("support_pillar_widening_factor", coFloat); + def->label = L("Pillar widening factor"); + def->category = L("Supports"); + def->tooltip = L("Merging bridges or pillars into another pillars can " + "increase the radius. Zero means no increase, one means " + "full increase."); + def->sidetext = L(""); + def->cli = ""; + def->min = 0; + def->max = 1.0; + def->default_value = new ConfigOptionFloat(0.0); def = this->add("support_base_radius", coFloat); def->label = L("Support base radius"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index b3d0c33be..cd11c4298 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -913,20 +913,18 @@ public: // How much the pinhead has to penetrate the model surface ConfigOptionFloat support_head_penetration /*= 0.2*/; - // Radius of the back side of the 3d arrow. TODO: consider renaming this - // to actual pillar radius, because that's what it boils down to. - ConfigOptionFloat support_head_back_radius /*= 0.5*/; - // Width in mm from the back sphere center to the front sphere center. ConfigOptionFloat support_head_width /*= 1.0*/; // Radius in mm of the support pillars. - // TODO: This parameter is questionable. The pillar radius will be dynamic in - // nature. Merged pillars will have an increased thickness. This parameter - // may serve as the maximum radius, or maybe an increase when two are merged - // The default radius will be derived from head_back_radius_mm ConfigOptionFloat support_pillar_radius /*= 0.8*/; + // TODO: unimplemented at the moment. This coefficient will have an impact + // when bridges and pillars are merged. The resulting pillar should be a bit + // thicker than the ones merging into it. How much thicker? I don't know + // but it will be derived from this value. + ConfigOptionFloat support_pillar_widening_factor; + // Radius in mm of the pillar base. ConfigOptionFloat support_base_radius /*= 2.0*/; @@ -968,9 +966,9 @@ protected: OPT_PTR(supports_enable); OPT_PTR(support_head_front_radius); OPT_PTR(support_head_penetration); - OPT_PTR(support_head_back_radius); OPT_PTR(support_head_width); OPT_PTR(support_pillar_radius); + OPT_PTR(support_pillar_widening_factor); OPT_PTR(support_base_radius); OPT_PTR(support_base_height); OPT_PTR(support_critical_angle); diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 27fa53236..6591596da 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -309,7 +309,7 @@ struct Head { } double request_pillar_radius(double radius) const { - const double rmax = r_back_mm /* * 0.65*/ ; + const double rmax = r_back_mm; return radius > 0 && radius < rmax ? radius : rmax; } }; @@ -929,6 +929,9 @@ bool SLASupportTree::generate(const PointSet &points, const SupportConfig &cfg, const Controller &ctl) { + // If there are no input points there is no point in doing anything + if(points.rows() == 0) return false; + PointSet filtered_points; // all valid support points PointSet head_positions; // support points with pinhead PointSet head_normals; // head normals @@ -1183,7 +1186,7 @@ bool SLASupportTree::generate(const PointSet &points, // If the pillars are so close that they touch each other, // there is no need to bridge them together. - if(pillar_dist > 2*cfg.pillar_radius_mm && + if(pillar_dist > 2*cfg.head_back_radius_mm && bridge_distance < cfg.max_bridge_length_mm) while(sj(Z) > pillar.endpoint(Z) && ej(Z) > nextpillar.endpoint(Z)) @@ -1222,7 +1225,7 @@ bool SLASupportTree::generate(const PointSet &points, Result& result) { const double hbr = cfg.head_back_radius_mm; - const double pradius = cfg.pillar_radius_mm; + const double pradius = cfg.head_back_radius_mm; const double maxbridgelen = cfg.max_bridge_length_mm; const double gndlvl = result.ground_level; @@ -1475,7 +1478,7 @@ bool SLASupportTree::generate(const PointSet &points, result.add_pillar(idx, Vec3d{headend(X), headend(Y), headend(Z) - gh + hl}, - cfg.pillar_radius_mm + cfg.head_back_radius_mm ).base = base_head.mesh; } }; @@ -1490,7 +1493,7 @@ bool SLASupportTree::generate(const PointSet &points, // For now we will just generate smaller headless sticks with a sharp // ending point that connects to the mesh surface. - const double R = 0.5*cfg.pillar_radius_mm; + const double R = cfg.headless_pillar_radius_mm; const double HWIDTH_MM = R/3; // We will sink the pins into the model surface for a distance of 1/3 of @@ -1619,10 +1622,7 @@ bool SLASupportTree::generate(const PointSet &points, return pc == ABORT; } -SLASupportTree::SLASupportTree(): m_impl(new Impl()) -{ - -} +SLASupportTree::SLASupportTree(): m_impl(new Impl()) {} const TriangleMesh &SLASupportTree::merged_mesh() const { diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index a24601de1..9213101f3 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -41,13 +41,16 @@ struct SupportConfig { // Width in mm from the back sphere center to the front sphere center. double head_width_mm = 1.0; - // Radius in mm of the support pillars. - // Warning: this value will be at most 65% of head_back_radius_mm - // TODO: This parameter is invalid. The pillar radius will be dynamic in - // nature. Merged pillars will have an increased thickness. This parameter - // may serve as the maximum radius, or maybe an increase when two are merged - // The default radius will be derived from head_back_radius_mm - double pillar_radius_mm = 0.8; + // Radius in mm of the support pillars. The actual radius of the pillars + // beginning with a head will not be higher than head_back_radius but the + // headless pillars will have half of this value. + double headless_pillar_radius_mm = 0.4; + + // TODO: unimplemented at the moment. This coefficient will have an impact + // when bridges and pillars are merged. The resulting pillar should be a bit + // thicker than the ones merging into it. How much thicker? I don't know + // but it will be derived from this value. + double pillar_widening_factor = 0.5; // Radius in mm of the pillar base. double base_radius_mm = 2.0; diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index 42799ffd0..ef00d8d86 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -84,6 +84,7 @@ size_t SpatIndex::size() const } PointSet normals(const PointSet& points, const EigenMesh3D& mesh) { + if(points.rows() == 0 || mesh.V.rows() == 0 || mesh.F.rows() == 0) return {}; #ifdef IGL_COMPATIBLE Eigen::VectorXd dists; Eigen::VectorXi I; @@ -108,7 +109,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& mesh) { } return ret; -#else +#else // TODO: do something on 32 bit windows return {}; #endif } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index cc6926a66..7c0ab2529 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -458,13 +458,16 @@ void SLAPrint::process() SLAPrintObjectConfig& c = po.m_config; scfg.head_front_radius_mm = c.support_head_front_radius.getFloat(); - scfg.head_back_radius_mm = c.support_head_back_radius.getFloat(); + scfg.head_back_radius_mm = c.support_pillar_radius.getFloat(); scfg.head_penetration_mm = c.support_head_penetration.getFloat(); scfg.head_width_mm = c.support_head_width.getFloat(); scfg.object_elevation_mm = c.support_object_elevation.getFloat(); scfg.tilt = c.support_critical_angle.getFloat() * PI / 180.0 ; scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat(); - scfg.pillar_radius_mm = c.support_pillar_radius.getFloat(); + scfg.headless_pillar_radius_mm = 0.75*c.support_pillar_radius.getFloat(); + scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat(); + scfg.base_radius_mm = c.support_base_radius.getFloat(); + scfg.base_height_mm = c.support_base_height.getFloat(); sla::Controller ctl; @@ -521,11 +524,6 @@ void SLAPrint::process() if(elevation < pad_h) sla::base_plate(trmesh, bp, float(pad_h), float(lh)); - std::cout << "Mesh is empty: " << trmesh.empty() << std::endl; - std::cout << "Pad height: " << pad_h << std::endl; - std::cout << "Elevation " << elevation << std::endl; - std::cout << "Pad plate vertices: " << bp.size() << std::endl; - po.m_supportdata->support_tree_ptr->add_pad(bp, wt, h, md, er); } }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 122368fdd..485615448 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1320,10 +1320,12 @@ void GLCanvas3D::Selection::add_all() return; m_mode = Instance; + clear(); for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { - _add_volume(i); + if (!(*m_volumes)[i]->is_wipe_tower) + _add_volume(i); } _update_type(); @@ -1399,6 +1401,12 @@ bool GLCanvas3D::Selection::is_single_full_instance() const return false; } +bool GLCanvas3D::Selection::is_from_single_object() const +{ + int idx = get_object_idx(); + return (0 <= idx) && (idx < 1000); +} + int GLCanvas3D::Selection::get_object_idx() const { return (m_cache.content.size() == 1) ? m_cache.content.begin()->first : -1; @@ -1455,7 +1463,7 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) (*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement); else if (m_mode == Volume) { - Vec3d local_displacement = (m_cache.volumes_data[i].get_instance_rotation_matrix() * m_cache.volumes_data[i].get_volume_rotation_matrix()).inverse() * displacement; + Vec3d local_displacement = m_cache.volumes_data[i].get_instance_rotation_matrix().inverse() * displacement; (*m_volumes)[i]->set_volume_offset(m_cache.volumes_data[i].get_volume_position() + local_displacement); } #else @@ -1924,9 +1932,17 @@ void GLCanvas3D::Selection::_update_type() unsigned int volumes_count = (unsigned int)model_object->volumes.size(); unsigned int instances_count = (unsigned int)model_object->instances.size(); if (volumes_count * instances_count == 1) + { m_type = SingleFullObject; + // ensures the correct mode is selected + m_mode = Instance; + } else if (volumes_count == 1) // instances_count > 1 + { m_type = SingleFullInstance; + // ensures the correct mode is selected + m_mode = Instance; + } else { m_type = SingleVolume; @@ -1950,11 +1966,19 @@ void GLCanvas3D::Selection::_update_type() unsigned int instances_count = (unsigned int)model_object->instances.size(); unsigned int selected_instances_count = (unsigned int)m_cache.content.begin()->second.size(); if (volumes_count * instances_count == (unsigned int)m_list.size()) + { m_type = SingleFullObject; + // ensures the correct mode is selected + m_mode = Instance; + } else if (selected_instances_count == 1) { if (volumes_count == (unsigned int)m_list.size()) + { m_type = SingleFullInstance; + // ensures the correct mode is selected + m_mode = Instance; + } else { unsigned int modifiers_count = 0; @@ -1977,7 +2001,11 @@ void GLCanvas3D::Selection::_update_type() } } else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) + { m_type = MultipleFullInstance; + // ensures the correct mode is selected + m_mode = Instance; + } } else { @@ -1990,7 +2018,11 @@ void GLCanvas3D::Selection::_update_type() sels_cntr += volumes_count * instances_count; } if (sels_cntr == (unsigned int)m_list.size()) + { m_type = MultipleFullObject; + // ensures the correct mode is selected + m_mode = Instance; + } } } } @@ -2002,66 +2034,84 @@ void GLCanvas3D::Selection::_update_type() v->disabled = requires_disable ? (v->object_idx() != object_idx) || (v->instance_idx() != instance_idx) : false; } + std::cout << "Selection: "; + std::cout << "mode: "; + switch (m_mode) + { + case Volume: + { + std::cout << "Volume"; + break; + } + case Instance: + { + std::cout << "Instance"; + break; + } + } + + std::cout << " - type: "; + switch (m_type) { case Invalid: { - std::cout << "selection type: Invalid" << std::endl; + std::cout << "Invalid" << std::endl; break; } case Empty: { - std::cout << "selection type: Empty" << std::endl; + std::cout << "Empty" << std::endl; break; } case WipeTower: { - std::cout << "selection type: WipeTower" << std::endl; + std::cout << "WipeTower" << std::endl; break; } case SingleModifier: { - std::cout << "selection type: SingleModifier" << std::endl; + std::cout << "SingleModifier" << std::endl; break; } case MultipleModifier: { - std::cout << "selection type: MultipleModifier" << std::endl; + std::cout << "MultipleModifier" << std::endl; break; } case SingleVolume: { - std::cout << "selection type: SingleVolume" << std::endl; + std::cout << "SingleVolume" << std::endl; break; } case MultipleVolume: { - std::cout << "selection type: MultipleVolume" << std::endl; + std::cout << "MultipleVolume" << std::endl; break; } case SingleFullObject: { - std::cout << "selection type: SingleFullObject" << std::endl; + std::cout << "SingleFullObject" << std::endl; break; } case MultipleFullObject: { - std::cout << "selection type: MultipleFullObject" << std::endl; + std::cout << "MultipleFullObject" << std::endl; break; } case SingleFullInstance: { - std::cout << "selection type: SingleFullInstance" << std::endl; + std::cout << "SingleFullInstance" << std::endl; break; } case MultipleFullInstance: { - std::cout << "selection type: MultipleFullInstance" << std::endl; + std::cout << "MultipleFullInstance" << std::endl; break; } case Mixed: { - std::cout << "selection type: Mixed" << std::endl; + std::cout << "Mixed" << std::endl; break; } } @@ -3943,7 +3993,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re int extruder_id = mvs->model_volume->extruder_id(); if (extruder_id != -1) volume->extruder_id = extruder_id; - } + + // updates volumes transformations + volume->set_instance_transformation(mvs->model_volume->get_object()->instances[volume->instance_idx()]->get_transformation()); + volume->set_volume_transformation(mvs->model_volume->get_transformation()); + } } } } @@ -4016,6 +4070,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re size_t idx = 0; const SLAPrint *sla_print = this->sla_print(); for (const SLAPrintObject *print_object : sla_print->objects()) { + std::cout << "Current elevation: "<< print_object->get_current_elevation() << std::endl; SLASupportState &state = sla_support_state[idx ++]; const ModelObject *model_object = print_object->model_object(); // Find an index of the ModelObject diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 9b38de311..1370d166b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -502,7 +502,7 @@ public: bool is_multiple_volume() const { return m_type == MultipleVolume; } bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } - bool is_from_single_object() const { return get_object_idx() != -1; } + bool is_from_single_object() const; bool contains_volume(unsigned int volume_idx) const { return std::find(m_list.begin(), m_list.end(), volume_idx) != m_list.end(); } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1cce8b06a..c5bab3b20 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -333,7 +333,7 @@ void ObjectList::key_event(wxKeyEvent& event) printf("WXK_BACK\n"); remove(); } - else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL)) + else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) select_item_all_children(); else event.Skip(); @@ -1230,7 +1230,8 @@ void ObjectList::delete_from_model_and_list(const std::vector& it m_objects_model->Delete(m_objects_model->GetItemById(item->obj_idx)); } else { - del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type); + if (!del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type)) + continue; if (item->type&itVolume) { m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item->obj_idx, item->sub_obj_idx)); @@ -1305,7 +1306,7 @@ void ObjectList::remove() for (auto& item : sels) { if (m_objects_model->GetParent(item) == wxDataViewItem(0)) - wxGetApp().plater()->remove(m_objects_model->GetIdByItem(item)); + delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1); else del_subobject_item(item); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index c67ac089c..3a8df4111 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -6,6 +6,7 @@ #include "GUI_ObjectSettings.hpp" #include "GLCanvas3D.hpp" +class wxStaticText; namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ffb6fd246..88d8c3202 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2200,7 +2200,7 @@ bool Plater::priv::init_object_menu() wxMenuItem* item_split = append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "shape_ungroup.png"); // Add the automatic rotation sub-menu - item_sla_autorot = append_menu_item(&object_menu, wxID_ANY, _(L("Optimize orientation\t+")), _(L("Optimize the rotation of the object for better print results.")), + item_sla_autorot = append_menu_item(&object_menu, wxID_ANY, _(L("Optimize orientation")), _(L("Optimize the rotation of the object for better print results.")), [this](wxCommandEvent&) { sla_optimize_rotation(); }); if(printer_technology == ptFFF) item_sla_autorot = object_menu.Remove(item_sla_autorot); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 96191e0ff..240cfea26 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -405,9 +405,9 @@ const std::vector& Preset::sla_print_options() "supports_enable", "support_head_front_radius", "support_head_penetration", - "support_head_back_radius", "support_head_width", "support_pillar_radius", + "support_pillar_widening_factor", "support_base_radius", "support_base_height", "support_critical_angle", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 7258ce003..bed0a42d9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3002,12 +3002,12 @@ void TabSLAPrint::build() optgroup = page->new_optgroup(_(L("Support head"))); optgroup->append_single_option_line("support_head_front_radius"); - optgroup->append_single_option_line("support_head_back_radius"); optgroup->append_single_option_line("support_head_penetration"); optgroup->append_single_option_line("support_head_width"); optgroup = page->new_optgroup(_(L("Support pillar"))); optgroup->append_single_option_line("support_pillar_radius"); + optgroup->append_single_option_line("support_pillar_widening_factor"); optgroup->append_single_option_line("support_base_radius"); optgroup->append_single_option_line("support_base_height"); optgroup->append_single_option_line("support_object_elevation"); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index b80976e65..dc17bed6b 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -410,6 +410,8 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vectorfind(m_name.ToStdString()); if (bmp == nullptr) {