Merge branch 'lm_drilling_backend_rebased'

This commit is contained in:
Lukas Matena 2020-02-03 15:46:02 +01:00
commit 6a2604cfe0
14 changed files with 342 additions and 300 deletions

View file

@ -150,7 +150,16 @@ void minus(TriangleMesh &A, const TriangleMesh &B)
triangle_mesh_to_cgal(B, meshB.m); triangle_mesh_to_cgal(B, meshB.m);
CGALMesh meshResult; CGALMesh meshResult;
CGALProc::corefine_and_compute_difference(meshA.m, meshB.m, meshResult.m); bool success = false;
try {
success = CGALProc::corefine_and_compute_difference(meshA.m, meshB.m, meshResult.m,
CGALParams::throw_on_self_intersection(true), CGALParams::throw_on_self_intersection(true));
}
catch (const CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception&) {
success = false;
}
if (! success)
throw std::runtime_error("CGAL corefine_and_compute_difference failed");
A = cgal_to_triangle_mesh(meshResult.m); A = cgal_to_triangle_mesh(meshResult.m);
} }

View file

@ -122,10 +122,10 @@ void SLAPrint::clear()
} }
// Transformation without rotation around Z and without a shift by X and Y. // Transformation without rotation around Z and without a shift by X and Y.
static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object) Transform3d SLAPrint::sla_trafo(const ModelObject &model_object) const
{ {
Vec3d corr = p.relative_correction(); Vec3d corr = this->relative_correction();
ModelInstance &model_instance = *model_object.instances.front(); ModelInstance &model_instance = *model_object.instances.front();
Vec3d offset = model_instance.get_offset(); Vec3d offset = model_instance.get_offset();
@ -376,7 +376,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
bool sla_trafo_differs = bool sla_trafo_differs =
model_object.instances.empty() != model_object_new.instances.empty() || model_object.instances.empty() != model_object_new.instances.empty() ||
(! model_object.instances.empty() && (! model_object.instances.empty() &&
(! sla_trafo(*this, model_object).isApprox(sla_trafo(*this, model_object_new)) || (! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)) ||
model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed())); model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed()));
if (model_parts_differ || sla_trafo_differs) { if (model_parts_differ || sla_trafo_differs) {
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects. // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
@ -419,7 +419,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
if (model_object.sla_drain_holes != model_object_new.sla_drain_holes) if (model_object.sla_drain_holes != model_object_new.sla_drain_holes)
{ {
model_object.sla_drain_holes = model_object_new.sla_drain_holes; model_object.sla_drain_holes = model_object_new.sla_drain_holes;
update_apply_status(it_print_object_status->print_object->invalidate_step(slaposHollowing)); update_apply_status(it_print_object_status->print_object->invalidate_step(slaposDrillHoles));
} }
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
@ -453,7 +453,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
// FIXME: this invalidates the transformed mesh in SLAPrintObject // FIXME: this invalidates the transformed mesh in SLAPrintObject
// which is expensive to calculate (especially the raw_mesh() call) // which is expensive to calculate (especially the raw_mesh() call)
print_object->set_trafo(sla_trafo(*this, model_object), model_object.instances.front()->is_left_handed()); print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed());
print_object->set_instances(std::move(new_instances)); print_object->set_instances(std::move(new_instances));
@ -1101,6 +1101,8 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const
{ {
switch (step) { switch (step) {
case slaposDrillHoles:
return m_hollowing_data && !m_hollowing_data->hollow_mesh_with_holes.empty();
case slaposSupportTree: case slaposSupportTree:
return ! this->support_mesh().empty(); return ! this->support_mesh().empty();
case slaposPad: case slaposPad:
@ -1117,7 +1119,7 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const
return this->support_mesh(); return this->support_mesh();
case slaposPad: case slaposPad:
return this->pad_mesh(); return this->pad_mesh();
case slaposHollowing: case slaposDrillHoles:
if (m_hollowing_data) if (m_hollowing_data)
return m_hollowing_data->hollow_mesh_with_holes; return m_hollowing_data->hollow_mesh_with_holes;
[[fallthrough]]; [[fallthrough]];

View file

@ -78,7 +78,7 @@ public:
// Support mesh is only valid if this->is_step_done(slaposPad) is true. // Support mesh is only valid if this->is_step_done(slaposPad) is true.
const TriangleMesh& pad_mesh() const; const TriangleMesh& pad_mesh() const;
// Ready after this->is_step_done(slaposHollowing) is true // Ready after this->is_step_done(slaposDrillHoles) is true
const TriangleMesh& hollowed_interior_mesh() const; const TriangleMesh& hollowed_interior_mesh() const;
// Get the mesh that is going to be printed with all the modifications // Get the mesh that is going to be printed with all the modifications
@ -421,6 +421,9 @@ public:
// Extracted value from the configuration objects // Extracted value from the configuration objects
Vec3d relative_correction() const; Vec3d relative_correction() const;
// Return sla tansformation for a given model_object
Transform3d sla_trafo(const ModelObject &model_object) const;
std::string output_filename(const std::string &filename_base = std::string()) const override; std::string output_filename(const std::string &filename_base = std::string()) const override;
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; } const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }

View file

@ -27,7 +27,7 @@ namespace {
const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = { const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
10, // slaposHollowing, 10, // slaposHollowing,
10, // slaposDrillHolesIfHollowed 10, // slaposDrillHoles
10, // slaposObjectSlice, 10, // slaposObjectSlice,
20, // slaposSupportPoints, 20, // slaposSupportPoints,
10, // slaposSupportTree, 10, // slaposSupportTree,
@ -39,7 +39,7 @@ std::string OBJ_STEP_LABELS(size_t idx)
{ {
switch (idx) { switch (idx) {
case slaposHollowing: return L("Hollowing model"); case slaposHollowing: return L("Hollowing model");
case slaposDrillHoles: return L("Drilling holes into hollowed model."); case slaposDrillHoles: return L("Drilling holes into model.");
case slaposObjectSlice: return L("Slicing model"); case slaposObjectSlice: return L("Slicing model");
case slaposSupportPoints: return L("Generating support points"); case slaposSupportPoints: return L("Generating support points");
case slaposSupportTree: return L("Generating support tree"); case slaposSupportTree: return L("Generating support tree");
@ -80,6 +80,7 @@ SLAPrint::Steps::Steps(SLAPrint *print)
void SLAPrint::Steps::hollow_model(SLAPrintObject &po) void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
{ {
po.m_hollowing_data.reset(); po.m_hollowing_data.reset();
if (! po.m_config.hollowing_enable.getBool()) { if (! po.m_config.hollowing_enable.getBool()) {
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
return; return;

View file

@ -314,32 +314,37 @@ public:
std::pair<size_t, size_t> geometry_id; std::pair<size_t, size_t> geometry_id;
// An ID containing the extruder ID (used to select color). // An ID containing the extruder ID (used to select color).
int extruder_id; int extruder_id;
// Various boolean flags.
struct {
// Is this object selected? // Is this object selected?
bool selected; bool selected : 1;
// Is this object disabled from selection? // Is this object disabled from selection?
bool disabled; bool disabled : 1;
// Is this object printable? // Is this object printable?
bool printable; bool printable : 1;
// Whether or not this volume is active for rendering // Whether or not this volume is active for rendering
bool is_active; bool is_active : 1;
// Whether or not to use this volume when applying zoom_to_volumes() // Whether or not to use this volume when applying zoom_to_volumes()
bool zoom_to_volumes; bool zoom_to_volumes : 1;
// Wheter or not this volume is enabled for outside print volume detection in shader. // Wheter or not this volume is enabled for outside print volume detection in shader.
bool shader_outside_printer_detection_enabled; bool shader_outside_printer_detection_enabled : 1;
// Wheter or not this volume is outside print volume. // Wheter or not this volume is outside print volume.
bool is_outside; bool is_outside : 1;
// Wheter or not this volume has been generated from a modifier
bool is_modifier : 1;
// Wheter or not this volume has been generated from the wipe tower
bool is_wipe_tower : 1;
// Wheter or not this volume has been generated from an extrusion path
bool is_extrusion_path : 1;
// Wheter or not to always render this volume using its own alpha
bool force_transparent : 1;
// Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE)
bool force_native_color : 1;
};
// Is mouse or rectangle selection over this object to select/deselect it ? // Is mouse or rectangle selection over this object to select/deselect it ?
EHoverState hover; EHoverState hover;
// Wheter or not this volume has been generated from a modifier
bool is_modifier;
// Wheter or not this volume has been generated from the wipe tower
bool is_wipe_tower;
// Wheter or not this volume has been generated from an extrusion path
bool is_extrusion_path;
// Wheter or not to always render this volume using its own alpha
bool force_transparent;
// Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE)
bool force_native_color;
// Interleaved triangles & normals with indexed triangles & quads. // Interleaved triangles & normals with indexed triangles & quads.
GLIndexedVertexArray indexed_vertex_array; GLIndexedVertexArray indexed_vertex_array;

View file

@ -1977,8 +1977,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
}; };
// SLA steps to pull the preview meshes for. // SLA steps to pull the preview meshes for.
typedef std::array<SLAPrintObjectStep, 2> SLASteps; typedef std::array<SLAPrintObjectStep, 3> SLASteps;
SLASteps sla_steps = { slaposSupportTree, slaposPad }; SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad };
struct SLASupportState { struct SLASupportState {
std::array<PrintStateBase::StateWithTimeStamp, std::tuple_size<SLASteps>::value> step; std::array<PrintStateBase::StateWithTimeStamp, std::tuple_size<SLASteps>::value> step;
}; };
@ -2025,7 +2025,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
// Consider the DONE step without a valid mesh as invalid for the purpose // Consider the DONE step without a valid mesh as invalid for the purpose
// of mesh visualization. // of mesh visualization.
state.step[istep].state = PrintStateBase::INVALID; state.step[istep].state = PrintStateBase::INVALID;
else else if (sla_steps[istep] != slaposDrillHoles)
for (const ModelInstance* model_instance : print_object->model_object()->instances) for (const ModelInstance* model_instance : print_object->model_object()->instances)
// Only the instances, which are currently printable, will have the SLA support structures kept. // Only the instances, which are currently printable, will have the SLA support structures kept.
// The instances outside the print bed will have the GLVolumes of their support structures released. // The instances outside the print bed will have the GLVolumes of their support structures released.
@ -2038,7 +2038,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower); std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower); std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower);
// Release all ModelVolume based GLVolumes not found in the current Model. // Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++volume_id) { for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++volume_id) {
GLVolume* volume = m_volumes.volumes[volume_id]; GLVolume* volume = m_volumes.volumes[volume_id];
ModelVolumeState key(volume); ModelVolumeState key(volume);
@ -2120,6 +2120,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
if (it_old_volume != deleted_volumes.end() && it_old_volume->composite_id == it->composite_id) if (it_old_volume != deleted_volumes.end() && it_old_volume->composite_id == it->composite_id)
// If a volume changed its ObjectID, but it reuses a GLVolume's CompositeID, maintain its selection. // If a volume changed its ObjectID, but it reuses a GLVolume's CompositeID, maintain its selection.
map_glvolume_old_to_new[it_old_volume->volume_idx] = m_volumes.volumes.size(); map_glvolume_old_to_new[it_old_volume->volume_idx] = m_volumes.volumes.size();
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
// later in this function.
it->volume_idx = m_volumes.volumes.size();
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized); m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized);
m_volumes.volumes.back()->geometry_id = key.geometry_id; m_volumes.volumes.back()->geometry_id = key.geometry_id;
update_object_list = true; update_object_list = true;
@ -2148,8 +2151,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
const ModelObject *model_object = print_object->model_object(); const ModelObject *model_object = print_object->model_object();
// Find an index of the ModelObject // Find an index of the ModelObject
int object_idx; int object_idx;
if (std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; }))
continue;
// There may be new SLA volumes added to the scene for this print_object. // There may be new SLA volumes added to the scene for this print_object.
// Find the object index of this print_object in the Model::objects list. // Find the object index of this print_object in the Model::objects list.
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object); auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
@ -2168,7 +2169,35 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(it != model_object->instances.end()); assert(it != model_object->instances.end());
int instance_idx = it - model_object->instances.begin(); int instance_idx = it - model_object->instances.begin();
for (size_t istep = 0; istep < sla_steps.size(); ++ istep) for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
if (sla_steps[istep] == slaposDrillHoles) {
// Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance,
// not into its own GLVolume.
// There shall always be such a GLVolume allocated.
ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id);
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
assert(!it->new_geometry());
GLVolume &volume = *m_volumes.volumes[it->volume_idx];
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
volume.indexed_vertex_array.release_geometry();
if (state.step[istep].state == PrintStateBase::DONE) { if (state.step[istep].state == PrintStateBase::DONE) {
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
assert(! mesh.empty());
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
volume.indexed_vertex_array.load_mesh(mesh);
} else {
// Reload the original volume.
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
}
volume.finalize_geometry(true);
}
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
// of various concenrs (model vs. 3D print path).
volume.offsets = { state.step[istep].timestamp };
} else if (state.step[istep].state == PrintStateBase::DONE) {
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id); assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
@ -2179,8 +2208,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx)); instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
else else
shift_zs[object_idx] = 0.; shift_zs[object_idx] = 0.;
} } else {
else {
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model. // Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
@ -2188,9 +2216,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
} }
// // stores the current volumes count
// size_t volumes_count = m_volumes.volumes.size();
for (size_t istep = 0; istep < sla_steps.size(); ++istep) for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty()) if (!instances[istep].empty())
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
@ -6081,8 +6106,6 @@ void GLCanvas3D::_load_sla_shells()
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) { for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true); add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true);
// if (! obj->hollowed_interior_mesh().empty())
// add_volume(*obj, -int(slaposHollowing), instance, obj->hollowed_interior_mesh(), GLVolume::MODEL_COLOR[0], false);
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call. // through the update_volumes_colors_by_extruder() call.
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id(); m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();

