This commit is contained in:
Enrico Turri 2020-02-03 15:48:56 +01:00
commit f09bed32b6
14 changed files with 342 additions and 300 deletions

View file

@ -150,8 +150,17 @@ void minus(TriangleMesh &A, const TriangleMesh &B)
triangle_mesh_to_cgal(B, meshB.m);
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);
}

View file

@ -122,10 +122,10 @@ void SLAPrint::clear()
}
// 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();
Vec3d offset = model_instance.get_offset();
@ -376,7 +376,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
bool sla_trafo_differs =
model_object.instances.empty() != model_object_new.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()));
if (model_parts_differ || sla_trafo_differs) {
// 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)
{
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.
@ -453,7 +453,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
// FIXME: this invalidates the transformed mesh in SLAPrintObject
// 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));
@ -1101,6 +1101,8 @@ const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const
{
switch (step) {
case slaposDrillHoles:
return m_hollowing_data && !m_hollowing_data->hollow_mesh_with_holes.empty();
case slaposSupportTree:
return ! this->support_mesh().empty();
case slaposPad:
@ -1117,7 +1119,7 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const
return this->support_mesh();
case slaposPad:
return this->pad_mesh();
case slaposHollowing:
case slaposDrillHoles:
if (m_hollowing_data)
return m_hollowing_data->hollow_mesh_with_holes;
[[fallthrough]];

View file

@ -78,7 +78,7 @@ public:
// Support mesh is only valid if this->is_step_done(slaposPad) is true.
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;
// Get the mesh that is going to be printed with all the modifications
@ -421,6 +421,9 @@ public:
// Extracted value from the configuration objects
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;
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }

View file

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

View file

@ -313,33 +313,38 @@ public:
// Valid geometry_id should always be positive.
std::pair<size_t, size_t> geometry_id;
// An ID containing the extruder ID (used to select color).
int extruder_id;
// Is this object selected?
bool selected;
// Is this object disabled from selection?
bool disabled;
// Is this object printable?
bool printable;
// Whether or not this volume is active for rendering
bool is_active;
// Whether or not to use this volume when applying zoom_to_volumes()
bool zoom_to_volumes;
// Wheter or not this volume is enabled for outside print volume detection in shader.
bool shader_outside_printer_detection_enabled;
// Wheter or not this volume is outside print volume.
bool is_outside;
int extruder_id;
// Various boolean flags.
struct {
// Is this object selected?
bool selected : 1;
// Is this object disabled from selection?
bool disabled : 1;
// Is this object printable?
bool printable : 1;
// Whether or not this volume is active for rendering
bool is_active : 1;
// Whether or not to use this volume when applying zoom_to_volumes()
bool zoom_to_volumes : 1;
// Wheter or not this volume is enabled for outside print volume detection in shader.
bool shader_outside_printer_detection_enabled : 1;
// Wheter or not this volume is outside print volume.
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 ?
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;
EHoverState hover;
// Interleaved triangles & normals with indexed triangles & quads.
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.
typedef std::array<SLAPrintObjectStep, 2> SLASteps;
SLASteps sla_steps = { slaposSupportTree, slaposPad };
typedef std::array<SLAPrintObjectStep, 3> SLASteps;
SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad };
struct SLASupportState {
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
// of mesh visualization.
state.step[istep].state = PrintStateBase::INVALID;
else
else if (sla_steps[istep] != slaposDrillHoles)
for (const ModelInstance* model_instance : print_object->model_object()->instances)
// 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.
@ -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(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) {
GLVolume* volume = m_volumes.volumes[volume_id];
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 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();
// 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.volumes.back()->geometry_id = key.geometry_id;
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();
// Find an index of the ModelObject
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.
// 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);
@ -2168,29 +2169,53 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(it != model_object->instances.end());
int instance_idx = it - model_object->instances.begin();
for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
if (state.step[istep].state == PrintStateBase::DONE) {
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);
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
if (it->new_geometry()) {
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) {
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);
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);
if (it->new_geometry()) {
// This can be an SLA support structure that should not be rendered (in case someone used undo
// to revert to before it was generated). If that's the case, we should not generate anything.
if (model_object->sla_points_status != sla::PointsStatus::NoPoints)
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
else
shift_zs[object_idx] = 0.;
} else {
// 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]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
}
else {
// 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]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
}
}
}
// // stores the current volumes count
// size_t volumes_count = m_volumes.volumes.size();
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty())
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();
for (const SLAPrintObject::Instance& instance : obj->instances()) {
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
// through the update_volumes_colors_by_extruder() call.
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();

View file

@ -4,6 +4,9 @@
#include <GL/glew.h>
#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;
}
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 Slic3r

View file

@ -31,6 +31,8 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
class ImGuiWrapper;
class CommonGizmosData;
class GLCanvas3D;
class ClippingPlane;
class GLGizmoBase
{
@ -189,9 +191,13 @@ class MeshClipper;
class CommonGizmosData {
public:
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;
@ -200,8 +206,8 @@ public:
std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper;
std::unique_ptr<TriangleMesh> m_cavity_mesh;
std::unique_ptr<GLVolume> m_volume_with_cavity;
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
//std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1;
float m_active_instance_bb_radius = 0;
@ -209,6 +215,22 @@ public:
int m_print_object_idx = -1;
int m_print_objects_count = -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

View file

@ -22,7 +22,7 @@ GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filenam
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
, 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();
if (m_quadric != nullptr)
// 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_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["quality"] = _(L("Quality")) + ": ";
m_desc["closing_distance"] = _(L("Closing distance")) + ": ";
@ -55,38 +55,16 @@ bool GLGizmoHollow::on_init()
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()) {
m_c->m_model_object = nullptr;
return;
}
if (m_c->recent_update) {
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 && 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();
if (m_c->m_model_object)
reload_cache();
}
if (m_state == On) {
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);
}
else
@ -109,8 +87,8 @@ void GLGizmoHollow::on_render() const
return;
}
if (! m_c->m_mesh)
const_cast<GLGizmoHollow*>(this)->update_mesh();
// !!! is it necessary?
//const_cast<GLGizmoHollow*>(this)->m_c->update_from_backend(m_parent, m_c->m_model_object);
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
@ -132,7 +110,7 @@ void GLGizmoHollow::on_render() 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_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->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using();
}
}*/
}
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;
// 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->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);
// 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
// cached so we don't have todo it on each render. We only search for the po if needed:
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)
// m_c->update_from_backend(m_parent, m_c->m_model_object);
if (m_c->m_print_object_idx >= 0) {
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_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);
}
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
{
if (m_clipping_plane_distance == 0.f)
if (m_c->m_clipping_plane_distance == 0.f)
return false;
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;
return 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();
return m_c->m_clipping_plane->is_point_clipped(transformed_point);
}
@ -393,9 +328,11 @@ void GLGizmoHollow::update_mesh()
// 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)
{
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
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 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
Vec3f hit;
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.
pos_and_normal = std::make_pair(hit, normal);
return true;
@ -492,7 +429,7 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
points_inside.push_back(points[idx].cast<float>());
// 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)
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) {
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);
return true;
}
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);
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_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)
@ -622,8 +559,8 @@ void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
void GLGizmoHollow::update_hollowed_mesh(std::unique_ptr<TriangleMesh> &&mesh)
{
// 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) {
// First subtract the holes:
if (! m_c->m_model_object->sla_drain_holes.empty()) {
@ -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()));
}
if (m_clipping_plane_distance == 0.f) {
m_clipping_plane_distance = 0.5f;
if (m_c->m_clipping_plane_distance == 0.f) {
m_c->m_clipping_plane_distance = 0.5f;
update_clipping_plane();
}
}*/
}
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
{
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();
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:
const float settings_sliders_left =
std::max(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("closing_distance")).x)
+ m_imgui->scaled(1.f);
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("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);
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 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);
window_width = std::max(std::max(window_width, /*buttons_width_approx*/0.f), 0.f);
float window_width = minimal_slider_width + std::max({settings_sliders_left, clipping_slider_left, diameter_slider_left});
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"});
@ -745,11 +688,8 @@ RENDER_AGAIN:
wxGetApp().obj_list()->update_and_show_object_settings_item();
}
}
m_imgui->disabled_begin(! m_enable_hollowing);
ImGui::SameLine();
if (m_imgui->button(m_desc["preview"]))
hollow_mesh();
m_imgui->disabled_begin(! m_enable_hollowing);
std::vector<std::string> opts_keys = {"hollowing_min_thickness", "hollowing_quality", "hollowing_closing_distance"};
auto opts = get_config_options(opts_keys);
@ -834,7 +774,7 @@ RENDER_AGAIN:
// m_imgui->text(" "); // vertical gap
ImGui::Separator();
float diameter_upper_cap = 5.f;
float diameter_upper_cap = 15.;
if (m_new_hole_radius > diameter_upper_cap)
m_new_hole_radius = diameter_upper_cap;
m_imgui->text(m_desc.at("hole_diameter"));
@ -904,7 +844,7 @@ RENDER_AGAIN:
// Following is rendered in both editing and non-editing mode:
// m_imgui->text("");
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"));
else {
if (m_imgui->button(m_desc.at("reset_direction"))) {
@ -916,7 +856,7 @@ RENDER_AGAIN:
ImGui::SameLine(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);
// 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
{
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
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
if (is_mesh_update_necessary())
update_mesh();
//m_c->update_from_backend(m_parent, m_c->m_model_object);
m_c->unstash_clipping_plane();
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
// we'll now reload support points:
if (m_c->m_model_object)
reload_cache();
m_parent.toggle_model_objects_visibility(false);
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_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
if (m_c->m_model_object) {
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);
}
// Set default head diameter from 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
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));
m_parent.toggle_model_objects_visibility(true);
m_clipping_plane_distance = 0.f;
update_clipping_plane();
m_c->stash_clipping_plane();
m_c->m_clipping_plane_distance = 0.f;
update_clipping_plane(true);
// Release clippers and the AABB raycaster.
m_c->m_object_clipper.reset();
m_c->m_supports_clipper.reset();
@ -1060,8 +1003,8 @@ void GLGizmoHollow::on_stop_dragging()
void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
{
ar(m_clipping_plane_distance,
*m_clipping_plane,
ar(m_c->m_clipping_plane_distance,
*m_c->m_clipping_plane,
m_c->m_model_object_id,
m_new_hole_radius,
m_new_hole_height,
@ -1074,8 +1017,8 @@ void GLGizmoHollow::on_load(cereal::BinaryInputArchive& ar)
void GLGizmoHollow::on_save(cereal::BinaryOutputArchive& ar) const
{
ar(m_clipping_plane_distance,
*m_clipping_plane,
ar(m_c->m_clipping_plane_distance,
*m_c->m_clipping_plane,
m_c->m_model_object_id,
m_new_hole_radius,
m_new_hole_height,
@ -1128,12 +1071,14 @@ void GLGizmoHollow::reload_cache()
void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
{
Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
if (! m_c->m_model_object)
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);
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();
}

View file

@ -53,14 +53,12 @@ private:
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const;
bool is_mesh_update_necessary() const;
void update_mesh();
void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const;
bool m_show_supports = true;
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
bool m_enable_hollowing = true;
@ -72,13 +70,9 @@ private:
float m_closing_d_stash = 2.f;
Vec3f m_hole_before_drag = Vec3f::Zero();
sla::DrainHoles m_holes_stash;
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
// 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_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();
if (m_quadric != nullptr)
// 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)
{
if (! model_object || selection.is_empty()) {
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) {
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_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
else
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
if (m_c->recent_update) {
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
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);
}
else
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
if (is_mesh_update_necessary()) {
update_mesh();
disable_editing_mode();
if (m_c->m_model_object)
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)
get_data_from_backend();
}
@ -120,9 +99,6 @@ void GLGizmoSlaSupports::on_render() const
return;
}
if (! m_its || ! m_c->m_mesh)
const_cast<GLGizmoSlaSupports*>(this)->update_mesh();
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
@ -143,7 +119,7 @@ void GLGizmoSlaSupports::on_render() 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_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->render(color_id, print_box_detection_id, print_box_worldmatrix_id);
m_parent.get_shader().stop_using();
}
}*/
}
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;
// 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->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);
@ -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_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);
}
else
@ -359,7 +335,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
}
// Now render the drain holes:
if (! m_c->m_cavity_mesh) {
/*if (! m_c->m_cavity_mesh) {
render_color[0] = 0.7f;
render_color[1] = 0.7f;
render_color[2] = 0.7f;
@ -394,7 +370,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glFrontFace(GL_CCW);
glsafe(::glPopMatrix());
}
}
}*/
if (!picking)
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
{
if (m_clipping_plane_distance == 0.f)
if (m_c->m_clipping_plane_distance == 0.f)
return false;
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;
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
// 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)
{
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
if (! m_c->m_mesh_raycaster)
update_mesh();
return false;
const Camera& camera = m_parent.get_camera();
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
Vec3f hit;
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
bool in_hole = false;
// In case the hollowed and drilled mesh is available, we can allow
// placing points in holes, because they should never end up
// 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) {
if (hole.is_inside(hit)) {
in_hole = true;
break;
}
}
}
}*/
if (! in_hole) {
// Return both the point and the facet 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>());
// 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)
unselect_point(points_idxs[idx]);
@ -632,13 +579,13 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
}
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);
return true;
}
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);
return true;
}
@ -719,10 +666,10 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
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();
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:
ImGui::Separator();
if (m_clipping_plane_distance == 0.f)
if (m_c->m_clipping_plane_distance == 0.f)
{
ImGui::AlignTextToFramePadding();
m_imgui->text(m_desc.at("clipping_of_view"));
@ -959,7 +906,7 @@ RENDER_AGAIN:
ImGui::SameLine(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);
@ -1043,15 +990,17 @@ void GLGizmoSlaSupports::on_set_state()
if (m_state == On && m_old_state != On) { // the gizmo was just 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:
if (m_c->m_model_object)
reload_cache();
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_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")));
m_parent.toggle_model_objects_visibility(true);
m_normal_cache.clear();
m_clipping_plane_distance = 0.f;
update_clipping_plane();
m_c->stash_clipping_plane();
m_c->m_clipping_plane_distance = 0.f;
update_clipping_plane(true);
// Release clippers and the AABB raycaster.
m_its = nullptr;
m_c->m_object_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;
@ -1127,8 +1077,8 @@ void GLGizmoSlaSupports::on_stop_dragging()
void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
{
ar(m_clipping_plane_distance,
*m_clipping_plane,
ar(m_c->m_clipping_plane_distance,
*m_c->m_clipping_plane,
m_c->m_model_object_id,
m_new_point_head_diameter,
m_normal_cache,
@ -1141,8 +1091,8 @@ void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
{
ar(m_clipping_plane_distance,
*m_clipping_plane,
ar(m_c->m_clipping_plane_distance,
*m_c->m_clipping_plane,
m_c->m_model_object_id,
m_new_point_head_diameter,
m_normal_cache,
@ -1244,6 +1194,9 @@ void GLGizmoSlaSupports::reload_cache()
bool GLGizmoSlaSupports::has_backend_supports() const
{
if (! m_c->m_model_object)
return false;
// find SlaPrintObject with this ID
for (const SLAPrintObject* po : m_parent.sla_print()->objects()) {
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
{
Vec3d normal = (keep_normal && m_clipping_plane->get_normal() != Vec3d::Zero() ?
m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward());
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);
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();
}

View file

@ -91,8 +91,6 @@ private:
void render_points(const Selection& selection, bool picking = false) const;
void render_clipping_plane(const Selection& selection) const;
void render_hollowed_mesh() const;
bool is_mesh_update_necessary() const;
void update_mesh();
bool unsaved_changes() const;
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
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
// 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())
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<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_sla_support_data(model_object, m_parent.get_selection());
}

View file

@ -5133,7 +5133,7 @@ void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error
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)