fix(build): revert CutUtils to v2.4.2 — ImageMap texture-remap additions broke signatures

The ImageMap fork removed src_object from perform_by_contour and saved_paintings
from finalize, making the .cpp incompatible with the v2.4.2 header. Reset both
files to v2.4.2 baseline; texture remapping on cut is an ImageMap-only feature
not yet ported.
This commit is contained in:
thysson2701
2026-07-21 15:00:48 +02:00
parent 7b554e1f50
commit 8b805d8cc9

View File

@@ -3,7 +3,6 @@
#include "Geometry.hpp"
#include "libslic3r.h"
#include "Model.hpp"
#include "ModelTextureDataRemap.hpp"
#include "TriangleMeshSlicer.hpp"
#include "TriangleSelector.hpp"
#include "ObjectID.hpp"
@@ -46,59 +45,10 @@ static void apply_tolerance(ModelVolume* vol)
vol->set_offset(vol->get_offset() + rot_norm * z_offset);
}
static void apply_cut_texture_data(ModelVolume *volume, const SimplifyTextureDataSnapshot *source_snapshot, const Transform3d &cut_matrix)
{
if (volume == nullptr || source_snapshot == nullptr ||
(source_snapshot->source == SimplifyColorSource::None && !source_snapshot->region_painting_present) ||
volume->mesh().empty())
return;
SimplifyTextureDataSnapshot snapshot = *source_snapshot;
transform_simplify_texture_data_snapshot(snapshot, cut_matrix);
transform_simplify_texture_data_snapshot(snapshot, translation_transform(-volume->get_offset()));
SimplifyTextureDataResult result = remap_simplify_texture_data(snapshot, volume->mesh().its);
apply_simplify_texture_data_result(*volume, std::move(result));
}
static bool volume_has_remappable_color_data(const ModelVolume &volume)
{
const indexed_triangle_set &its = volume.mesh().its;
if (its.vertices.empty() || its.indices.empty())
return false;
if (model_volume_region_painting_needs_remap(volume))
return true;
if (!volume.texture_mapping_color_facets.empty())
return true;
const bool has_valid_uvs = volume.imported_texture_uv_valid.size() == its.indices.size() &&
volume.imported_texture_uvs_per_face.size() >= its.indices.size() * 6;
const bool has_rgba_texture = volume.imported_texture_width > 0 && volume.imported_texture_height > 0 &&
volume.imported_texture_rgba.size() >=
size_t(volume.imported_texture_width) * size_t(volume.imported_texture_height) * 4;
const bool has_raw_texture = volume.imported_texture_width > 0 && volume.imported_texture_height > 0 &&
volume.imported_texture_raw_channels > 0 &&
volume.imported_texture_raw_filament_offsets.size() >=
size_t(volume.imported_texture_width) * size_t(volume.imported_texture_height) *
size_t(volume.imported_texture_raw_channels);
if (has_valid_uvs && (has_rgba_texture || has_raw_texture))
return true;
return volume.imported_vertex_colors_rgba.size() == its.vertices.size();
}
static ModelVolume* add_cut_volume(TriangleMesh &mesh,
ModelObject *object,
const ModelVolume *src_volume,
const Transform3d &cut_matrix,
const std::string &suffix = {},
ModelVolumeType type = ModelVolumeType::MODEL_PART,
const SimplifyTextureDataSnapshot *source_snapshot = nullptr)
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 nullptr;
return;
mesh.transform(cut_matrix);
ModelVolume* vol = object->add_volume(mesh);
@@ -111,31 +61,20 @@ static ModelVolume* add_cut_volume(TriangleMesh &mesh,
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;
apply_cut_texture_data(vol, source_snapshot, cut_matrix);
return vol;
}
static void process_volume_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, TriangleMesh& upper_mesh, TriangleMesh& lower_mesh,
SimplifyTextureDataSnapshot *source_snapshot = nullptr,
const SimplifyTextureDataSnapshot *volume_snapshot = nullptr)
static void process_volume_cut( const 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();
const Transformation cut_transformation = Transformation(cut_matrix);
const Transform3d invert_cut_matrix =
cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1 * cut_transformation.get_offset());
const Transform3d source_to_cut_matrix = invert_cut_matrix * instance_matrix * volume_matrix;
if (source_snapshot != nullptr) {
*source_snapshot = volume_snapshot != nullptr ? *volume_snapshot : snapshot_simplify_texture_data(*volume);
transform_simplify_texture_data_snapshot(*source_snapshot, source_to_cut_matrix);
}
const Transform3d invert_cut_matrix = cut_transformation.get_rotation_matrix().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(source_to_cut_matrix, true);
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);
@@ -147,8 +86,7 @@ static void process_volume_cut( ModelVolume* volume, const Transform3d& instance
static void process_connector_cut( ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower,
std::vector<ModelObject*>& dowels,
const SimplifyTextureDataSnapshot *volume_snapshot = nullptr)
std::vector<ModelObject*>& dowels)
{
assert(volume->cut_info.is_connector);
volume->cut_info.set_processed();
@@ -205,16 +143,15 @@ static void process_connector_cut( ModelVolume* volume, const Transform3d& inst
// Perform cut
TriangleMesh upper_mesh, lower_mesh;
SimplifyTextureDataSnapshot source_snapshot;
process_volume_cut(volume, Transform3d::Identity(), cut_matrix, attributes, upper_mesh, lower_mesh, &source_snapshot, volume_snapshot);
process_volume_cut(volume, Transform3d::Identity(), 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(), &source_snapshot);
add_cut_volume(lower_mesh, lower, volume, cut_matrix, "_B", volume->type(), &source_snapshot);
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A", volume->type());
add_cut_volume(lower_mesh, lower, volume, cut_matrix, "_B", volume->type());
}
}
@@ -241,31 +178,29 @@ static void process_modifier_cut(ModelVolume* volume, const Transform3d& instanc
lower->add_volume(*volume);
}
static void process_solid_part_cut(ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower,
const SimplifyTextureDataSnapshot *volume_snapshot = nullptr)
static void process_solid_part_cut(const ModelVolume* volume, const Transform3d& instance_matrix, const Transform3d& cut_matrix,
ModelObjectCutAttributes attributes, ModelObject* upper, ModelObject* lower)
{
// Perform cut
TriangleMesh upper_mesh, lower_mesh;
SimplifyTextureDataSnapshot source_snapshot;
process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh, &source_snapshot, volume_snapshot);
process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh);
// Add required cut parts to the objects
if (attributes.has(ModelObjectCutAttribute::KeepAsParts)) {
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A", ModelVolumeType::MODEL_PART, &source_snapshot);
add_cut_volume(upper_mesh, upper, volume, cut_matrix, "_A");
if (!lower_mesh.empty()) {
add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B", ModelVolumeType::MODEL_PART, &source_snapshot);
add_cut_volume(lower_mesh, upper, volume, cut_matrix, "_B");
upper->volumes.back()->cut_info.is_from_upper = false;
}
return;
}
if (attributes.has(ModelObjectCutAttribute::KeepUpper))
add_cut_volume(upper_mesh, upper, volume, cut_matrix, {}, ModelVolumeType::MODEL_PART, &source_snapshot);
add_cut_volume(upper_mesh, upper, volume, cut_matrix);
if (attributes.has(ModelObjectCutAttribute::KeepLower) && !lower_mesh.empty())
add_cut_volume(lower_mesh, lower, volume, cut_matrix, {}, ModelVolumeType::MODEL_PART, &source_snapshot);
add_cut_volume(lower_mesh, lower, volume, cut_matrix);
}
static void reset_instance_transformation(ModelObject* object, size_t src_instance_idx,
@@ -344,9 +279,22 @@ void Cut::post_process(ModelObject* upper, ModelObject* lower, ModelObjectPtrs&
}
void Cut::finalize(const ModelObjectPtrs& objects)
void Cut::finalize(const ModelObjectPtrs& objects, const std::vector<std::optional<TriangleSelector::SavedPainting>>& saved_paintings)
{
//clear model from temporarry objects
// Paint volumes
for (const auto& saved_painting : saved_paintings) {
if (saved_painting) {
for (const auto object : objects) {
for (const auto volume : object->volumes) {
if (volume->is_model_part() && !volume->is_cut_connector()) {
volume->restore_painting(saved_painting, true);
}
}
}
}
}
//clear model from temporary objects
m_model.clear_objects();
// add to model result objects
@@ -385,18 +333,27 @@ const ModelObjectPtrs& Cut::perform_with_plane()
const Transformation cut_transformation = Transformation(m_cut_matrix);
const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset());
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
for (ModelVolume* volume : mo->volumes) {
SimplifyTextureDataSnapshot volume_snapshot = snapshot_simplify_texture_data(*volume);
// Save painting data before reset_extra_facets() discards it.
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
volume->reset_extra_facets();
if (!volume->is_model_part()) {
if (volume->cut_info.is_processed)
process_modifier_cut(volume, instance_matrix, inverse_cut_matrix, m_attributes, upper, lower);
else
process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels, &volume_snapshot);
process_connector_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, dowels);
}
else if (!volume->mesh().empty())
process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower, &volume_snapshot);
process_solid_part_cut(volume, instance_matrix, m_cut_matrix, m_attributes, upper, lower);
}
// Post-process cut parts
@@ -442,9 +399,9 @@ const ModelObjectPtrs& Cut::perform_with_plane()
}
}
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
finalize(cut_object_ptrs, saved_paintings);
finalize(cut_object_ptrs);
BOOST_LOG_TRIVIAL(trace) << "ModelObject::cut - end";
return m_model.objects;
}
@@ -472,25 +429,10 @@ static void distribute_modifiers_from_object(ModelObject* from_obj, const int in
static void merge_solid_parts_inside_object(ModelObjectPtrs& objects)
{
for (ModelObject* mo : objects) {
bool has_remappable_color_data = false;
for (const ModelVolume* mv : mo->volumes) {
if (mv->is_model_part() && !mv->is_cut_connector() && volume_has_remappable_color_data(*mv)) {
has_remappable_color_data = true;
break;
}
}
if (has_remappable_color_data) {
mo->sort_volumes(true);
continue;
}
TriangleMesh mesh;
const ModelVolume *merged_volume_source = nullptr;
// Merge all SolidPart but not Connectors
for (const ModelVolume* mv : mo->volumes) {
if (mv->is_model_part() && !mv->is_cut_connector()) {
if (merged_volume_source == nullptr)
merged_volume_source = mv;
TriangleMesh m = mv->mesh();
m.transform(mv->get_matrix());
mesh.merge(m);
@@ -499,14 +441,6 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs& objects)
if (!mesh.empty()) {
ModelVolume* new_volume = mo->add_volume(mesh);
new_volume->name = mo->name;
if (merged_volume_source != nullptr) {
new_volume->config.assign_config(merged_volume_source->config);
if (ModelMaterial *material = merged_volume_source->material())
new_volume->set_material(merged_volume_source->material_id(), *material);
else
new_volume->set_material_id(merged_volume_source->material_id());
new_volume->cut_info = merged_volume_source->cut_info;
}
// Delete all merged SolidPart but not Connectors
for (int i = int(mo->volumes.size()) - 2; i >= 0; --i) {
const ModelVolume* mv = mo->volumes[i];
@@ -520,7 +454,7 @@ static void merge_solid_parts_inside_object(ModelObjectPtrs& objects)
}
const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowels_count)
const ModelObjectPtrs& Cut::perform_by_contour(const ModelObject* src_object, std::vector<Part> parts, int dowels_count)
{
ModelObject* cut_mo = m_model.objects.front();
@@ -535,6 +469,19 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
lower->name = lower->name + "_B";
}
// Save painting data so we later can remap it.
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
const auto instance_matrix = src_object->instances[m_instance]->get_transformation().get_matrix_no_offset();
for (const auto volume : src_object->volumes) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
}
const size_t cut_parts_cnt = parts.size();
bool has_modifiers = false;
@@ -564,7 +511,7 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
merge_solid_parts_inside_object(cut_object_ptrs);
// replace initial objects in model with cut object
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
}
else if (volumes.size() > cut_parts_cnt) {
// Means that object is cut with connectors
@@ -595,7 +542,7 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
merge_solid_parts_inside_object(cut_object_ptrs);
// replace initial objects in model with cut object
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
// Add Dowel-connectors as separate objects to model
if (cut_connectors_obj.size() >= 3)
@@ -607,7 +554,12 @@ const ModelObjectPtrs& Cut::perform_by_contour(std::vector<Part> parts, int dowe
}
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Transform3d& rotation_m, bool keep_as_parts/* = false*/)
const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove,
const Transform3d& rotation_m,
const int groove_count,
const float groove_gap,
const float m_radius,
bool keep_as_parts /* = false*/)
{
ModelObject* cut_mo = m_model.objects.front();
@@ -621,6 +573,20 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
upper->name = upper->name + "_A";
lower->name = lower->name + "_B";
}
// Save painting data so we later can remap it.
std::vector<std::optional<TriangleSelector::SavedPainting>> saved_paintings;
if (m_attributes.has(ModelObjectCutAttribute::KeepPaint)) {
const auto instance_matrix = cut_mo->instances[m_instance]->get_transformation().get_matrix_no_offset();
for (const auto volume : cut_mo->volumes) {
saved_paintings.emplace_back(volume->save_painting());
if (saved_paintings.back()) {
// Transform mesh to cut space (same transform as process_volume_cut applies)
saved_paintings.back()->mesh.transform(instance_matrix * volume->get_matrix(), true);
}
}
}
const double groove_half_depth = 0.5 * double(groove.depth);
Model tmp_model_for_cut = Model();
@@ -654,61 +620,108 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
reset_instance_transformation(object, m_instance);
};
// cut by upper plane
const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
// cut by upper plane (+Z)
{
const Transform3d cut_matrix_upper = translation_transform(rotation_m * (groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// cut by lower plane
const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
// cut by lower plane (-Z)
{
const Transform3d cut_matrix_lower = translation_transform(rotation_m * (-groove_half_depth * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
}
// cut middle part with 2 angles and add parts to related upper/lower objects
// Compute same slot outer width used in preview plane
const float groove_width = calculate_groove_width(groove, m_radius);
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
ModelObject* groove_object{nullptr};
// cut by angle1 plane
{
const Transform3d cut_matrix_angle1 = translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
// multiple cuts
for (int i = 0; i < groove_count; i++) {
bool is_first_groove = i == 0;
bool is_last_groove = i == groove_count - 1;
cut(tmp_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
// Calculate the x-axis offset for this dovetail
float groove_offset_factor_start = -.5 * ((groove_count - 1));
float groove_offset_factor = groove_offset_factor_start + i;
float offset_x = groove_offset_factor * (groove_gap + groove_width);
tmp_object->clone_for_cut(&groove_object);
for (ModelVolume* volume : tmp_object->volumes) {
ModelVolume* new_vol = groove_object->add_volume(*volume);
new_vol->reset_from_upper();
}
// isolate area of current groove
if (!is_first_groove) {
float left_cut_position = (-groove_gap / 2.f) - (groove_width / 2.f) + offset_x;
const Transform3d cut_matrix_left = translation_transform(rotation_m * (left_cut_position * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
cut(groove_object, cut_matrix_left, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
if (!is_last_groove) {
float right_cut_position = (groove_gap / 2.f) + (groove_width / 2.f) + offset_x;
const Transform3d cut_matrix_right = translation_transform(rotation_m * (right_cut_position * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, M_PI / 2.0, 0));
cut(groove_object, cut_matrix_right, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
}
const Transform3d groove_translation = translation_transform(rotation_m * (offset_x * Vec3d::UnitX()));
// cut middle part with 2 angles and add parts to related upper/lower objects
const double h_side_shift = 0.5 * double(groove.width + groove.depth / tan(groove.flaps_angle));
// cut by angle1 plane
{
const Transform3d cut_matrix_angle1 = groove_translation * translation_transform(rotation_m * (-h_side_shift * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(groove_object, cut_matrix_angle1, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// cut by angle2 plane
{
const Transform3d cut_matrix_angle2 = groove_translation * translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(groove_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// apply tolerance to the middle part
{
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
const Transform3d cut_matrix_lower_tolerance = groove_translation * translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) *
m_cut_matrix;
cut(groove_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
const Transform3d cut_matrix_angle1_tolerance = groove_translation * translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(groove_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
const Transform3d cut_matrix_angle2_tolerance = groove_translation * translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) *
m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(groove_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
groove_object->clear_volumes();
}
// cut by angle2 plane
{
const Transform3d cut_matrix_angle2 = translation_transform(rotation_m * (h_side_shift * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(tmp_object, cut_matrix_angle2, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
add_volumes_from_cut(lower, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// apply tolerance to the middle part
{
const double h_groove_shift_tolerance = groove_half_depth - (double)groove.depth_tolerance;
const Transform3d cut_matrix_lower_tolerance = translation_transform(rotation_m * (-h_groove_shift_tolerance * Vec3d::UnitZ())) * m_cut_matrix;
cut(tmp_object, cut_matrix_lower_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
const double h_side_shift_tolerance = h_side_shift - 0.5 * double(groove.width_tolerance);
const Transform3d cut_matrix_angle1_tolerance = translation_transform(rotation_m * (-h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, -groove.flaps_angle, -groove.angle));
cut(tmp_object, cut_matrix_angle1_tolerance, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
const Transform3d cut_matrix_angle2_tolerance = translation_transform(rotation_m * (h_side_shift_tolerance * Vec3d::UnitX())) * m_cut_matrix * rotation_transform(Vec3d(0, groove.flaps_angle, groove.angle));
cut(tmp_object, cut_matrix_angle2_tolerance, ModelObjectCutAttribute::KeepUpper, tmp_model_for_cut);
}
// this part can be added to the upper object now
add_volumes_from_cut(upper, ModelObjectCutAttribute::KeepLower, tmp_model_for_cut);
ModelObjectPtrs cut_object_ptrs;
if (keep_as_parts) {
@@ -747,9 +760,24 @@ const ModelObjectPtrs& Cut::perform_with_groove(const Groove& groove, const Tran
merge_solid_parts_inside_object(cut_object_ptrs);
}
finalize(cut_object_ptrs);
finalize(cut_object_ptrs, saved_paintings);
return m_model.objects;
}
float Cut::calculate_groove_width (const Cut::Groove& groove, const float m_radius)
{
// Compute same slot outer width used in preview plane
const double flap_width = is_approx(groove.flaps_angle, 0.f) ? groove.depth : groove.depth / sin(groove.flaps_angle);
const double total_flap_width = 2.0 * flap_width * cos(groove.flaps_angle);
const double slot_neck_half_width = 0.5f * (groove.width);
const double slot_mouth_half_width = 0.5 * (groove.width + total_flap_width);
const double plane_half_height = 0.5f* (1.5f * (1.5f *m_radius));
const double flap_taper_offset = plane_half_height * tan(groove.angle);
const double slot_outer_x_max = std::max(slot_mouth_half_width + flap_taper_offset, slot_neck_half_width + flap_taper_offset);
return float(2.0 * slot_outer_x_max);
}
} // namespace Slic3r