View file

@ -4,6 +4,9 @@
#include <GL/glew.h> #include <GL/glew.h>
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
@ -302,5 +305,87 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr
return b; return b;
} }
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
{
recent_update = false;
if (m_model_object != model_object
|| (model_object && m_model_object_id != model_object->id())) {
m_model_object = model_object;
m_print_object_idx = -1;
m_mesh_raycaster.reset();
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = nullptr;
m_mesh = nullptr;
m_backend_mesh_transformed.clear();
if (m_model_object) {
m_active_instance = canvas.get_selection().get_instance_idx();
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
}
recent_update = true;
}
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
return false;
int old_po_idx = m_print_object_idx;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = canvas.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
m_mesh = nullptr;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if (m_print_object_idx >=0) {
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
if (po->is_step_done(slaposDrillHoles)) {
m_backend_mesh_transformed = po->get_mesh_to_print();
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
m_mesh = &m_backend_mesh_transformed;
}
}
if (! m_mesh) {
m_mesh = &m_model_object->volumes.front()->mesh();
m_backend_mesh_transformed.clear();
}
m_model_object_id = m_model_object->id();
if (m_mesh != m_old_mesh) {
wxBusyCursor wait;
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = m_mesh;
m_clipping_plane_distance = 0.f;
m_clipping_plane_distance_stash = 0.f;
recent_update = true;
return true;
}
if (! recent_update)
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
return m_print_object_idx < 0 ? old_po_idx >=0 : false;
}
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View file

