mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 00:21:46 +08:00
Cut WIP: Import/Export cut information to/from .3mf file
+ Fixed a crash during change object selection, when CutGizmo is On + Fixed Undo/Redo (was accidentally broken with 7912613dc8e11db2ddea8018ce16b26a01756a3b)
This commit is contained in:
parent
70a575198b
commit
cf144da4fe
@ -77,6 +77,7 @@ const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Prusa_Slicer_layer_config
|
|||||||
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
|
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
|
||||||
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
|
const std::string SLA_DRAIN_HOLES_FILE = "Metadata/Slic3r_PE_sla_drain_holes.txt";
|
||||||
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml";
|
const std::string CUSTOM_GCODE_PER_PRINT_Z_FILE = "Metadata/Prusa_Slicer_custom_gcode_per_print_z.xml";
|
||||||
|
const std::string CUT_INFORMATION_FILE = "Metadata/Prusa_Slicer_cut_information.xml";
|
||||||
|
|
||||||
static constexpr const char* MODEL_TAG = "model";
|
static constexpr const char* MODEL_TAG = "model";
|
||||||
static constexpr const char* RESOURCES_TAG = "resources";
|
static constexpr const char* RESOURCES_TAG = "resources";
|
||||||
@ -416,6 +417,7 @@ namespace Slic3r {
|
|||||||
typedef std::map<int, Geometry> IdToGeometryMap;
|
typedef std::map<int, Geometry> IdToGeometryMap;
|
||||||
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
||||||
typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
||||||
|
typedef std::map<int, CutObjectBase> IdToCutObjectIdMap;
|
||||||
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
||||||
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;
|
typedef std::map<int, std::vector<sla::DrainHole>> IdToSlaDrainHolesMap;
|
||||||
|
|
||||||
@ -443,6 +445,7 @@ namespace Slic3r {
|
|||||||
IdToGeometryMap m_geometries;
|
IdToGeometryMap m_geometries;
|
||||||
CurrentConfig m_curr_config;
|
CurrentConfig m_curr_config;
|
||||||
IdToMetadataMap m_objects_metadata;
|
IdToMetadataMap m_objects_metadata;
|
||||||
|
IdToCutObjectIdMap m_cut_object_ids;
|
||||||
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
||||||
IdToLayerConfigRangesMap m_layer_config_ranges;
|
IdToLayerConfigRangesMap m_layer_config_ranges;
|
||||||
IdToSlaSupportPointsMap m_sla_support_points;
|
IdToSlaSupportPointsMap m_sla_support_points;
|
||||||
@ -474,6 +477,7 @@ namespace Slic3r {
|
|||||||
|
|
||||||
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions);
|
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions);
|
||||||
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
|
void _extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
|
||||||
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
|
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions);
|
||||||
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
@ -676,6 +680,10 @@ namespace Slic3r {
|
|||||||
// extract slic3r layer heights profile file
|
// extract slic3r layer heights profile file
|
||||||
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
||||||
}
|
}
|
||||||
|
else if (boost::algorithm::iequals(name, CUT_INFORMATION_FILE)) {
|
||||||
|
// extract slic3r layer config ranges file
|
||||||
|
_extract_cut_information_from_archive(archive, stat, config_substitutions);
|
||||||
|
}
|
||||||
else if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) {
|
else if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE)) {
|
||||||
// extract slic3r layer config ranges file
|
// extract slic3r layer config ranges file
|
||||||
_extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
|
_extract_layer_config_ranges_from_archive(archive, stat, config_substitutions);
|
||||||
@ -766,6 +774,11 @@ namespace Slic3r {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// m_cut_object_ids are indexed by a 1 based model object index.
|
||||||
|
IdToCutObjectIdMap::iterator cut_object_id = m_cut_object_ids.find(object.second + 1);
|
||||||
|
if (cut_object_id != m_cut_object_ids.end())
|
||||||
|
model_object->cut_id = std::move(cut_object_id->second);
|
||||||
|
|
||||||
// m_layer_heights_profiles are indexed by a 1 based model object index.
|
// m_layer_heights_profiles are indexed by a 1 based model object index.
|
||||||
IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1);
|
IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.second + 1);
|
||||||
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
||||||
@ -944,6 +957,48 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _3MF_Importer::_extract_cut_information_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, ConfigSubstitutionContext& config_substitutions)
|
||||||
|
{
|
||||||
|
if (stat.m_uncomp_size > 0) {
|
||||||
|
std::string buffer((size_t)stat.m_uncomp_size, 0);
|
||||||
|
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||||
|
if (res == 0) {
|
||||||
|
add_error("Error while reading cut information data to buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream iss(buffer); // wrap returned xml to istringstream
|
||||||
|
pt::ptree objects_tree;
|
||||||
|
pt::read_xml(iss, objects_tree);
|
||||||
|
|
||||||
|
for (const auto& object : objects_tree.get_child("objects")) {
|
||||||
|
pt::ptree object_tree = object.second;
|
||||||
|
int obj_idx = object_tree.get<int>("<xmlattr>.id", -1);
|
||||||
|
if (obj_idx <= 0) {
|
||||||
|
add_error("Found invalid object id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdToCutObjectIdMap::iterator object_item = m_cut_object_ids.find(obj_idx);
|
||||||
|
if (object_item != m_cut_object_ids.end()) {
|
||||||
|
add_error("Found duplicated cut_object_id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& obj_cut_id : object_tree) {
|
||||||
|
if (obj_cut_id.first != "cut_id")
|
||||||
|
continue;
|
||||||
|
pt::ptree cut_id_tree = obj_cut_id.second;
|
||||||
|
ObjectID obj_id(cut_id_tree.get<size_t>("<xmlattr>.id"));
|
||||||
|
CutObjectBase cut_id(ObjectID(cut_id_tree.get<size_t>("<xmlattr>.id")),
|
||||||
|
cut_id_tree.get<size_t>("<xmlattr>.check_sum"),
|
||||||
|
cut_id_tree.get<size_t>("<xmlattr>.connectors_cnt"));
|
||||||
|
m_cut_object_ids.insert({ obj_idx, std::move(cut_id) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _3MF_Importer::_extract_print_config_from_archive(
|
void _3MF_Importer::_extract_print_config_from_archive(
|
||||||
mz_zip_archive& archive, const mz_zip_archive_file_stat& stat,
|
mz_zip_archive& archive, const mz_zip_archive_file_stat& stat,
|
||||||
DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions,
|
DynamicPrintConfig& config, ConfigSubstitutionContext& config_substitutions,
|
||||||
@ -2219,6 +2274,7 @@ namespace Slic3r {
|
|||||||
bool _add_object_to_model_stream(mz_zip_writer_staged_context &context, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
|
bool _add_object_to_model_stream(mz_zip_writer_staged_context &context, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
|
||||||
bool _add_mesh_to_object_stream(mz_zip_writer_staged_context &context, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
bool _add_mesh_to_object_stream(mz_zip_writer_staged_context &context, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
||||||
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
||||||
|
bool _add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
|
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
|
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
@ -2281,6 +2337,15 @@ namespace Slic3r {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds file with information for object cut ("Metadata/Slic3r_PE_cut_information.txt").
|
||||||
|
// All information for object cut of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
||||||
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||||
|
if (!_add_cut_information_file_to_archive(archive, model)) {
|
||||||
|
close_zip_writer(&archive);
|
||||||
|
boost::filesystem::remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds layer height profile file ("Metadata/Slic3r_PE_layer_heights_profile.txt").
|
// Adds layer height profile file ("Metadata/Slic3r_PE_layer_heights_profile.txt").
|
||||||
// All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
// All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
||||||
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||||
@ -2781,6 +2846,51 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _3MF_Exporter::_add_cut_information_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
|
{
|
||||||
|
std::string out = "";
|
||||||
|
pt::ptree tree;
|
||||||
|
|
||||||
|
unsigned int object_cnt = 0;
|
||||||
|
for (const ModelObject* object : model.objects) {
|
||||||
|
object_cnt++;
|
||||||
|
pt::ptree& obj_tree = tree.add("objects.object", "");
|
||||||
|
|
||||||
|
obj_tree.put("<xmlattr>.id", object_cnt);
|
||||||
|
|
||||||
|
// Store info for cut_id
|
||||||
|
pt::ptree& cut_id_tree = obj_tree.add("cut_id", "");
|
||||||
|
|
||||||
|
// store cut_id atributes
|
||||||
|
cut_id_tree.put("<xmlattr>.id", object->cut_id.id().id);
|
||||||
|
cut_id_tree.put("<xmlattr>.check_sum", object->cut_id.check_sum());
|
||||||
|
cut_id_tree.put("<xmlattr>.connectors_cnt", object->cut_id.connectors_cnt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tree.empty()) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
pt::write_xml(oss, tree);
|
||||||
|
out = oss.str();
|
||||||
|
|
||||||
|
// Post processing("beautification") of the output string for a better preview
|
||||||
|
boost::replace_all(out, "><object", ">\n <object");
|
||||||
|
boost::replace_all(out, "><cut_id", ">\n <cut_id");
|
||||||
|
boost::replace_all(out, "></cut_id>", ">\n </cut_id>");
|
||||||
|
boost::replace_all(out, "></object>", ">\n </object>");
|
||||||
|
// OR just
|
||||||
|
boost::replace_all(out, "><", ">\n<");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.empty()) {
|
||||||
|
if (!mz_zip_writer_add_mem(&archive, CUT_INFORMATION_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION)) {
|
||||||
|
add_error("Unable to add cut information file to archive");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model)
|
bool _3MF_Exporter::_add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
{
|
{
|
||||||
assert(is_decimal_separator_point());
|
assert(is_decimal_separator_point());
|
||||||
|
@ -351,7 +351,7 @@ public:
|
|||||||
// Holes to be drilled into the object so resin can flow out
|
// Holes to be drilled into the object so resin can flow out
|
||||||
sla::DrainHoles sla_drain_holes;
|
sla::DrainHoles sla_drain_holes;
|
||||||
|
|
||||||
// Connectors to be added into the object after cut
|
// Connectors to be added into the object before cut and are used to create a solid/negative volumes during a cut perform
|
||||||
CutConnectors cut_connectors;
|
CutConnectors cut_connectors;
|
||||||
CutObjectBase cut_id;
|
CutObjectBase cut_id;
|
||||||
|
|
||||||
|
@ -89,7 +89,9 @@ private:
|
|||||||
friend class cereal::access;
|
friend class cereal::access;
|
||||||
friend class Slic3r::UndoRedo::StackImpl;
|
friend class Slic3r::UndoRedo::StackImpl;
|
||||||
template<class Archive> void serialize(Archive &ar) { ar(m_id); }
|
template<class Archive> void serialize(Archive &ar) { ar(m_id); }
|
||||||
|
protected: // #vbCHECKME && #ysFIXME
|
||||||
ObjectBase(const ObjectID id) : m_id(id) {}
|
ObjectBase(const ObjectID id) : m_id(id) {}
|
||||||
|
private:
|
||||||
template<class Archive> static void load_and_construct(Archive & ar, cereal::construct<ObjectBase> &construct) { ObjectID id; ar(id); construct(id); }
|
template<class Archive> static void load_and_construct(Archive & ar, cereal::construct<ObjectBase> &construct) { ObjectID id; ar(id); construct(id); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,6 +143,8 @@ public:
|
|||||||
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
|
// Constructor with ignored int parameter to assign an invalid ID, to be replaced
|
||||||
// by an existing ID copied from elsewhere.
|
// by an existing ID copied from elsewhere.
|
||||||
CutObjectBase(int) : ObjectBase(-1) {}
|
CutObjectBase(int) : ObjectBase(-1) {}
|
||||||
|
// Constructor to initialize full information from 3mf
|
||||||
|
CutObjectBase(ObjectID id, size_t check_sum, size_t connectors_cnt) : ObjectBase(id), m_check_sum(check_sum), m_connectors_cnt(connectors_cnt) {}
|
||||||
// The class tree will have virtual tables and type information.
|
// The class tree will have virtual tables and type information.
|
||||||
virtual ~CutObjectBase() = default;
|
virtual ~CutObjectBase() = default;
|
||||||
|
|
||||||
|
@ -627,7 +627,7 @@ void GLGizmoCut3D::render_cut_center_graber()
|
|||||||
|
|
||||||
const BoundingBoxf3 box = bounding_box();
|
const BoundingBoxf3 box = bounding_box();
|
||||||
|
|
||||||
const double mean_size = float((box.size().x() + box.size().y() + box.size().z()) / 6.0);
|
const double mean_size = float((box.size().x() + box.size().y() + box.size().z()) / 3.0);
|
||||||
double size = m_dragging && m_hover_id == Z ? double(graber.get_dragging_half_size(mean_size)) : double(graber.get_half_size(mean_size));
|
double size = m_dragging && m_hover_id == Z ? double(graber.get_dragging_half_size(mean_size)) : double(graber.get_half_size(mean_size));
|
||||||
|
|
||||||
Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
Vec3d cone_scale = Vec3d(0.75 * size, 0.75 * size, 1.8 * size);
|
||||||
@ -821,8 +821,8 @@ bool GLGizmoCut3D::on_init()
|
|||||||
|
|
||||||
void GLGizmoCut3D::on_load(cereal::BinaryInputArchive& ar)
|
void GLGizmoCut3D::on_load(cereal::BinaryInputArchive& ar)
|
||||||
{
|
{
|
||||||
ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, //m_selected,
|
ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, m_connectors_editing,//m_selected,
|
||||||
m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id,
|
// m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id,
|
||||||
m_ar_plane_center, m_ar_rotations);
|
m_ar_plane_center, m_ar_rotations);
|
||||||
|
|
||||||
set_center_pos(m_ar_plane_center, true);
|
set_center_pos(m_ar_plane_center, true);
|
||||||
@ -835,8 +835,8 @@ void GLGizmoCut3D::on_load(cereal::BinaryInputArchive& ar)
|
|||||||
|
|
||||||
void GLGizmoCut3D::on_save(cereal::BinaryOutputArchive& ar) const
|
void GLGizmoCut3D::on_save(cereal::BinaryOutputArchive& ar) const
|
||||||
{
|
{
|
||||||
ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, //m_selected,
|
ar( m_keep_upper, m_keep_lower, m_rotate_lower, m_rotate_upper, m_hide_cut_plane, m_mode, m_connectors_editing,//m_selected,
|
||||||
m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id,
|
// m_connector_depth_ratio, m_connector_size, m_connector_mode, m_connector_type, m_connector_style, m_connector_shape_id,
|
||||||
m_ar_plane_center, m_ar_rotations);
|
m_ar_plane_center, m_ar_rotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,7 +1224,10 @@ bool GLGizmoCut3D::update_bb()
|
|||||||
m_max_pos = box.max;
|
m_max_pos = box.max;
|
||||||
m_min_pos = box.min;
|
m_min_pos = box.min;
|
||||||
m_bb_center = box.center();
|
m_bb_center = box.center();
|
||||||
|
if (box.contains(m_center_offset))
|
||||||
set_center_pos(m_bb_center + m_center_offset, true);
|
set_center_pos(m_bb_center + m_center_offset, true);
|
||||||
|
else
|
||||||
|
set_center_pos(m_bb_center, true);
|
||||||
|
|
||||||
m_radius = box.radius();
|
m_radius = box.radius();
|
||||||
m_grabber_connection_len = 0.75 * m_radius;// std::min<double>(0.75 * m_radius, 35.0);
|
m_grabber_connection_len = 0.75 * m_radius;// std::min<double>(0.75 * m_radius, 35.0);
|
||||||
@ -1242,6 +1245,9 @@ bool GLGizmoCut3D::update_bb()
|
|||||||
m_circle.reset();
|
m_circle.reset();
|
||||||
m_scale.reset();
|
m_scale.reset();
|
||||||
m_snap_radii.reset();
|
m_snap_radii.reset();
|
||||||
|
m_reference_radius.reset();
|
||||||
|
|
||||||
|
on_unregister_raycasters_for_picking();
|
||||||
|
|
||||||
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
|
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
|
||||||
m_selected.clear();
|
m_selected.clear();
|
||||||
@ -1271,7 +1277,6 @@ void GLGizmoCut3D::on_render()
|
|||||||
{
|
{
|
||||||
if (update_bb() || force_update_clipper_on_render) {
|
if (update_bb() || force_update_clipper_on_render) {
|
||||||
update_clipper_on_render();
|
update_clipper_on_render();
|
||||||
if (force_update_clipper_on_render)
|
|
||||||
m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, 0.4f);
|
m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, 0.4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1725,11 +1730,11 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
|
|||||||
|
|
||||||
const bool has_connectors = !mo->cut_connectors.empty();
|
const bool has_connectors = !mo->cut_connectors.empty();
|
||||||
{
|
{
|
||||||
|
Plater::TakeSnapshot snapshot(plater, _L("Cut by Plane"));
|
||||||
// update connectors pos as offset of its center before cut performing
|
// update connectors pos as offset of its center before cut performing
|
||||||
if (has_connectors && m_connector_mode == CutConnectorMode::Manual) {
|
if (has_connectors && m_connector_mode == CutConnectorMode::Manual) {
|
||||||
m_selected.clear();
|
m_selected.clear();
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(plater, _L("Cut by Plane"));
|
|
||||||
for (CutConnector& connector : mo->cut_connectors) {
|
for (CutConnector& connector : mo->cut_connectors) {
|
||||||
connector.rotation = rotation;
|
connector.rotation = rotation;
|
||||||
|
|
||||||
|
@ -5962,6 +5962,8 @@ void Slic3r::GUI::Plater::cut(size_t obj_idx, size_t instance_idx, const Vec3d&
|
|||||||
// suppress to call selection update for Object List to avoid call of early Gizmos on/off update
|
// suppress to call selection update for Object List to avoid call of early Gizmos on/off update
|
||||||
p->load_model_objects(new_objects, false, false);
|
p->load_model_objects(new_objects, false, false);
|
||||||
|
|
||||||
|
this->allow_snapshots();
|
||||||
|
|
||||||
// now process all updates of the 3d scene
|
// now process all updates of the 3d scene
|
||||||
update();
|
update();
|
||||||
// Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(),
|
// Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user