wipe towers volumes

This commit is contained in:
Lukas Matena 2024-10-31 14:48:21 +01:00
parent fae06e0773
commit 5b59785456
11 changed files with 107 additions and 62 deletions

View File

@ -2,6 +2,7 @@
#include "BuildVolume.hpp"
#include "Model.hpp"
#include "Print.hpp"
#include <cassert>
@ -214,5 +215,22 @@ bool MultipleBeds::update_after_load_or_arrange(Model& model, const BuildVolume&
void MultipleBeds::ensure_wipe_towers_on_beds(Model& model, const std::vector<std::unique_ptr<Print>>& prints)
{
for (size_t bed_idx = 0; bed_idx < get_number_of_beds(); ++bed_idx) {
ModelWipeTower& mwt = model.get_wipe_tower_vector()[bed_idx];
double depth = prints[bed_idx]->wipe_tower_data().depth;
double width = prints[bed_idx]->wipe_tower_data().width;
double brim = prints[bed_idx]->wipe_tower_data().brim_width;
Polygon plg(Points{Point::new_scale(-brim,-brim), Point::new_scale(brim+width, -brim), Point::new_scale(brim+width, brim+depth), Point::new_scale(-brim, brim+depth)});
plg.rotate(Geometry::deg2rad(mwt.rotation));
plg.translate(scaled(mwt.position));
if (std::all_of(plg.points.begin(), plg.points.end(), [this](const Point& pt) { return !m_build_volume_bb.contains(unscale(pt)); }))
mwt.position = 2*brim*Vec2d(1.,1.);
}
}
}

View File

@ -12,6 +12,7 @@ namespace Slic3r {
class Model;
class BuildVolume;
class PrintBase;
class Print;
extern bool s_reload_preview_after_switching_beds;
extern bool s_beds_just_switched;
@ -48,6 +49,7 @@ public:
bool get_loading_project_flag() const { return m_loading_project; }
void update_build_volume(const BoundingBoxf& build_volume_bb, const BoundingBoxf& build_volume_bb_incl_model) { m_build_volume_bb = build_volume_bb; m_build_volume_bb_incl_model = build_volume_bb_incl_model; }
void ensure_wipe_towers_on_beds(Model& model, const std::vector<std::unique_ptr<Print>>& prints);

View File

@ -502,11 +502,11 @@ int GLVolumeCollection::load_object_volume(
#if SLIC3R_OPENGL_ES
int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle,
float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh)
float rotation_angle, bool size_unknown, float brim_width, size_t idx, TriangleMesh* out_mesh)
#else
int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle,
float rotation_angle, bool size_unknown, float brim_width)
float rotation_angle, bool size_unknown, float brim_width, size_t idx)
#endif // SLIC3R_OPENGL_ES
{
if (height == 0.0f)
@ -604,9 +604,9 @@ int GLVolumeCollection::load_wipe_tower_preview(
v.set_convex_hull(mesh.convex_hull_3d());
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
v.composite_id = GLVolume::CompositeID(INT_MAX, 0, 0);
v.composite_id = GLVolume::CompositeID(INT_MAX - idx, 0, 0);
v.geometry_id.first = 0;
v.geometry_id.second = wipe_tower_instance_id(0).id;
v.geometry_id.second = wipe_tower_instance_id(idx).id;
v.is_wipe_tower = true;
v.shader_outside_printer_detection_enabled = !size_unknown;
return int(volumes.size() - 1);

View File

@ -426,10 +426,10 @@ public:
#if SLIC3R_OPENGL_ES
int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr);
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, size_t idx, TriangleMesh* out_mesh = nullptr);
#else
int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width);
float pos_x, float pos_y, float width, float depth, const std::vector<std::pair<float, float>>& z_and_depth_pairs, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, size_t idx);
#endif // SLIC3R_OPENGL_ES
// Load SLA auxiliary GLVolumes (for support trees or pad).

View File