@ -31,6 +31,8 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
class ImGuiWrapper; class ImGuiWrapper;
class CommonGizmosData; class CommonGizmosData;
class GLCanvas3D;
class ClippingPlane;
class GLGizmoBase class GLGizmoBase
{ {
@ -189,9 +191,13 @@ class MeshClipper;
class CommonGizmosData { class CommonGizmosData {
public: public:
const TriangleMesh* mesh() const { const TriangleMesh* mesh() const {
return (! m_mesh ? nullptr : (m_cavity_mesh ? m_cavity_mesh.get() : m_mesh)); return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
} }
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
bool recent_update = false;
ModelObject* m_model_object = nullptr; ModelObject* m_model_object = nullptr;
@ -200,8 +206,8 @@ public:
std::unique_ptr<MeshClipper> m_object_clipper; std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper; std::unique_ptr<MeshClipper> m_supports_clipper;
std::unique_ptr<TriangleMesh> m_cavity_mesh; //std::unique_ptr<TriangleMesh> m_cavity_mesh;
std::unique_ptr<GLVolume> m_volume_with_cavity; //std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1; int m_active_instance = -1;
float m_active_instance_bb_radius = 0; float m_active_instance_bb_radius = 0;
@ -209,6 +215,22 @@ public:
int m_print_object_idx = -1; int m_print_object_idx = -1;
int m_print_objects_count = -1; int m_print_objects_count = -1;
int m_old_timestamp = -1; int m_old_timestamp = -1;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
void stash_clipping_plane() {
m_clipping_plane_distance_stash = m_clipping_plane_distance;
}
void unstash_clipping_plane() {
m_clipping_plane_distance = m_clipping_plane_distance_stash;
}
private:
const TriangleMesh* m_old_mesh;
TriangleMesh m_backend_mesh_transformed;
float m_clipping_plane_distance_stash = 0.f;
}; };
} // namespace GUI } // namespace GUI

View file

@ -22,7 +22,7 @@ GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filenam
: GLGizmoBase(parent, icon_filename, sprite_id, cd) : GLGizmoBase(parent, icon_filename, sprite_id, cd)
, m_quadric(nullptr) , m_quadric(nullptr)
{ {
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_quadric = ::gluNewQuadric(); m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr) if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation // using GLU_FILL does not work when the instance's transformation
@ -40,7 +40,7 @@ bool GLGizmoHollow::on_init()
{ {
m_shortcut_key = WXK_CONTROL_H; m_shortcut_key = WXK_CONTROL_H;
m_desc["enable"] = _(L("Hollow this object")); m_desc["enable"] = _(L("Hollow this object"));
m_desc["preview"] = _(L("Preview")); m_desc["preview"] = _(L("Preview hollowed and drilled model"));
m_desc["offset"] = _(L("Offset")) + ": "; m_desc["offset"] = _(L("Offset")) + ": ";
m_desc["quality"] = _(L("Quality")) + ": "; m_desc["quality"] = _(L("Quality")) + ": ";
m_desc["closing_distance"] = _(L("Closing distance")) + ": "; m_desc["closing_distance"] = _(L("Closing distance")) + ": ";
@ -55,38 +55,16 @@ bool GLGizmoHollow::on_init()
return true; return true;
} }
void GLGizmoHollow::set_sla_support_data(ModelObject* model_object, const Selection& selection) void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
{ {
if (! model_object || selection.is_empty()) { if (m_c->recent_update) {
m_c->m_model_object = nullptr;
return;
}
bool something_changed = false; if (m_c->m_model_object)
if (m_c->m_model_object != model_object
|| m_c->m_model_object_id != model_object->id()
|| m_c->m_active_instance != selection.get_instance_idx()) {
m_c->m_model_object = model_object;
m_c->m_print_object_idx = -1;
m_c->m_active_instance = selection.get_instance_idx();
something_changed = true;
}
if (model_object && something_changed && selection.is_from_single_instance())
{
// Cache the bb - it's needed for dealing with the clipping plane quite often
// It could be done inside update_mesh but one has to account for scaling of the instance.
m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius();
if (is_mesh_update_necessary()) {
update_mesh();
reload_cache(); reload_cache();
}
if (m_state == On) { if (m_state == On) {
m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
} }
else else
@ -109,8 +87,8 @@ void GLGizmoHollow::on_render() const
return; return;
} }
if (! m_c->m_mesh) // !!! is it necessary?
const_cast<GLGizmoHollow*>(this)->update_mesh(); //const_cast<GLGizmoHollow*>(this)->m_c->update_from_backend(m_parent, m_c->m_model_object);
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
@ -132,7 +110,7 @@ void GLGizmoHollow::on_render() const
void GLGizmoHollow::render_hollowed_mesh() const void GLGizmoHollow::render_hollowed_mesh() const
{ {
if (m_c->m_volume_with_cavity) { /*if (m_c->m_volume_with_cavity) {
m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift); m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift);
m_parent.get_shader().start_using(); m_parent.get_shader().start_using();
@ -148,14 +126,13 @@ void GLGizmoHollow::render_hollowed_mesh() const
m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation()); m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation());
m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id); m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using(); m_parent.get_shader().stop_using();
} }*/
} }
void GLGizmoHollow::render_clipping_plane(const Selection& selection) const void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
{ {
if (m_clipping_plane_distance == 0.f || m_c->mesh()->empty()) if (m_c->m_clipping_plane_distance == 0.f)
return; return;
// Get transformation of the instance // Get transformation of the instance
@ -177,22 +154,14 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
m_c->m_object_clipper.reset(new MeshClipper); m_c->m_object_clipper.reset(new MeshClipper);
m_c->m_object_clipper->set_mesh(*m_c->mesh()); m_c->m_object_clipper->set_mesh(*m_c->mesh());
} }
m_c->m_object_clipper->set_plane(*m_clipping_plane); m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane);
m_c->m_object_clipper->set_transformation(trafo); m_c->m_object_clipper->set_transformation(trafo);
// Next, ask the backend if supports are already calculated. If so, we are gonna cut them too. // Next, ask the backend if supports are already calculated. If so, we are gonna cut them too.
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is //if (m_c->m_print_object_idx < 0)
// cached so we don't have todo it on each render. We only search for the po if needed: // m_c->update_from_backend(m_parent, m_c->m_model_object);
if (m_c->m_print_object_idx < 0 || (int)m_parent.sla_print()->objects().size() != m_c->m_print_objects_count) {
m_c->m_print_objects_count = m_parent.sla_print()->objects().size();
m_c->m_print_object_idx = -1;
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
++m_c->m_print_object_idx;
if (po->model_object()->id() == m_c->m_model_object->id())
break;
}
}
if (m_c->m_print_object_idx >= 0) { if (m_c->m_print_object_idx >= 0) {
const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx]; const SLAPrintObject* print_object = m_parent.sla_print()->objects()[m_c->m_print_object_idx];
@ -208,7 +177,7 @@ void GLGizmoHollow::render_clipping_plane(const Selection& selection) const
m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); m_c->m_supports_clipper->set_mesh(print_object->support_mesh());
m_c->m_old_timestamp = timestamp; m_c->m_old_timestamp = timestamp;
} }
m_c->m_supports_clipper->set_plane(*m_clipping_plane); m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane);
m_c->m_supports_clipper->set_transformation(supports_trafo); m_c->m_supports_clipper->set_transformation(supports_trafo);
} }
else else
@ -345,46 +314,12 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const
{ {
if (m_clipping_plane_distance == 0.f) if (m_c->m_clipping_plane_distance == 0.f)
return false; return false;
Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point;
transformed_point(2) += m_z_shift; transformed_point(2) += m_z_shift;
return m_clipping_plane->is_point_clipped(transformed_point); return m_c->m_clipping_plane->is_point_clipped(transformed_point);
}
bool GLGizmoHollow::is_mesh_update_necessary() const
{
return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty())
&& ((m_c->m_model_object->id() != m_c->m_model_object_id) || ! m_c->m_mesh);
}
void GLGizmoHollow::update_mesh()
{
if (! m_c->m_model_object)
return;
wxBusyCursor wait;
// this way we can use that mesh directly.
// This mesh does not account for the possible Z up SLA offset.
m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh();
// If this is different mesh than last time
if (m_c->m_model_object_id != m_c->m_model_object->id()) {
m_c->m_cavity_mesh.reset(); // dump the cavity
m_c->m_volume_with_cavity.reset();
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_c->m_mesh_raycaster.reset();
}
if (! m_c->m_mesh_raycaster)
m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
m_c->m_model_object_id = m_c->m_model_object->id();
} }
@ -393,9 +328,11 @@ void GLGizmoHollow::update_mesh()
// Return false if no intersection was found, true otherwise. // Return false if no intersection was found, true otherwise.
bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal) bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
{ {
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
if (! m_c->m_mesh_raycaster) if (! m_c->m_mesh_raycaster)
update_mesh(); return false;
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
// !!! is it really necessary?
//m_c->update_from_backend(m_parent, m_c->m_model_object);
const Camera& camera = m_parent.get_camera(); const Camera& camera = m_parent.get_camera();
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
@ -406,7 +343,7 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V
// The raycaster query // The raycaster query
Vec3f hit; Vec3f hit;
Vec3f normal; Vec3f normal;
if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_c->m_clipping_plane.get())) {
// Return both the point and the facet normal. // Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal); pos_and_normal = std::make_pair(hit, normal);
return true; return true;
@ -492,7 +429,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
points_inside.push_back(points[idx].cast<float>()); points_inside.push_back(points[idx].cast<float>());
// Only select/deselect points that are actually visible // Only select/deselect points that are actually visible
for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get())) for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get()))
{ {
if (rectangle_status == GLSelectionRectangle::Deselect) if (rectangle_status == GLSelectionRectangle::Deselect)
unselect_point(points_idxs[idx]); unselect_point(points_idxs[idx]);
@ -546,13 +483,13 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
} }
if (action == SLAGizmoEventType::MouseWheelUp && control_down) { if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
update_clipping_plane(true); update_clipping_plane(true);
return true; return true;
} }
if (action == SLAGizmoEventType::MouseWheelDown && control_down) { if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f);
update_clipping_plane(true); update_clipping_plane(true);
return true; return true;
} }
@ -605,7 +542,7 @@ void GLGizmoHollow::update_mesh_raycaster(std::unique_ptr<MeshRaycaster> &&rc)
{ {
m_c->m_mesh_raycaster = std::move(rc); m_c->m_mesh_raycaster = std::move(rc);
m_c->m_object_clipper.reset(); m_c->m_object_clipper.reset();
m_c->m_volume_with_cavity.reset(); //m_c->m_volume_with_cavity.reset();
} }
void GLGizmoHollow::hollow_mesh(bool postpone_error_messages) void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
@ -622,7 +559,7 @@ void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh) void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
{ {
// Called from Plater when the UI job finishes // Called from Plater when the UI job finishes
m_c->m_cavity_mesh = std::move(mesh); /*m_c->m_cavity_mesh = std::move(mesh);
if(m_c->m_cavity_mesh) { if(m_c->m_cavity_mesh) {
// First subtract the holes: // First subtract the holes:
@ -665,10 +602,10 @@ void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh())); m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
} }
if (m_clipping_plane_distance == 0.f) { if (m_c->m_clipping_plane_distance == 0.f) {
m_clipping_plane_distance = 0.5f; m_c->m_clipping_plane_distance = 0.5f;
update_clipping_plane(); update_clipping_plane();
} }*/
} }
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const
@ -701,10 +638,10 @@ std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> GLGizmoHollo
ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const ClippingPlane GLGizmoHollow::get_sla_clipping_plane() const
{ {
if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f)
return ClippingPlane::ClipsNothing(); return ClippingPlane::ClipsNothing();
else else
return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]);
} }
@ -724,18 +661,24 @@ RENDER_AGAIN:
// First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that: // First calculate width of all the texts that are could possibly be shown. We will decide set the dialog width based on that:
const float settings_sliders_left = const float settings_sliders_left =
std::max(std::max(m_imgui->calc_text_size(m_desc.at("offset")).x, std::max({m_imgui->calc_text_size(m_desc.at("offset")).x,
m_imgui->calc_text_size(m_desc.at("quality")).x), m_imgui->calc_text_size(m_desc.at("quality")).x,
m_imgui->calc_text_size(m_desc.at("closing_distance")).x) m_imgui->calc_text_size(m_desc.at("closing_distance")).x,
m_imgui->calc_text_size(m_desc.at("hole_diameter")).x,
m_imgui->calc_text_size(m_desc.at("hole_depth")).x})
+ m_imgui->scaled(1.f); + m_imgui->scaled(1.f);
const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f); const float clipping_slider_left = std::max(m_imgui->calc_text_size(m_desc.at("clipping_of_view")).x, m_imgui->calc_text_size(m_desc.at("reset_direction")).x) + m_imgui->scaled(1.5f);
const float diameter_slider_left = m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f); const float diameter_slider_left = settings_sliders_left; //m_imgui->calc_text_size(m_desc.at("hole_diameter")).x + m_imgui->scaled(1.f);
const float minimal_slider_width = m_imgui->scaled(4.f); const float minimal_slider_width = m_imgui->scaled(4.f);
//const float buttons_width_approx = m_imgui->calc_text_size(m_desc.at("apply_changes")).x + m_imgui->calc_text_size(m_desc.at("discard_changes")).x + m_imgui->scaled(1.5f);
float window_width = minimal_slider_width + std::max(std::max(settings_sliders_left, clipping_slider_left), diameter_slider_left); float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left});
window_width = std::max(std::max(window_width, /*buttons_width_approx*/0.f), 0.f); window_width = std::max(window_width, m_imgui->calc_text_size(m_desc.at("preview")).x);
if (m_imgui->button(m_desc["preview"]))
hollow_mesh();
ImGui::Separator();
{ {
auto opts = get_config_options({"hollowing_enable"}); auto opts = get_config_options({"hollowing_enable"});
@ -745,11 +688,8 @@ RENDER_AGAIN:
wxGetApp().obj_list()->update_and_show_object_settings_item(); wxGetApp().obj_list()->update_and_show_object_settings_item();
} }
} }
m_imgui->disabled_begin(! m_enable_hollowing);
ImGui::SameLine(); m_imgui->disabled_begin(! m_enable_hollowing);
if (m_imgui->button(m_desc["preview"]))
hollow_mesh();
std::vector<std::string> opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"}; std::vector<std::string> opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"};
auto opts = get_config_options(opts_keys); auto opts = get_config_options(opts_keys);
@ -834,7 +774,7 @@ RENDER_AGAIN:
// m_imgui->text(" "); // vertical gap // m_imgui->text(" "); // vertical gap
ImGui::Separator(); ImGui::Separator();
float diameter_upper_cap = 5.f; float diameter_upper_cap = 15.;
if (m_new_hole_radius > diameter_upper_cap) if (m_new_hole_radius > diameter_upper_cap)
m_new_hole_radius = diameter_upper_cap; m_new_hole_radius = diameter_upper_cap;
m_imgui->text(m_desc.at("hole_diameter")); m_imgui->text(m_desc.at("hole_diameter"));
@ -904,7 +844,7 @@ RENDER_AGAIN:
// Following is rendered in both editing and non-editing mode: // Following is rendered in both editing and non-editing mode:
// m_imgui->text(""); // m_imgui->text("");
ImGui::Separator(); ImGui::Separator();
if (m_clipping_plane_distance == 0.f) if (m_c->m_clipping_plane_distance == 0.f)
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));
else { else {
if (m_imgui->button(m_desc.at("reset_direction"))) { if (m_imgui->button(m_desc.at("reset_direction"))) {
@ -916,7 +856,7 @@ RENDER_AGAIN:
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left);
if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
update_clipping_plane(true); update_clipping_plane(true);
// make sure supports are shown/hidden as appropriate // make sure supports are shown/hidden as appropriate
@ -973,7 +913,7 @@ bool GLGizmoHollow::on_is_selectable() const
std::string GLGizmoHollow::on_get_name() const std::string GLGizmoHollow::on_get_name() const
{ {
return (_(L("Hollowing")) + " [H]").ToUTF8().data(); return (_(L("Hollowing and drilling")) + " [H]").ToUTF8().data();
} }
@ -995,17 +935,19 @@ void GLGizmoHollow::on_set_state()
if (m_state == On && m_old_state != On) { // the gizmo was just turned on if (m_state == On && m_old_state != On) { // the gizmo was just turned on
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
if (is_mesh_update_necessary()) //m_c->update_from_backend(m_parent, m_c->m_model_object);
update_mesh(); m_c->unstash_clipping_plane();
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
// we'll now reload support points: // we'll now reload support points:
if (m_c->m_model_object) if (m_c->m_model_object)
reload_cache(); reload_cache();
m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(false);
if (m_c->m_model_object) if (m_c->m_model_object) {
m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
// Set default head diameter from config. // Set default head diameter from config.
//const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; //const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
@ -1014,8 +956,9 @@ void GLGizmoHollow::on_set_state()
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); //Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));
m_parent.toggle_model_objects_visibility(true); m_parent.toggle_model_objects_visibility(true);
m_clipping_plane_distance = 0.f; m_c->stash_clipping_plane();
update_clipping_plane(); m_c->m_clipping_plane_distance = 0.f;
update_clipping_plane(true);
// Release clippers and the AABB raycaster. // Release clippers and the AABB raycaster.
m_c->m_object_clipper.reset(); m_c->m_object_clipper.reset();
m_c->m_supports_clipper.reset(); m_c->m_supports_clipper.reset();
@ -1060,8 +1003,8 @@ void GLGizmoHollow::on_stop_dragging()
void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar) void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
{ {
ar(m_clipping_plane_distance, ar(m_c->m_clipping_plane_distance,
*m_clipping_plane, *m_c->m_clipping_plane,
m_c->m_model_object_id, m_c->m_model_object_id,
m_new_hole_radius, m_new_hole_radius,
m_new_hole_height, m_new_hole_height,
@ -1074,8 +1017,8 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const
{ {
ar(m_clipping_plane_distance, ar(m_c->m_clipping_plane_distance,
*m_clipping_plane, *m_c->m_clipping_plane,
m_c->m_model_object_id, m_c->m_model_object_id,
m_new_hole_radius, m_new_hole_radius,
m_new_hole_height, m_new_hole_height,
@ -1128,12 +1071,14 @@ void GLGizmoHollow::reload_cache()
void GLGizmoHollow::update_clipping_plane(bool keep_normal) const void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
{ {
Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? if (! m_c->m_model_object)
m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); return;
Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
float dist = normal.dot(center); float dist = normal.dot(center);
*m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius));
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }

View file

@ -53,14 +53,12 @@ private:
void render_points(const Selection& selection, bool picking = false) const; void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const; void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const; void render_hollowed_mesh() const;
bool is_mesh_update_necessary() const;
void update_mesh();
void hollow_mesh(bool postpone_error_messages = false); void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const; bool unsaved_changes() const;
bool m_show_supports = true; bool m_show_supports = true;
float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 5.f; float m_new_hole_height = 6.f;
mutable std::vector<bool> m_selected; // which holes are currently selected mutable std::vector<bool> m_selected; // which holes are currently selected
bool m_enable_hollowing = true; bool m_enable_hollowing = true;
@ -72,13 +70,9 @@ private:
float m_closing_d_stash = 2.f; float m_closing_d_stash = 2.f;
Vec3f m_hole_before_drag = Vec3f::Zero(); Vec3f m_hole_before_drag = Vec3f::Zero();
sla::DrainHoles m_holes_stash; sla::DrainHoles m_holes_stash;
//std::unique_ptr<ClippingPlane> m_clipping_plane;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View file

@ -27,7 +27,7 @@ GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& ic
, m_quadric(nullptr) , m_quadric(nullptr)
, m_its(nullptr) , m_its(nullptr)
{ {
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.)); m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_quadric = ::gluNewQuadric(); m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr) if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation // using GLU_FILL does not work when the instance's transformation
@ -63,43 +63,22 @@ bool GLGizmoSlaSupports::on_init()
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection) void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
{ {
if (! model_object || selection.is_empty()) { if (m_c->recent_update) {
m_c->m_model_object = nullptr;
return;
}
bool something_changed = false;
if (m_c->m_model_object != model_object
|| m_c->m_model_object_id != model_object->id()
|| m_c->m_active_instance != selection.get_instance_idx()) {
m_c->m_model_object = model_object;
m_c->m_print_object_idx = -1;
m_c->m_active_instance = selection.get_instance_idx();
something_changed = true;
}
if (model_object && selection.is_from_single_instance())
{
// Cache the bb - it's needed for dealing with the clipping plane quite often
// It could be done inside update_mesh but one has to account for scaling of the instance.
if (something_changed) {
m_c->m_active_instance_bb_radius = m_c->m_model_object->instance_bounding_box(m_c->m_active_instance).radius();
if (m_state == On) { if (m_state == On) {
m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(! m_c->m_cavity_mesh, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
} }
else else
m_parent.toggle_model_objects_visibility(true, nullptr, -1); m_parent.toggle_model_objects_visibility(true, nullptr, -1);
}
if (is_mesh_update_necessary()) { disable_editing_mode();
update_mesh(); if (m_c->m_model_object)
reload_cache(); reload_cache();
} }
// If we triggered autogeneration before, check backend and fetch results if they are there // If we triggered autogeneration before, check backend and fetch results if they are there
if (m_c->m_model_object) {
if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating) if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)
get_data_from_backend(); get_data_from_backend();
} }
@ -120,9 +99,6 @@ void GLGizmoSlaSupports::on_render() const
return; return;
} }
if (! m_its || ! m_c->m_mesh)
const_cast<GLGizmoSlaSupports*>(this)->update_mesh();
glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
@ -143,7 +119,7 @@ void GLGizmoSlaSupports::on_render() const
void GLGizmoSlaSupports::render_hollowed_mesh() const void GLGizmoSlaSupports::render_hollowed_mesh() const
{ {
if (m_c->m_volume_with_cavity) { /*if (m_c->m_volume_with_cavity) {
m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift); m_c->m_volume_with_cavity->set_sla_shift_z(m_z_shift);
m_parent.get_shader().start_using(); m_parent.get_shader().start_using();
@ -159,14 +135,14 @@ void GLGizmoSlaSupports::render_hollowed_mesh() const
m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation()); m_c->m_volume_with_cavity->set_instance_transformation(m_c->m_model_object->instances[size_t(m_c->m_active_instance)]->get_transformation());
m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id); m_c->m_volume_with_cavity->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using(); m_parent.get_shader().stop_using();
} }*/
} }
void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
{ {
if (m_clipping_plane_distance == 0.f || m_c->m_mesh->empty()) if (m_c->m_clipping_plane_distance == 0.f || m_c->m_mesh->empty())
return; return;
// Get transformation of the instance // Get transformation of the instance
@ -188,7 +164,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
m_c->m_object_clipper.reset(new MeshClipper); m_c->m_object_clipper.reset(new MeshClipper);
m_c->m_object_clipper->set_mesh(*m_c->mesh()); m_c->m_object_clipper->set_mesh(*m_c->mesh());
} }
m_c->m_object_clipper->set_plane(*m_clipping_plane); m_c->m_object_clipper->set_plane(*m_c->m_clipping_plane);
m_c->m_object_clipper->set_transformation(trafo); m_c->m_object_clipper->set_transformation(trafo);
@ -219,7 +195,7 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
m_c->m_supports_clipper->set_mesh(print_object->support_mesh()); m_c->m_supports_clipper->set_mesh(print_object->support_mesh());
m_c->m_old_timestamp = timestamp; m_c->m_old_timestamp = timestamp;
} }
m_c->m_supports_clipper->set_plane(*m_clipping_plane); m_c->m_supports_clipper->set_plane(*m_c->m_clipping_plane);
m_c->m_supports_clipper->set_transformation(supports_trafo); m_c->m_supports_clipper->set_transformation(supports_trafo);
} }
else else
@ -359,7 +335,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
} }
// Now render the drain holes: // Now render the drain holes:
if (! m_c->m_cavity_mesh) { /*if (! m_c->m_cavity_mesh) {
render_color[0] = 0.7f; render_color[0] = 0.7f;
render_color[1] = 0.7f; render_color[1] = 0.7f;
render_color[2] = 0.7f; render_color[2] = 0.7f;
@ -394,7 +370,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glFrontFace(GL_CCW); glFrontFace(GL_CCW);
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
} }
} }*/
if (!picking) if (!picking)
glsafe(::glDisable(GL_LIGHTING)); glsafe(::glDisable(GL_LIGHTING));
@ -406,51 +382,22 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
{ {
if (m_clipping_plane_distance == 0.f) if (m_c->m_clipping_plane_distance == 0.f)
return false; return false;
Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point; Vec3d transformed_point = m_c->m_model_object->instances[m_c->m_active_instance]->get_transformation().get_matrix() * point;
transformed_point(2) += m_z_shift; transformed_point(2) += m_z_shift;
return m_clipping_plane->is_point_clipped(transformed_point); return m_c->m_clipping_plane->is_point_clipped(transformed_point);
} }
bool GLGizmoSlaSupports::is_mesh_update_necessary() const
{
return ((m_state == On) && (m_c->m_model_object != nullptr) && !m_c->m_model_object->instances.empty())
&& ((m_c->m_model_object->id() != m_c->m_model_object_id) || m_its == nullptr);
}
void GLGizmoSlaSupports::update_mesh()
{
if (! m_c->m_model_object)
return;
wxBusyCursor wait;
// this way we can use that mesh directly.
// This mesh does not account for the possible Z up SLA offset.
m_c->m_mesh = &m_c->m_model_object->volumes.front()->mesh();
m_its = &m_c->m_mesh->its;
// If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
if (m_c->m_model_object_id != m_c->m_model_object->id() || ! m_c->m_mesh_raycaster)
m_c->m_mesh_raycaster.reset(new MeshRaycaster(*m_c->mesh()));
m_c->m_model_object_id = m_c->m_model_object->id();
disable_editing_mode();
}
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal // Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
// Return false if no intersection was found, true otherwise. // Return false if no intersection was found, true otherwise.
bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal) bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
{ {
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
if (! m_c->m_mesh_raycaster) if (! m_c->m_mesh_raycaster)
update_mesh(); return false;
const Camera& camera = m_parent.get_camera(); const Camera& camera = m_parent.get_camera();
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
@ -461,20 +408,20 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
// The raycaster query // The raycaster query
Vec3f hit; Vec3f hit;
Vec3f normal; Vec3f normal;
if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) { if (m_c->m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_c->m_clipping_plane.get())) {
// Check whether the hit is in a hole // Check whether the hit is in a hole
bool in_hole = false; bool in_hole = false;
// In case the hollowed and drilled mesh is available, we can allow // In case the hollowed and drilled mesh is available, we can allow
// placing points in holes, because they should never end up // placing points in holes, because they should never end up
// on surface that's been drilled away. // on surface that's been drilled away.
if (! m_c->m_cavity_mesh) { /*if (! m_c->m_cavity_mesh) {
for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) { for (const sla::DrainHole& hole : m_c->m_model_object->sla_drain_holes) {
if (hole.is_inside(hit)) { if (hole.is_inside(hit)) {
in_hole = true; in_hole = true;
break; break;
} }
} }
} }*/
if (! in_hole) { if (! in_hole) {
// Return both the point and the facet normal. // Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal); pos_and_normal = std::make_pair(hit, normal);
@ -555,7 +502,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
points_inside.push_back(points[idx].cast<float>()); points_inside.push_back(points[idx].cast<float>());
// Only select/deselect points that are actually visible // Only select/deselect points that are actually visible
for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get())) for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get()))
{ {
if (rectangle_status == GLSelectionRectangle::Deselect) if (rectangle_status == GLSelectionRectangle::Deselect)
unselect_point(points_idxs[idx]); unselect_point(points_idxs[idx]);
@ -632,13 +579,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
} }
if (action == SLAGizmoEventType::MouseWheelUp && control_down) { if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_clipping_plane_distance = std::min(1.f, m_clipping_plane_distance + 0.01f); m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
update_clipping_plane(true); update_clipping_plane(true);
return true; return true;
} }
if (action == SLAGizmoEventType::MouseWheelDown && control_down) { if (action == SLAGizmoEventType::MouseWheelDown && control_down) {
m_clipping_plane_distance = std::max(0.f, m_clipping_plane_distance - 0.01f); m_c->m_clipping_plane_distance = std::max(0.f, m_c->m_clipping_plane_distance - 0.01f);
update_clipping_plane(true); update_clipping_plane(true);
return true; return true;
} }
@ -719,10 +666,10 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const
{ {
if (!m_c->m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) if (!m_c->m_model_object || m_state == Off || m_c->m_clipping_plane_distance == 0.f)
return ClippingPlane::ClipsNothing(); return ClippingPlane::ClipsNothing();
else else
return ClippingPlane(-m_clipping_plane->get_normal(), m_clipping_plane->get_data()[3]); return ClippingPlane(-m_c->m_clipping_plane->get_normal(), m_c->m_clipping_plane->get_data()[3]);
} }
@ -944,7 +891,7 @@ RENDER_AGAIN:
// Following is rendered in both editing and non-editing mode: // Following is rendered in both editing and non-editing mode:
ImGui::Separator(); ImGui::Separator();
if (m_clipping_plane_distance == 0.f) if (m_c->m_clipping_plane_distance == 0.f)
{ {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view")); m_imgui->text(m_desc.at("clipping_of_view"));
@ -959,7 +906,7 @@ RENDER_AGAIN:
ImGui::SameLine(clipping_slider_left); ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left);
if (ImGui::SliderFloat(" ", &m_clipping_plane_distance, 0.f, 1.f, "%.2f")) if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
update_clipping_plane(true); update_clipping_plane(true);
@ -1043,15 +990,17 @@ void GLGizmoSlaSupports::on_set_state()
if (m_state == On && m_old_state != On) { // the gizmo was just turned on if (m_state == On && m_old_state != On) { // the gizmo was just turned on
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on"))); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
if (is_mesh_update_necessary())
update_mesh(); m_c->unstash_clipping_plane();
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
// we'll now reload support points: // we'll now reload support points:
if (m_c->m_model_object) if (m_c->m_model_object)
reload_cache(); reload_cache();
m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(false);
if (m_c->m_model_object && ! m_c->m_cavity_mesh) if (m_c->m_model_object /*&& ! m_c->m_cavity_mesh*/)
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance); m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
@ -1081,13 +1030,14 @@ void GLGizmoSlaSupports::on_set_state()
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off"))); Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));
m_parent.toggle_model_objects_visibility(true); m_parent.toggle_model_objects_visibility(true);
m_normal_cache.clear(); m_normal_cache.clear();
m_clipping_plane_distance = 0.f; m_c->stash_clipping_plane();
update_clipping_plane(); m_c->m_clipping_plane_distance = 0.f;
update_clipping_plane(true);
// Release clippers and the AABB raycaster. // Release clippers and the AABB raycaster.
m_its = nullptr; m_its = nullptr;
m_c->m_object_clipper.reset(); m_c->m_object_clipper.reset();
m_c->m_supports_clipper.reset(); m_c->m_supports_clipper.reset();
m_c->m_mesh_raycaster.reset(); //m_c->m_mesh_raycaster.reset();
} }
} }
m_old_state = m_state; m_old_state = m_state;
@ -1127,8 +1077,8 @@ void GLGizmoSlaSupports::on_stop_dragging()
void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar) void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
{ {
ar(m_clipping_plane_distance, ar(m_c->m_clipping_plane_distance,
*m_clipping_plane, *m_c->m_clipping_plane,
m_c->m_model_object_id, m_c->m_model_object_id,
m_new_point_head_diameter, m_new_point_head_diameter,
m_normal_cache, m_normal_cache,
@ -1141,8 +1091,8 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
{ {
ar(m_clipping_plane_distance, ar(m_c->m_clipping_plane_distance,
*m_clipping_plane, *m_c->m_clipping_plane,
m_c->m_model_object_id, m_c->m_model_object_id,
m_new_point_head_diameter, m_new_point_head_diameter,
m_normal_cache, m_normal_cache,
@ -1244,6 +1194,9 @@ void GLGizmoSlaSupports::reload_cache()
bool GLGizmoSlaSupports::has_backend_supports() const bool GLGizmoSlaSupports::has_backend_supports() const
{ {
if (! m_c->m_model_object)
return false;
// find SlaPrintObject with this ID // find SlaPrintObject with this ID
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
if (po->model_object()->id() == m_c->m_model_object->id()) if (po->model_object()->id() == m_c->m_model_object->id())
@ -1338,12 +1291,12 @@ bool GLGizmoSlaSupports::unsaved_changes() const
void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const
{ {
Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ? Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ?
m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift);
float dist = normal.dot(center); float dist = normal.dot(center);
*m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius)); *m_c->m_clipping_plane = ClippingPlane(normal, (dist - (-m_c->m_active_instance_bb_radius) - m_c->m_clipping_plane_distance * 2*m_c->m_active_instance_bb_radius));
m_parent.set_as_dirty(); m_parent.set_as_dirty();
} }

View file

@ -91,8 +91,6 @@ private:
void render_points(const Selection& selection, bool picking = false) const; void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const; void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const; void render_hollowed_mesh() const;
bool is_mesh_update_necessary() const;
void update_mesh();
bool unsaved_changes() const; bool unsaved_changes() const;
bool m_lock_unique_islands = false; bool m_lock_unique_islands = false;
@ -105,8 +103,7 @@ private:
mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected mutable std::vector<CacheEntry> m_editing_cache; // a support point and whether it is currently selected
std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo std::vector<sla::SupportPoint> m_normal_cache; // to restore after discarding changes or undo/redo
float m_clipping_plane_distance = 0.f; //std::unique_ptr<ClippingPlane> m_clipping_plane;
std::unique_ptr<ClippingPlane> m_clipping_plane;
// This map holds all translated description texts, so they can be easily referenced during layout calculations // This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect. // etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View file

@ -348,6 +348,9 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
if (!m_enabled || m_gizmos.empty()) if (!m_enabled || m_gizmos.empty())
return; return;
// Update common data for hollowing and sla support gizmos.
m_common_gizmos_data->update_from_backend(m_parent, model_object);
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection()); dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection());
dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_sla_support_data(model_object, m_parent.get_selection()); dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_sla_support_data(model_object, m_parent.get_selection());
} }

View file

@ -5130,7 +5130,7 @@ void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error
void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages) void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages)
{ {
reslice_SLA_until_step(slaposHollowing, object, postpone_error_messages); reslice_SLA_until_step(slaposDrillHoles, object, postpone_error_messages);
} }
void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages) void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages)