mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-23 14:44:19 -06:00
ENH: recover CutToParts for cut
Change-Id: I5d7fb089c5d2ea9d36fce3d70ec4da896d601940 (cherry picked from commit e0232b21ebf5a37bedee1c213d1c21890634c563)
This commit is contained in:
parent
b1041a5de8
commit
518cd4ce27
4 changed files with 174 additions and 164 deletions
|
@ -916,6 +916,25 @@ bool Model::is_mm_painted() const
|
|||
return std::any_of(this->objects.cbegin(), this->objects.cend(), [](const ModelObject *mo) { return mo->is_mm_painted(); });
|
||||
}
|
||||
|
||||
|
||||
static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix, const std::string& suffix = {}, ModelVolumeType type = ModelVolumeType::MODEL_PART)
|
||||
{
|
||||
if (mesh.empty())
|
||||
return;
|
||||
|
||||
mesh.transform(cut_matrix);
|
||||
ModelVolume* vol = object->add_volume(mesh);
|
||||
vol->set_type(type);
|
||||
|
||||
vol->name = src_volume->name + suffix;
|
||||
// Don't copy the config's ID.
|
||||
vol->config.assign_config(src_volume->config);
|
||||
assert(vol->config.id().valid());
|
||||
assert(vol->config.id() != src_volume->config.id());
|
||||
vol->set_material(src_volume->material_id(), *src_volume->material());
|
||||
vol->cut_info = src_volume->cut_info;
|
||||
}
|
||||
|
||||
ModelObject::~ModelObject()
|
||||
{
|
||||
this->clear_volumes();
|
||||
|
@ -1706,7 +1725,9 @@ void ModelObject::synchronize_model_after_cut()
|
|||
void ModelObject::apply_cut_attributes(ModelObjectCutAttributes attributes)
|
||||
{
|
||||
// we don't save cut information, if result will not contains all parts of initial object
|
||||
if (!attributes.has(ModelObjectCutAttribute::KeepUpper) || !attributes.has(ModelObjectCutAttribute::KeepLower))
|
||||
if (!attributes.has(ModelObjectCutAttribute::KeepUpper) ||
|
||||
!attributes.has(ModelObjectCutAttribute::KeepLower) ||
|
||||
attributes.has(ModelObjectCutAttribute::InvalidateCutInfo))
|
||||
return;
|
||||
|
||||
if (cut_id.id().invalid())
|
||||
|
@ -1768,6 +1789,8 @@ Transform3d ModelObject::calculate_cut_plane_inverse_matrix(const std::array<Vec
|
|||
|
||||
void ModelObject::process_connector_cut(
|
||||
ModelVolume *volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d& cut_matrix,
|
||||
ModelObjectCutAttributes attributes,
|
||||
ModelObject *upper, ModelObject *lower,
|
||||
std::vector<ModelObject *> &dowels,
|
||||
|
@ -1780,6 +1803,7 @@ void ModelObject::process_connector_cut(
|
|||
|
||||
// ! Don't apply instance transformation for the conntectors.
|
||||
// This transformation is already there
|
||||
if (volume->cut_info.connector_type != CutConnectorType::Dowel) {
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper)) {
|
||||
ModelVolume *vol = upper->add_volume(*volume);
|
||||
vol->set_transformation(volume_matrix);
|
||||
|
@ -1788,14 +1812,12 @@ void ModelObject::process_connector_cut(
|
|||
if (attributes.has(ModelObjectCutAttribute::KeepLower)) {
|
||||
ModelVolume *vol = lower->add_volume(*volume);
|
||||
vol->set_transformation(volume_matrix);
|
||||
|
||||
if (volume->cut_info.connector_type == CutConnectorType::Dowel)
|
||||
vol->apply_tolerance();
|
||||
else
|
||||
// for lower part change type of connector from NEGATIVE_VOLUME to MODEL_PART if this connector is a plug
|
||||
vol->set_type(ModelVolumeType::MODEL_PART);
|
||||
}
|
||||
if (volume->cut_info.connector_type == CutConnectorType::Dowel && attributes.has(ModelObjectCutAttribute::CreateDowels)) {
|
||||
}
|
||||
else {
|
||||
if (attributes.has(ModelObjectCutAttribute::CreateDowels)) {
|
||||
ModelObject *dowel{nullptr};
|
||||
// Clone the object to duplicate instances, materials etc.
|
||||
clone_for_cut(&dowel);
|
||||
|
@ -1813,6 +1835,22 @@ void ModelObject::process_connector_cut(
|
|||
|
||||
dowels.push_back(dowel);
|
||||
}
|
||||
|
||||
// Cut the dowel
|
||||
volume->apply_tolerance();
|
||||
|
||||
// Perform cut
|
||||
TriangleMesh upper_mesh, lower_mesh;
|
||||
process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh);
|
||||
|
||||
// add small Z offset to better preview
|
||||
upper_mesh.translate((-0.05 * Vec3d::UnitZ()).cast<float>());
|
||||
lower_mesh.translate((0.05 * Vec3d::UnitZ()).cast<float>());
|
||||
|
||||
// Add cut parts to the related objects
|
||||
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A", volume->type());
|
||||
add_cut_volume(lower_mesh, lower, volume, cut_matrix, "_B", volume->type());
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObject::process_modifier_cut(
|
||||
|
@ -1829,6 +1867,11 @@ void ModelObject::process_modifier_cut(
|
|||
// to the modifier volume transformation to preserve their shape properly.
|
||||
volume->set_transformation(Geometry::Transformation(volume_matrix));
|
||||
|
||||
if (attributes.has(ModelObjectCutAttribute::CutToParts)) {
|
||||
upper->add_volume(*volume);
|
||||
return;
|
||||
}
|
||||
|
||||
// Some logic for the negative volumes/connectors. Add only needed modifiers
|
||||
auto bb = volume->mesh().transformed_bounding_box(inverse_cut_matrix * volume_matrix);
|
||||
bool is_crossed_by_cut = bb.min[Z] <= 0 && bb.max[Z] >= 0;
|
||||
|
@ -1838,52 +1881,59 @@ void ModelObject::process_modifier_cut(
|
|||
lower->add_volume(*volume);
|
||||
}
|
||||
|
||||
void ModelObject::process_volume_cut(ModelVolume * volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d & cut_matrix,
|
||||
ModelObjectCutAttributes attributes,
|
||||
TriangleMesh & upper_mesh,
|
||||
TriangleMesh & lower_mesh)
|
||||
{
|
||||
const auto volume_matrix = volume->get_matrix();
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
const Geometry::Transformation cut_transformation = Geometry::Transformation(cut_matrix);
|
||||
const Transform3d invert_cut_matrix = cut_transformation.get_matrix(true, false, true, true).inverse()
|
||||
* translation_transform(-1 * cut_transformation.get_offset());
|
||||
|
||||
// Transform the mesh by the combined transformation matrix.
|
||||
// Flip the triangles in case the composite transformation is left handed.
|
||||
TriangleMesh mesh(volume->mesh());
|
||||
mesh.transform(invert_cut_matrix * instance_matrix * volume_matrix, true);
|
||||
|
||||
indexed_triangle_set upper_its, lower_its;
|
||||
cut_mesh(mesh.its, 0.0f, &upper_its, &lower_its);
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
|
||||
upper_mesh = TriangleMesh(upper_its);
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepLower))
|
||||
lower_mesh = TriangleMesh(lower_its);
|
||||
}
|
||||
|
||||
void ModelObject::process_solid_part_cut(ModelVolume * volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d & cut_matrix,
|
||||
const std::array<Vec3d, 4> &plane_points,
|
||||
ModelObjectCutAttributes attributes,
|
||||
ModelObject * upper,
|
||||
ModelObject * lower,
|
||||
Vec3d & local_displace)
|
||||
{
|
||||
// Transform the mesh by the combined transformation matrix.
|
||||
// Flip the triangles in case the composite transformation is left handed.
|
||||
TriangleMesh mesh(volume->mesh());
|
||||
mesh.transform(instance_matrix * volume->get_matrix(), true);
|
||||
volume->reset_mesh();
|
||||
// Reset volume transformation except for offset
|
||||
const Vec3d offset = volume->get_offset();
|
||||
volume->set_transformation(Geometry::Transformation());
|
||||
volume->set_offset(offset);
|
||||
|
||||
// Perform cut
|
||||
TriangleMesh upper_mesh, lower_mesh;
|
||||
{
|
||||
indexed_triangle_set upper_its, lower_its;
|
||||
cut_mesh(mesh.its, plane_points, &upper_its, &lower_its);
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper)) upper_mesh = TriangleMesh(upper_its);
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepLower)) lower_mesh = TriangleMesh(lower_its);
|
||||
process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh);
|
||||
|
||||
// Add required cut parts to the objects
|
||||
if (attributes.has(ModelObjectCutAttribute::CutToParts)) {
|
||||
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A");
|
||||
add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && !upper_mesh.empty()) {
|
||||
ModelVolume *vol = upper->add_volume(upper_mesh);
|
||||
vol->name = volume->name.substr(0, volume->name.find_last_of('.')) + "_upper"; // BBS
|
||||
// Don't copy the config's ID.
|
||||
vol->config.assign_config(volume->config);
|
||||
assert(vol->config.id().valid());
|
||||
assert(vol->config.id() != volume->config.id());
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
vol->cut_info = volume->cut_info;
|
||||
}
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
|
||||
add_cut_volume(upper_mesh, upper, volume, cut_matrix);
|
||||
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty()) {
|
||||
ModelVolume *vol = lower->add_volume(lower_mesh);
|
||||
vol->name = volume->name.substr(0, volume->name.find_last_of('.')) + "_lower"; // BBS
|
||||
// Don't copy the config's ID.
|
||||
vol->config.assign_config(volume->config);
|
||||
assert(vol->config.id().valid());
|
||||
assert(vol->config.id() != volume->config.id());
|
||||
vol->set_material(volume->material_id(), *volume->material());
|
||||
vol->cut_info = volume->cut_info;
|
||||
add_cut_volume(lower_mesh, lower, volume, cut_matrix);
|
||||
|
||||
// Compute the displacement (in instance coordinates) to be applied to place the upper parts
|
||||
// The upper part displacement is set to half of the lower part bounding box
|
||||
|
@ -1957,29 +2007,13 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
|
|||
// apply cut attributes for object
|
||||
apply_cut_attributes(attributes);
|
||||
|
||||
// Clone the object to duplicate instances, materials etc.
|
||||
bool keep_upper = attributes.has(ModelObjectCutAttribute::KeepUpper);
|
||||
bool keep_lower = attributes.has(ModelObjectCutAttribute::KeepLower);
|
||||
ModelObject* upper = keep_upper ? ModelObject::new_clone(*this) : nullptr;
|
||||
ModelObject* lower = keep_lower ? ModelObject::new_clone(*this) : nullptr;
|
||||
ModelObject* upper{ nullptr };
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
|
||||
clone_for_cut(&upper);
|
||||
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper)) {
|
||||
upper->set_model(nullptr);
|
||||
upper->sla_support_points.clear();
|
||||
upper->sla_drain_holes.clear();
|
||||
upper->sla_points_status = sla::PointsStatus::NoPoints;
|
||||
upper->clear_volumes();
|
||||
upper->input_file.clear();
|
||||
}
|
||||
|
||||
if (keep_lower && lower != upper) {
|
||||
lower->set_model(nullptr);
|
||||
lower->sla_support_points.clear();
|
||||
lower->sla_drain_holes.clear();
|
||||
lower->sla_points_status = sla::PointsStatus::NoPoints;
|
||||
lower->clear_volumes();
|
||||
lower->input_file.clear();
|
||||
}
|
||||
ModelObject* lower{ nullptr };
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepLower) && !attributes.has(ModelObjectCutAttribute::CutToParts))
|
||||
clone_for_cut(&lower);
|
||||
|
||||
// Because transformations are going to be applied to meshes directly,
|
||||
// we reset transformation of all instances and volumes,
|
||||
|
@ -1999,6 +2033,8 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
|
|||
for (Vec3d& point : plane_points) {
|
||||
point -= instances[instance]->get_offset();
|
||||
}
|
||||
Transform3d inverse_cut_matrix = calculate_cut_plane_inverse_matrix(plane_points);
|
||||
Transform3d cut_matrix = inverse_cut_matrix.inverse();
|
||||
|
||||
std::vector<ModelObject *> dowels;
|
||||
// Displacement (in instance coordinates) to be applied to place the upper parts
|
||||
|
@ -2016,88 +2052,43 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
|
|||
if (volume->cut_info.is_processed) {
|
||||
// Modifiers are not cut, but we still need to add the instance transformation
|
||||
// to the modifier volume transformation to preserve their shape properly.
|
||||
Transform3d inverse_cut_matrix = calculate_cut_plane_inverse_matrix(plane_points);
|
||||
//Transform3d inverse_cut_matrix = calculate_cut_plane_inverse_matrix(plane_points);
|
||||
process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, attributes, upper, lower);
|
||||
}
|
||||
else {
|
||||
process_connector_cut(volume, attributes, upper, lower, dowels, local_dowels_displace);
|
||||
process_connector_cut(volume, instance_matrix, cut_matrix, attributes, upper, lower, dowels, local_dowels_displace);
|
||||
}
|
||||
}
|
||||
else if (! volume->mesh().empty()) {
|
||||
process_solid_part_cut(volume, instance_matrix, plane_points, attributes, upper, lower, local_displace);
|
||||
process_solid_part_cut(volume, instance_matrix, cut_matrix, plane_points, attributes, upper, lower, local_displace);
|
||||
}
|
||||
}
|
||||
|
||||
ModelObjectPtrs res;
|
||||
|
||||
Transform3d cut_matrix = calculate_cut_plane_inverse_matrix(plane_points).inverse();
|
||||
if (attributes.has(ModelObjectCutAttribute::CutToParts) && !upper->volumes.empty()) {
|
||||
reset_instance_transformation(upper, instance, cut_matrix);
|
||||
res.push_back(upper);
|
||||
}
|
||||
else {
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepUpper) && upper->volumes.size() > 0) {
|
||||
invalidate_translations(upper, instances[instance]);
|
||||
|
||||
reset_instance_transformation(upper, instance, cut_matrix,
|
||||
attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper),
|
||||
attributes.has(ModelObjectCutAttribute::FlipUpper),
|
||||
local_displace);
|
||||
reset_instance_transformation(upper, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutUpper),
|
||||
attributes.has(ModelObjectCutAttribute::FlipUpper), local_displace);
|
||||
|
||||
res.push_back(upper);
|
||||
}
|
||||
if (attributes.has(ModelObjectCutAttribute::KeepLower) && lower->volumes.size() > 0) {
|
||||
invalidate_translations(lower, instances[instance]);
|
||||
|
||||
reset_instance_transformation(lower, instance, cut_matrix,
|
||||
attributes.has(ModelObjectCutAttribute::PlaceOnCutLower),
|
||||
reset_instance_transformation(lower, instance, cut_matrix, attributes.has(ModelObjectCutAttribute::PlaceOnCutLower),
|
||||
attributes.has(ModelObjectCutAttribute::PlaceOnCutLower) ? true : attributes.has(ModelObjectCutAttribute::FlipLower));
|
||||
|
||||
res.push_back(lower);
|
||||
}
|
||||
|
||||
if (attributes.has(ModelObjectCutAttribute::CreateDowels) && !dowels.empty()) {
|
||||
auto invalidate_translations = [](ModelObject *object, const ModelInstance *src_instance) {
|
||||
if (!object->origin_translation.isApprox(Vec3d::Zero()) && src_instance->get_offset().isApprox(Vec3d::Zero())) {
|
||||
object->center_around_origin();
|
||||
object->translate_instances(-object->origin_translation);
|
||||
object->origin_translation = Vec3d::Zero();
|
||||
} else {
|
||||
object->invalidate_bounding_box();
|
||||
object->center_around_origin();
|
||||
}
|
||||
};
|
||||
|
||||
auto reset_instance_transformation = [](ModelObject *object, size_t src_instance_idx, const Transform3d &cut_matrix,
|
||||
bool place_on_cut = false, bool flip = false, Vec3d local_displace = Vec3d::Zero()) {
|
||||
using namespace Geometry;
|
||||
// Reset instance transformation except offset and Z-rotation
|
||||
for (size_t i = 0; i < object->instances.size(); ++i) {
|
||||
auto & obj_instance = object->instances[i];
|
||||
const Vec3d offset = obj_instance->get_offset();
|
||||
const double rot_z = obj_instance->get_rotation().z();
|
||||
|
||||
obj_instance->set_transformation(Transformation());
|
||||
|
||||
const Vec3d displace = local_displace.isApprox(Vec3d::Zero()) ? Vec3d::Zero() : rotation_transform(obj_instance->get_rotation()) * local_displace;
|
||||
obj_instance->set_offset(offset + displace);
|
||||
|
||||
Vec3d rotation = Vec3d::Zero();
|
||||
if (!flip && !place_on_cut) {
|
||||
if (i != src_instance_idx) rotation[Z] = rot_z;
|
||||
} else {
|
||||
Transform3d rotation_matrix = Transform3d::Identity();
|
||||
if (flip)
|
||||
rotation_matrix = rotation_transform(PI * Vec3d::UnitX());
|
||||
|
||||
if (place_on_cut)
|
||||
rotation_matrix = rotation_matrix * Transformation(cut_matrix).get_matrix(true, false, true, true).inverse();
|
||||
|
||||
if (i != src_instance_idx)
|
||||
rotation_matrix = rotation_transform(rot_z * Vec3d::UnitZ()) * rotation_matrix;
|
||||
|
||||
rotation = Transformation(rotation_matrix).get_rotation();
|
||||
}
|
||||
|
||||
obj_instance->set_rotation(rotation);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto dowel : dowels) {
|
||||
invalidate_translations(dowel, instances[instance]);
|
||||
|
||||
|
@ -2108,6 +2099,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, std::array<Vec3d, 4> plane_poi
|
|||
res.push_back(dowel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
|
||||
|
||||
|
@ -2552,7 +2544,7 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
|
|||
// %print_volume.min.x() %print_volume.min.y() %print_volume.min.z()%print_volume.max.x() %print_volume.max.y() %print_volume.max.z();
|
||||
for (ModelInstance* model_instance : this->instances) {
|
||||
unsigned int inside_outside = 0;
|
||||
for (const ModelVolume* vol : this->volumes)
|
||||
for (const ModelVolume *vol : this->volumes) {
|
||||
if (vol->is_model_part()) {
|
||||
//BBS: add bounding box empty check logic, for some volume is empty before split(it will be removed after split to object)
|
||||
BoundingBoxf3 bb = vol->get_convex_hull().bounding_box();
|
||||
|
@ -2578,6 +2570,7 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume
|
|||
// Volume colliding with the build volume.
|
||||
inside_outside |= INSIDE | OUTSIDE;
|
||||
}
|
||||
}
|
||||
model_instance->print_volume_state =
|
||||
inside_outside == (INSIDE | OUTSIDE) ? ModelInstancePVS_Partly_Outside :
|
||||
inside_outside == INSIDE ? ModelInstancePVS_Inside : ModelInstancePVS_Fully_Outside;
|
||||
|
|
|
@ -316,7 +316,7 @@ enum class ModelVolumeType : int {
|
|||
SUPPORT_ENFORCER
|
||||
};
|
||||
|
||||
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels };
|
||||
enum class ModelObjectCutAttribute : int { KeepUpper, KeepLower, FlipUpper, FlipLower, PlaceOnCutUpper, PlaceOnCutLower, CreateDowels, CutToParts, InvalidateCutInfo };
|
||||
using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
|
||||
ENABLE_ENUM_BITMASK_OPERATORS(ModelObjectCutAttribute);
|
||||
|
||||
|
@ -475,6 +475,8 @@ public:
|
|||
void clone_for_cut(ModelObject **obj);
|
||||
Transform3d calculate_cut_plane_inverse_matrix(const std::array<Vec3d, 4> &plane_points);
|
||||
void process_connector_cut(ModelVolume *volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d& cut_matrix,
|
||||
ModelObjectCutAttributes attributes,
|
||||
ModelObject *upper, ModelObject *lower,
|
||||
std::vector<ModelObject *> &dowels,
|
||||
|
@ -485,8 +487,15 @@ public:
|
|||
ModelObjectCutAttributes attributes,
|
||||
ModelObject * upper,
|
||||
ModelObject * lower);
|
||||
void process_volume_cut(ModelVolume * volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d & cut_matrix,
|
||||
ModelObjectCutAttributes attributes,
|
||||
TriangleMesh & upper_mesh,
|
||||
TriangleMesh & lower_mesh);
|
||||
void process_solid_part_cut(ModelVolume * volume,
|
||||
const Transform3d & instance_matrix,
|
||||
const Transform3d & cut_matrix,
|
||||
const std::array<Vec3d, 4> &plane_points,
|
||||
ModelObjectCutAttributes attributes,
|
||||
ModelObject * upper,
|
||||
|
|
|
@ -113,6 +113,7 @@ GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& ic
|
|||
, m_last_active_id(0)
|
||||
, m_keep_upper(true)
|
||||
, m_keep_lower(true)
|
||||
, m_cut_to_parts(false)
|
||||
, m_do_segment(false)
|
||||
, m_segment_smoothing_alpha(0.5)
|
||||
, m_segment_number(5)
|
||||
|
@ -350,6 +351,7 @@ void GLGizmoAdvancedCut::reset_all()
|
|||
|
||||
m_keep_upper = true;
|
||||
m_keep_lower = true;
|
||||
m_cut_to_parts = false;
|
||||
m_place_on_cut_upper = true;
|
||||
m_place_on_cut_lower = false;
|
||||
m_rotate_upper = false;
|
||||
|
@ -653,11 +655,13 @@ void GLGizmoAdvancedCut::perform_cut(const Selection& selection)
|
|||
wxGetApp().plater()->cut(object_idx, instance_idx, get_plane_points_world_coord(),
|
||||
only_if(m_keep_upper, ModelObjectCutAttribute::KeepUpper) |
|
||||
only_if(m_keep_lower, ModelObjectCutAttribute::KeepLower) |
|
||||
only_if(m_cut_to_parts, ModelObjectCutAttribute::CutToParts) |
|
||||
only_if(m_place_on_cut_upper, ModelObjectCutAttribute::PlaceOnCutUpper) |
|
||||
only_if(m_place_on_cut_lower, ModelObjectCutAttribute::PlaceOnCutLower) |
|
||||
only_if(m_rotate_upper, ModelObjectCutAttribute::FlipUpper) |
|
||||
only_if(m_rotate_lower, ModelObjectCutAttribute::FlipLower) |
|
||||
only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels));
|
||||
only_if(create_dowels_as_separate_object, ModelObjectCutAttribute::CreateDowels) |
|
||||
only_if(!has_connectors, ModelObjectCutAttribute::InvalidateCutInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1393,7 +1397,7 @@ void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float b
|
|||
ImGui::PopStyleVar(1);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower);
|
||||
m_imgui->disabled_begin(!m_keep_upper || !m_keep_lower || m_cut_to_parts);
|
||||
if (m_imgui->button(_L("Add/Edit connectors"))) set_connectors_editing(true);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
|
@ -1406,22 +1410,22 @@ void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float b
|
|||
label_width = width;
|
||||
}
|
||||
|
||||
auto render_part_action_line = [this, label_width](const wxString& label, const wxString& suffix, bool& keep_part, bool& place_on_cut_part, bool& rotate_part) {
|
||||
CutConnectors &connectors = m_c->selection_info()->model_object()->cut_connectors;
|
||||
|
||||
const bool has_connectors = !connectors.empty();
|
||||
auto render_part_action_line = [this, label_width, &connectors](const wxString &label, const wxString &suffix, bool &keep_part, bool &place_on_cut_part, bool &rotate_part) {
|
||||
bool keep = true;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(label);
|
||||
|
||||
ImGui::SameLine(label_width);
|
||||
|
||||
m_imgui->disabled_begin(!connectors.empty());
|
||||
m_imgui->disabled_begin(!connectors.empty() || m_cut_to_parts);
|
||||
m_imgui->bbl_checkbox(_L("Keep") + suffix, connectors.empty() ? keep_part : keep);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
m_imgui->disabled_begin(!keep_part);
|
||||
m_imgui->disabled_begin(!keep_part || m_cut_to_parts);
|
||||
if (m_imgui->bbl_checkbox(_L("Place on cut") + suffix, place_on_cut_part))
|
||||
rotate_part = false;
|
||||
ImGui::SameLine();
|
||||
|
@ -1434,6 +1438,9 @@ void GLGizmoAdvancedCut::render_cut_plane_input_window(float x, float y, float b
|
|||
render_part_action_line( _L("Upper part"), "##upper", m_keep_upper, m_place_on_cut_upper, m_rotate_upper);
|
||||
render_part_action_line( _L("Lower part"), "##lower", m_keep_lower, m_place_on_cut_lower, m_rotate_lower);
|
||||
|
||||
m_imgui->disabled_begin(has_connectors);
|
||||
m_imgui->bbl_checkbox(_L("Cut to parts"), m_cut_to_parts);
|
||||
m_imgui->disabled_end();
|
||||
|
||||
#if 0
|
||||
// Auto segment input
|
||||
|
|
|
@ -48,6 +48,7 @@ private:
|
|||
|
||||
bool m_keep_upper;
|
||||
bool m_keep_lower;
|
||||
bool m_cut_to_parts;
|
||||
bool m_place_on_cut_upper{true};
|
||||
bool m_place_on_cut_lower{false};
|
||||
bool m_rotate_upper{false};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue