Cut WIP:
* Suppress to split cut objects * ObjectList: * Use another icons to mark the cut objects and connectors * For the cut object show parts, which are not connectors * Set different colors for the Plugs and Dowels * CutGizmo: * Invalidate CutGizmo after changes in ObjectList or perform a cut * CupPlane in Connectors mode: Unselect selection, when click on empty space * Connectors mode: Fixed performance issue
This commit is contained in:
parent
e689be65db
commit
0201a5055a
26
resources/icons/cut_connectors.svg
Normal file
26
resources/icons/cut_connectors.svg
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||
<g id="add_x5F_part">
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M14.62,4.37c-0.01-0.14,0.06-0.34,0.15-0.44l0.13-0.15c0.09-0.11,0.12-0.3,0.07-0.43l-0.2-0.49
|
||||
c-0.05-0.13-0.21-0.24-0.35-0.25l-0.2-0.01c-0.14-0.01-0.33-0.1-0.42-0.21c-0.09-0.1-0.37-0.46-0.38-0.6l-0.01-0.2
|
||||
c-0.01-0.14-0.12-0.3-0.25-0.35l-0.49-0.2C12.52,0.97,12.33,1,12.22,1.1l-0.15,0.13c-0.11,0.09-0.31,0.16-0.44,0.15
|
||||
c-0.14-0.01-0.59-0.06-0.69-0.15L10.78,1.1c-0.11-0.09-0.3-0.12-0.43-0.07l-0.49,0.2C9.73,1.28,9.61,1.44,9.6,1.58l-0.01,0.2
|
||||
C9.58,1.92,9.49,2.11,9.38,2.2c-0.1,0.09-0.46,0.37-0.6,0.38L8.58,2.6c-0.14,0.01-0.3,0.12-0.35,0.25l-0.2,0.49
|
||||
C7.97,3.48,8,3.67,8.1,3.78l0.13,0.15c0.09,0.11,0.16,0.31,0.15,0.44C8.37,4.52,8.32,4.96,8.23,5.07L8.1,5.22
|
||||
C8,5.33,7.97,5.52,8.03,5.65l0.2,0.49C8.28,6.27,8.44,6.39,8.58,6.4l0.2,0.01c0.14,0.01,0.33,0.1,0.42,0.21
|
||||
c0.09,0.1,0.37,0.46,0.38,0.6l0.01,0.2c0.01,0.14,0.12,0.3,0.25,0.35l0.49,0.2C10.48,8.03,10.67,8,10.78,7.9l0.15-0.13
|
||||
c0.11-0.09,0.31-0.16,0.44-0.15c0.14,0.01,0.59,0.06,0.69,0.15l0.15,0.13c0.11,0.09,0.3,0.12,0.43,0.07l0.49-0.2
|
||||
c0.13-0.05,0.24-0.21,0.25-0.35l0.01-0.2c0.01-0.14,0.1-0.33,0.21-0.42s0.46-0.37,0.6-0.38l0.2-0.01c0.14-0.01,0.3-0.12,0.35-0.25
|
||||
l0.2-0.49C15.03,5.52,15,5.33,14.9,5.22l-0.13-0.15C14.68,4.96,14.63,4.51,14.62,4.37z M11.5,6.6c-1.16,0-2.1-0.94-2.1-2.1
|
||||
s0.94-2.1,2.1-2.1s2.1,0.94,2.1,2.1S12.66,6.6,11.5,6.6z"/>
|
||||
</g>
|
||||
<path fill="#808080" d="M10.98,9.78c-0.29,0-0.52,0.23-0.52,0.52v2.09v1.04c0,0.29-0.23,0.52-0.52,0.52H2.62
|
||||
c-0.29,0-0.53-0.24-0.53-0.53L2.04,6.12c0-0.14,0.05-0.27,0.15-0.37c0.1-0.1,0.23-0.15,0.37-0.15l3.19,0v0
|
||||
c0.29,0,0.52-0.23,0.52-0.52S6.04,4.55,5.75,4.55H3.66c-0.01,0-0.01,0-0.02,0l-1.08,0c-0.42,0-0.81,0.16-1.11,0.46
|
||||
C1.16,5.31,1,5.71,1,6.13l0.04,7.31C1.05,14.3,1.75,15,2.62,15h7.31c0.86,0,1.57-0.7,1.57-1.57v-1.04V10.3
|
||||
C11.5,10.01,11.27,9.78,10.98,9.78z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -1191,11 +1191,21 @@ size_t ModelObject::parts_count() const
|
||||
return num;
|
||||
}
|
||||
|
||||
bool ModelObject::has_connectors() const
|
||||
{
|
||||
assert(is_cut());
|
||||
for (const ModelVolume* v : this->volumes)
|
||||
if (v->cut_info.is_connector)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
indexed_triangle_set ModelObject::get_connector_mesh(CutConnectorAttributes connector_attributes)
|
||||
{
|
||||
indexed_triangle_set connector_mesh;
|
||||
|
||||
int sectorCount;
|
||||
int sectorCount {1};
|
||||
switch (CutConnectorShape(connector_attributes.shape)) {
|
||||
case CutConnectorShape::Triangle:
|
||||
sectorCount = 3;
|
||||
@ -1238,7 +1248,7 @@ void ModelObject::apply_cut_connectors(const std::string& new_name)
|
||||
new_volume->set_transformation(assemble_transform(connector.pos) * connector.rotation_m *
|
||||
scale_transform(Vec3f(connector.radius, connector.radius, connector.height).cast<double>()));
|
||||
|
||||
new_volume->cut_info = { true, connector.attribs.type, connector.radius_tolerance, connector.height_tolerance };
|
||||
new_volume->cut_info = { connector.attribs.type, connector.radius_tolerance, connector.height_tolerance };
|
||||
new_volume->name = new_name + "-" + std::to_string(++connector_id);
|
||||
}
|
||||
cut_id.increase_connectors_cnt(cut_connectors.size());
|
||||
@ -1298,7 +1308,8 @@ void ModelVolume::reset_extra_facets()
|
||||
|
||||
void ModelVolume::apply_tolerance()
|
||||
{
|
||||
if (!cut_info.is_connector)
|
||||
assert(cut_info.is_connector);
|
||||
if (cut_info.is_processed)
|
||||
return;
|
||||
|
||||
Vec3d sf = get_scaling_factor();
|
||||
@ -1321,7 +1332,8 @@ void ModelVolume::apply_tolerance()
|
||||
void ModelObject::process_connector_cut(ModelVolume* volume, ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower,
|
||||
std::vector<ModelObject*>& dowels, Vec3d& local_dowels_displace)
|
||||
{
|
||||
volume->cut_info.discard();
|
||||
assert(volume->cut_info.is_connector);
|
||||
volume->cut_info.set_processed();
|
||||
|
||||
const auto volume_matrix = volume->get_matrix();
|
||||
|
||||
@ -1546,10 +1558,10 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
||||
volume->reset_extra_facets();
|
||||
|
||||
if (!volume->is_model_part()) {
|
||||
if (volume->cut_info.is_connector)
|
||||
process_connector_cut(volume, attributes, upper, lower, dowels, local_dowels_displace);
|
||||
else
|
||||
if (volume->cut_info.is_processed)
|
||||
process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, attributes, upper, lower);
|
||||
else
|
||||
process_connector_cut(volume, attributes, upper, lower, dowels, local_dowels_displace);
|
||||
}
|
||||
else if (!volume->mesh().empty())
|
||||
process_solid_part_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, local_displace);
|
||||
|
@ -477,6 +477,7 @@ public:
|
||||
int get_repaired_errors_count(const int vol_idx = -1) const;
|
||||
|
||||
bool is_cut() const { return cut_id.id().valid(); }
|
||||
bool has_connectors() const;
|
||||
|
||||
private:
|
||||
friend class Model;
|
||||
@ -723,14 +724,26 @@ public:
|
||||
struct CutInfo
|
||||
{
|
||||
bool is_connector{ false };
|
||||
bool is_processed{ true };
|
||||
CutConnectorType connector_type{ CutConnectorType::Plug };
|
||||
float radius_tolerance;// [0.f : 1.f]
|
||||
float height_tolerance;// [0.f : 1.f]
|
||||
float radius_tolerance{ 0.f };// [0.f : 1.f]
|
||||
float height_tolerance{ 0.f };// [0.f : 1.f]
|
||||
|
||||
void discard() { is_connector = false; }
|
||||
CutInfo() = default;
|
||||
CutInfo(CutConnectorType type, float rad_tolerance, float h_tolerance) :
|
||||
is_connector(true),
|
||||
is_processed(false),
|
||||
connector_type(type),
|
||||
radius_tolerance(rad_tolerance),
|
||||
height_tolerance(h_tolerance)
|
||||
{}
|
||||
|
||||
void set_processed() { is_processed = true; }
|
||||
};
|
||||
CutInfo cut_info;
|
||||
|
||||
bool is_cut_connector() const { return cut_info.is_processed && cut_info.is_connector; }
|
||||
|
||||
// The triangular model.
|
||||
const TriangleMesh& mesh() const { return *m_mesh.get(); }
|
||||
#if ENABLE_RAYCAST_PICKING
|
||||
|
@ -1881,13 +1881,8 @@ void ObjectList::del_info_item(const int obj_idx, InfoItemType type)
|
||||
mv->seam_facets.reset();
|
||||
break;
|
||||
|
||||
case InfoItemType::Cut:
|
||||
if (0) { // #ysFIXME_Cut
|
||||
cnv->get_gizmos_manager().reset_all_states();
|
||||
Plater::TakeSnapshot(plater, _L("Remove cut connectors"));
|
||||
(*m_objects)[obj_idx]->cut_connectors.clear();
|
||||
} else
|
||||
Slic3r::GUI::show_error(nullptr, _L("Connectors cannot be deleted from cut object."));
|
||||
case InfoItemType::CutConnectors:
|
||||
show_error(nullptr, _L("Connectors cannot be deleted from cut object."));
|
||||
break;
|
||||
|
||||
case InfoItemType::MmuSegmentation:
|
||||
@ -2422,9 +2417,12 @@ bool ObjectList::is_splittable(bool to_objects)
|
||||
auto obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0)
|
||||
return false;
|
||||
if ((*m_objects)[obj_idx]->volumes.size() > 1)
|
||||
const ModelObject* object = (*m_objects)[obj_idx];
|
||||
if (object->is_cut())
|
||||
return false;
|
||||
if (object->volumes.size() > 1)
|
||||
return true;
|
||||
return (*m_objects)[obj_idx]->volumes[0]->is_splittable();
|
||||
return object->volumes[0]->is_splittable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2595,19 +2593,13 @@ void ObjectList::part_selection_changed()
|
||||
}
|
||||
case InfoItemType::CustomSupports:
|
||||
case InfoItemType::CustomSeam:
|
||||
// case InfoItemType::Cut:
|
||||
case InfoItemType::MmuSegmentation:
|
||||
{
|
||||
GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports :
|
||||
info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam :
|
||||
info_type == InfoItemType::Cut ? GLGizmosManager::EType::Cut :
|
||||
GLGizmosManager::EType::MmuSegmentation;
|
||||
if (gizmos_mgr.get_current_type() != gizmo_type)
|
||||
gizmos_mgr.open_gizmo(gizmo_type);
|
||||
if (info_type == InfoItemType::Cut) {
|
||||
GLGizmoCut3D* cut = dynamic_cast<GLGizmoCut3D*>(gizmos_mgr.get_current());
|
||||
cut->set_connectors_editing();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InfoItemType::Sinking: { break; }
|
||||
@ -2762,7 +2754,7 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio
|
||||
|
||||
for (InfoItemType type : {InfoItemType::CustomSupports,
|
||||
InfoItemType::CustomSeam,
|
||||
InfoItemType::Cut,
|
||||
InfoItemType::CutConnectors,
|
||||
InfoItemType::MmuSegmentation,
|
||||
InfoItemType::Sinking,
|
||||
InfoItemType::VariableLayerHeight}) {
|
||||
@ -2783,11 +2775,8 @@ void ObjectList::update_info_items(size_t obj_idx, wxDataViewItemArray* selectio
|
||||
});
|
||||
break;
|
||||
|
||||
case InfoItemType::Cut :
|
||||
if (0) // #ysFIXME_Cut
|
||||
should_show = !model_object->cut_connectors.empty();
|
||||
else
|
||||
should_show = model_object->is_cut() && model_object->volumes.size() > 1;
|
||||
case InfoItemType::CutConnectors:
|
||||
should_show = model_object->is_cut() && model_object->has_connectors() && model_object->volumes.size() > 1;
|
||||
break;
|
||||
case InfoItemType::VariableLayerHeight :
|
||||
should_show = printer_technology() == ptFFF
|
||||
@ -2841,9 +2830,20 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
||||
|
||||
update_info_items(obj_idx, nullptr, call_selection_changed);
|
||||
|
||||
bool can_add_volumes = model_object->volumes.size() > 1;
|
||||
if (can_add_volumes && model_object->is_cut()) {
|
||||
int no_connectors_cnt = 0;
|
||||
for (const ModelVolume* v : model_object->volumes)
|
||||
if (!v->is_cut_connector())
|
||||
no_connectors_cnt++;
|
||||
can_add_volumes = no_connectors_cnt > 1;
|
||||
}
|
||||
|
||||
// add volumes to the object
|
||||
if (model_object->volumes.size() > 1 && !model_object->is_cut()) {
|
||||
if (can_add_volumes) {
|
||||
for (const ModelVolume* volume : model_object->volumes) {
|
||||
if (model_object->is_cut() && volume->is_cut_connector())
|
||||
continue;
|
||||
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(item,
|
||||
from_u8(volume->name),
|
||||
volume->type(),
|
||||
|
@ -18,9 +18,17 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
static const double Margin = 20.0;
|
||||
static const ColorRGBA GRABBER_COLOR = ColorRGBA::YELLOW();
|
||||
|
||||
// connector colors
|
||||
static const ColorRGBA PLAG_COLOR = ColorRGBA::YELLOW();
|
||||
static const ColorRGBA DOWEL_COLOR = ColorRGBA::DARK_YELLOW();
|
||||
static const ColorRGBA HOVERED_PLAG_COLOR = ColorRGBA::CYAN();
|
||||
static const ColorRGBA HOVERED_DOWEL_COLOR = ColorRGBA(0.0f, 0.5f, 0.5f, 1.0f);
|
||||
static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY();
|
||||
static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::DARK_GRAY();
|
||||
static const ColorRGBA CONNECTOR_DEF_COLOR = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
|
||||
const unsigned int AngleResolution = 64;
|
||||
const unsigned int ScaleStepsCount = 72;
|
||||
const float ScaleStepRad = 2.0f * float(PI) / ScaleStepsCount;
|
||||
@ -1426,8 +1434,6 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors)
|
||||
unselect_all_connectors();
|
||||
set_connectors_editing(false);
|
||||
}
|
||||
|
||||
m_parent.request_extra_frame();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_build_size()
|
||||
@ -1455,10 +1461,22 @@ void GLGizmoCut3D::reset_cut_plane()
|
||||
update_clipper();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::invalidate_cut_plane()
|
||||
{
|
||||
m_rotation_m = Transform3d::Identity();
|
||||
m_plane_center = Vec3d::Zero();
|
||||
m_min_pos = Vec3d::Zero();
|
||||
m_max_pos = Vec3d::Zero();
|
||||
m_bb_center = Vec3d::Zero();
|
||||
m_center_offset = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::set_connectors_editing(bool connectors_editing)
|
||||
{
|
||||
m_connectors_editing = connectors_editing;
|
||||
update_raycasters_for_picking();
|
||||
|
||||
m_parent.request_extra_frame();
|
||||
}
|
||||
|
||||
void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
|
||||
@ -1661,13 +1679,14 @@ void GLGizmoCut3D::render_connectors()
|
||||
pos[Z] += sla_shift;
|
||||
|
||||
// First decide about the color of the point.
|
||||
if (size_t(m_hover_id- m_connectors_group_id) == i)
|
||||
render_color = ColorRGBA::CYAN();
|
||||
if (!m_connectors_editing)
|
||||
render_color = CONNECTOR_DEF_COLOR;
|
||||
else if (size_t(m_hover_id - m_connectors_group_id) == i)
|
||||
render_color = connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR;
|
||||
else if (m_selected[i])
|
||||
render_color = ColorRGBA::DARK_GRAY();
|
||||
render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR;
|
||||
else // neither hover nor picking
|
||||
render_color = m_connectors_editing ? ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f) : ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f);
|
||||
|
||||
render_color = connector.attribs.type == CutConnectorType::Dowel ? DOWEL_COLOR : PLAG_COLOR;
|
||||
// ! #ysFIXME rework get_volume_transformation
|
||||
if (0) { // else { // neither hover nor picking
|
||||
int mesh_id = -1;
|
||||
@ -1773,6 +1792,8 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
||||
else {
|
||||
// the object is SLA-elevated and the plane is under it.
|
||||
}
|
||||
|
||||
invalidate_cut_plane();
|
||||
}
|
||||
|
||||
|
||||
@ -2005,7 +2026,8 @@ bool GLGizmoCut3D::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_posi
|
||||
if (action == SLAGizmoEventType::LeftDown && !shift_down) {
|
||||
// If there is no selection and no hovering, add new point
|
||||
if (m_hover_id == -1 && !control_down && !alt_down)
|
||||
return add_connector(connectors, mouse_position);
|
||||
if (!add_connector(connectors, mouse_position))
|
||||
unselect_all_connectors();
|
||||
return true;
|
||||
}
|
||||
if (!m_connectors_editing)
|
||||
|
@ -149,6 +149,7 @@ public:
|
||||
void update_clipper();
|
||||
void update_clipper_on_render();
|
||||
void set_connectors_editing() { m_connectors_editing = true; }
|
||||
void invalidate_cut_plane();
|
||||
|
||||
BoundingBoxf3 bounding_box() const;
|
||||
BoundingBoxf3 transformed_bounding_box(bool revert_move = false) const;
|
||||
|
@ -1228,7 +1228,7 @@ void NotificationManager::UpdatedItemsInfoNotification::add_type(InfoItemType ty
|
||||
case InfoItemType::MmuSegmentation: text += format(_L_PLURAL("%1$d object was loaded with multimaterial painting.", "%1$d objects were loaded with multimaterial painting.",(*it).second), (*it).second) + "\n"; break;
|
||||
case InfoItemType::VariableLayerHeight: text += format(_L_PLURAL("%1$d object was loaded with variable layer height.", "%1$d objects were loaded with variable layer height.", (*it).second), (*it).second) + "\n"; break;
|
||||
case InfoItemType::Sinking: text += format(_L_PLURAL("%1$d object was loaded with partial sinking.", "%1$d objects were loaded with partial sinking.", (*it).second), (*it).second) + "\n"; break;
|
||||
case InfoItemType::Cut: text += format(_L_PLURAL("%1$d object was loaded as a part of cut object.", "%1$d objects were loaded as parts of cut object", (*it).second), (*it).second) + "\n"; break;
|
||||
case InfoItemType::CutConnectors: text += format(_L_PLURAL("%1$d object was loaded as a part of cut object.", "%1$d objects were loaded as parts of cut object", (*it).second), (*it).second) + "\n"; break;
|
||||
default: BOOST_LOG_TRIVIAL(error) << "Unknown InfoItemType: " << (*it).second; break;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ static constexpr char LayerRootIcon[] = "edit_layers_all";
|
||||
static constexpr char LayerIcon[] = "edit_layers_some";
|
||||
static constexpr char WarningIcon[] = "exclamation";
|
||||
static constexpr char WarningManifoldIcon[] = "exclamation_manifold";
|
||||
static constexpr char LockIcon[] = "lock_closed";
|
||||
static constexpr char LockIcon[] = "cut_";
|
||||
|
||||
struct InfoItemAtributes {
|
||||
std::string name;
|
||||
@ -49,7 +49,7 @@ const std::map<InfoItemType, InfoItemAtributes> INFO_ITEMS{
|
||||
// info_item Type info_item Name info_item BitmapName
|
||||
{ InfoItemType::CustomSupports, {L("Paint-on supports"), "fdm_supports_" }, },
|
||||
{ InfoItemType::CustomSeam, {L("Paint-on seam"), "seam_" }, },
|
||||
{ InfoItemType::Cut, {L("Cut connectors"), "cut_" }, },
|
||||
{ InfoItemType::CutConnectors, {L("Cut connectors"), "cut_connectors" }, },
|
||||
{ InfoItemType::MmuSegmentation, {L("Multimaterial painting"), "mmu_segmentation_"}, },
|
||||
{ InfoItemType::Sinking, {L("Sinking"), "sinking"}, },
|
||||
{ InfoItemType::VariableLayerHeight, {L("Variable layer height"), "layers"}, },
|
||||
|
@ -51,7 +51,7 @@ enum class InfoItemType
|
||||
Undef,
|
||||
CustomSupports,
|
||||
CustomSeam,
|
||||
Cut,
|
||||
CutConnectors,
|
||||
MmuSegmentation,
|
||||
Sinking,
|
||||
VariableLayerHeight
|
||||
|
@ -97,6 +97,7 @@
|
||||
#include "MsgDialog.hpp"
|
||||
#include "ProjectDirtyStateManager.hpp"
|
||||
#include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification
|
||||
#include "Gizmos/GLGizmoCut.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "Gizmos/GLGizmosManager.hpp"
|
||||
@ -2980,6 +2981,9 @@ void Plater::priv::object_list_changed()
|
||||
const bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() == ModelInstancePVS_Inside;
|
||||
|
||||
sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits);
|
||||
|
||||
// invalidate CutGizmo after changes in ObjectList
|
||||
static_cast<GLGizmoCut3D*>(q->canvas3D()->get_gizmos_manager().get_gizmo(GLGizmosManager::Cut))->invalidate_cut_plane();
|
||||
}
|
||||
|
||||
void Plater::priv::select_all()
|
||||
|
Loading…
Reference in New Issue
Block a user