@ -1699,7 +1699,7 @@ void GCodeViewer::load_wipetower_shell(const Print& print)
const float brim_width = wipe_tower_data.brim_width;
if (depth != 0.) {
m_shells.volumes.load_wipe_tower_preview(wxGetApp().plater()->model().wipe_tower().position.x(), wxGetApp().plater()->model().wipe_tower().position.y(), config.wipe_tower_width, depth, z_and_depth_pairs,
max_z, config.wipe_tower_cone_angle, wxGetApp().plater()->model().wipe_tower().rotation, false, brim_width);
max_z, config.wipe_tower_cone_angle, wxGetApp().plater()->model().wipe_tower().rotation, false, brim_width, 0);
GLVolume* volume = m_shells.volumes.volumes.back();
volume->color.a(0.25f);
volume->force_native_color = true;

View File

@ -2211,7 +2211,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh;
PrinterTechnology printer_technology = current_printer_technology();
int volume_idx_wipe_tower_old = -1;
std::map<size_t, size_t> volume_idxs_wipe_towers_old; // map from geometry_id.second to volume_id
// Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed).
// First initialize model_volumes_new_sorted & model_instances_new_sorted.
@ -2284,12 +2284,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
if (mvs == nullptr || force_full_scene_refresh) {
// This GLVolume will be released.
if (volume->is_wipe_tower) {
// There is only one wipe tower.
assert(volume_idx_wipe_tower_old == -1);
#if SLIC3R_OPENGL_ES
m_wipe_tower_mesh.clear();
m_wipe_tower_meshes.clear();
#endif // SLIC3R_OPENGL_ES
volume_idx_wipe_tower_old = (int)volume_id;
volume_idxs_wipe_towers_old.emplace(std::make_pair(volume->geometry_id.second, volume_id));
}
if (!m_reload_delayed) {
deleted_volumes.emplace_back(volume, volume_id);
@ -2451,38 +2449,46 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
const bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
const bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
if (extruders_count > 1 && wt && !co) {
const float x = m_model->wipe_tower().position.x();
const float y = m_model->wipe_tower().position.y();
const float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value;
const float a = m_model->wipe_tower().rotation;
const float bw = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_brim_width"))->value;
const float ca = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_cone_angle"))->value;
const Print *print = m_process->fff_print();
if (extruders_count > 1 && wt && !co) {
for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_number_of_beds(); ++bed_idx) {
const Print *print = wxGetApp().plater()->get_fff_prints()[bed_idx].get();
const float x = m_model->get_wipe_tower_vector()[bed_idx].position.x();
const float y = m_model->get_wipe_tower_vector()[bed_idx].position.y();
const float a = m_model->get_wipe_tower_vector()[bed_idx].rotation;
const float depth = print->wipe_tower_data(extruders_count).depth;
const std::vector<std::pair<float, float>> z_and_depth_pairs = print->wipe_tower_data(extruders_count).z_and_depth_pairs;
const float height_real = print->wipe_tower_data(extruders_count).height; // -1.f = unknown
const bool is_wipe_tower_step_done = print->is_step_done(psWipeTower);
// Height of a print (Show at least a slab).
const double height = height_real < 0.f ? std::max(m_model->max_z(), 10.0) : height_real;
if (depth != 0.) {
#if SLIC3R_OPENGL_ES
if (bed_idx >= m_wipe_tower_meshes.size())
m_wipe_tower_meshes.resize(bed_idx + 1);
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !print->is_step_done(psWipeTower),
bw, &m_wipe_tower_mesh);
x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !is_wipe_tower_step_done,
bw, bed_idx, &m_wipe_tower_meshes[bed_idx]);
#else
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !print->is_step_done(psWipeTower),
bw);
x, y, w, depth, z_and_depth_pairs, (float)height, ca, a, !is_wipe_tower_step_done,
bw, bed_idx);
#endif // SLIC3R_OPENGL_ES
if (volume_idx_wipe_tower_old != -1)
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
auto it = volume_idxs_wipe_towers_old.find(m_volumes.volumes.back()->geometry_id.second);
if (it != volume_idxs_wipe_towers_old.end())
map_glvolume_old_to_new[it->second] = volume_idx_wipe_tower_new;
m_volumes.volumes.back()->set_volume_offset(m_volumes.volumes.back()->get_volume_offset() + s_multiple_beds.get_bed_translation(bed_idx));
}
}
s_multiple_beds.ensure_wipe_towers_on_beds(wxGetApp().plater()->model(), wxGetApp().plater()->get_fff_prints());
}
}
update_volumes_colors_by_extruder();
@ -3983,11 +3989,13 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
std::set<std::pair<int, int>> done; // keeps track of modified instances
bool object_moved = false;
Vec3d wipe_tower_origin = Vec3d::Zero();
std::vector<Vec3d> wipe_tower_origin = std::vector<Vec3d>(s_multiple_beds.get_max_beds(), Vec3d::Zero());
Selection::EMode selection_mode = m_selection.get_mode();
int vol_id = -1;
for (const GLVolume* v : m_volumes.volumes) {
++vol_id;
int object_idx = v->object_idx();
int instance_idx = v->instance_idx();
int volume_idx = v->volume_idx();
@ -4012,9 +4020,15 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
model_object->invalidate_bounding_box();
}
}
else if (m_selection.is_wipe_tower() && v->is_wipe_tower)
else if (m_selection.is_wipe_tower() && v->is_wipe_tower && m_selection.contains_volume(vol_id)) {
// Move a wipe tower proxy.
wipe_tower_origin = v->get_volume_offset();
for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_max_beds(); ++bed_idx) {
if (v->geometry_id.second == wipe_tower_instance_id(bed_idx).id) {
wipe_tower_origin[bed_idx] = v->get_volume_offset();
break;
}
}
}
}
// Fixes flying instances
@ -4041,8 +4055,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
if (object_moved)
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
if (wipe_tower_origin != Vec3d::Zero()) {
m_model->wipe_tower().position = Vec2d(wipe_tower_origin[0], wipe_tower_origin[1]);
if (auto it = std::find_if(wipe_tower_origin.begin(), wipe_tower_origin.end(), [](const Vec3d& pos) { return pos != Vec3d::Zero(); }); it != wipe_tower_origin.end()) {
size_t bed_idx = it - wipe_tower_origin.begin();
m_model->get_wipe_tower_vector()[bed_idx].position = Vec2d((*it)[0] - s_multiple_beds.get_bed_translation(bed_idx).x(), (*it)[1] - s_multiple_beds.get_bed_translation(bed_idx).y());
post_event(SimpleEvent(EVT_GLCANVAS_WIPETOWER_TOUCHED));
}
@ -4082,14 +4097,23 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
std::set<std::pair<int, int>> done; // keeps track of modified instances
Selection::EMode selection_mode = m_selection.get_mode();
int v_id = -1;
for (const GLVolume* v : m_volumes.volumes) {
++v_id;
if (v->is_wipe_tower) {
const Vec3d offset = v->get_volume_offset();
if (m_selection.contains_volume(v_id)) {
for (size_t bed_idx = 0; bed_idx < s_multiple_beds.get_max_beds(); ++bed_idx) {
if (v->geometry_id.second == wipe_tower_instance_id(bed_idx).id) {
const Vec3d offset = v->get_volume_offset() - s_multiple_beds.get_bed_translation(bed_idx);
Vec3d rot_unit_x = v->get_volume_transformation().get_matrix().linear() * Vec3d::UnitX();
double z_rot = std::atan2(rot_unit_x.y(), rot_unit_x.x());
m_model->wipe_tower().position = Vec2d(offset.x(), offset.y());
m_model->wipe_tower().rotation = (180. / M_PI) * z_rot;
m_model->get_wipe_tower_vector()[bed_idx].position = Vec2d(offset.x(), offset.y());
m_model->get_wipe_tower_vector()[bed_idx].rotation = (180. / M_PI) * z_rot;
break;
}
}
}
}
const int object_idx = v->object_idx();
if (object_idx < 0 || (int)m_model->objects.size() <= object_idx)

View File

@ -510,7 +510,7 @@ private:
GLVolumeCollection m_volumes;
#if SLIC3R_OPENGL_ES
TriangleMesh m_wipe_tower_mesh;
std::vector<TriangleMesh> m_wipe_tower_meshes;
#endif // SLIC3R_OPENGL_ES
GCodeViewer m_gcode_viewer;

View File

@ -528,8 +528,6 @@ struct Plater::priv
void on_object_select(SimpleEvent&);
void on_right_click(RBtnEvent&);
void on_wipetower_moved(Vec3dEvent&);
void on_wipetower_rotated(Vec3dEvent&);
void on_update_geometry(Vec3dsEvent<2>&);
void on_3dcanvas_mouse_dragging_started(SimpleEvent&);
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
@ -1599,7 +1597,10 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
GLGizmoSimplify::add_simplify_suggestion_notification(
obj_idxs, model.objects, *notification_manager);
if (s_multiple_beds.update_after_load_or_arrange(model, q->build_volume(), [this]() {q->canvas3D()->check_volumes_outside_state(); }))
if (s_multiple_beds.update_after_load_or_arrange(model, q->build_volume(), [this]() {
q->canvas3D()->check_volumes_outside_state();
s_multiple_beds.ensure_wipe_towers_on_beds(model, fff_prints);
}))
update();
return obj_idxs;
@ -3386,17 +3387,6 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
}
}
void Plater::priv::on_wipetower_moved(Vec3dEvent &evt)
{
model.wipe_tower().position = Vec2d(evt.data[0], evt.data[1]);
}
void Plater::priv::on_wipetower_rotated(Vec3dEvent& evt)
{
model.wipe_tower().position = Vec2d(evt.data[0], evt.data[1]);
model.wipe_tower().rotation = Geometry::rad2deg(evt.data(2));
}
void Plater::priv::on_update_geometry(Vec3dsEvent<2>&)
{
// TODO
@ -6792,7 +6782,10 @@ void Plater::arrange(Worker &w, bool selected)
concat_strings(names, "\n")));
}
s_multiple_beds.update_after_load_or_arrange(model(), build_volume(), [this]() { canvas3D()->check_volumes_outside_state(); });
s_multiple_beds.update_after_load_or_arrange(model(), build_volume(), [this]() {
canvas3D()->check_volumes_outside_state();
s_multiple_beds.ensure_wipe_towers_on_beds(model(), get_fff_prints());
});
update(static_cast<unsigned int>(UpdateParams::FORCE_FULL_SCREEN_REFRESH));
wxGetApp().obj_manipul()->set_dirty();
@ -7289,6 +7282,11 @@ void Plater::bring_instance_forward()
p->bring_instance_forward();
}
std::vector<std::unique_ptr<Print>>& Plater::get_fff_prints()
{
return p->fff_prints;
}
wxMenu* Plater::object_menu() { return p->menus.object_menu(); }
wxMenu* Plater::part_menu() { return p->menus.part_menu(); }
wxMenu* Plater::text_part_menu() { return p->menus.text_part_menu(); }

View File

@ -100,6 +100,8 @@ public:
Print& active_fff_print();
SLAPrint& active_sla_print();
std::vector<std::unique_ptr<Print>>& get_fff_prints();
void new_project();
void load_project();
void load_project(const wxString& filename);

View File

@ -162,7 +162,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came
const std::vector<std::shared_ptr<SceneRaycasterItem>>* raycasters = get_raycasters(type);
const Vec3f camera_forward = camera.get_dir_forward().cast<float>();
HitResult current_hit = { type };
for (std::shared_ptr<SceneRaycasterItem> item : *raycasters) {
for (const std::shared_ptr<SceneRaycasterItem>& item : *raycasters) {
if (!item->is_active())
continue;

View File

@ -23,6 +23,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/BuildVolume.hpp"
#include "libslic3r/MultipleBeds.hpp"
#include <GL/glew.h>
@ -147,7 +148,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
return;
// wipe tower is already selected
if (is_wipe_tower() && volume->is_wipe_tower)
if (is_wipe_tower() && volume->is_wipe_tower && contains_volume(volume_idx))
return;
bool keep_instance_mode = (m_mode == Instance) && !as_single_selection;