mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-30 20:32:01 +08:00
Multiple beds in SLA
This commit is contained in:
parent
324763a90e
commit
08eb318780
@ -22,6 +22,8 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
|
||||
// #define SLAPRINT_DO_BENCHMARK
|
||||
|
||||
#ifdef SLAPRINT_DO_BENCHMARK
|
||||
@ -298,6 +300,16 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
||||
if (! material_diff.empty())
|
||||
update_apply_status(this->invalidate_state_by_config_options(material_diff, invalidate_all_model_objects));
|
||||
|
||||
// Multiple beds hack: We currently use one SLAPrint for all beds. It must be invalidated
|
||||
// when beds are switched. If not done explicitly, supports from previously sliced object
|
||||
// might end up with wrong offset.
|
||||
static int last_bed_idx = s_multiple_beds.get_active_bed();
|
||||
int current_bed = s_multiple_beds.get_active_bed();
|
||||
if (current_bed != last_bed_idx) {
|
||||
invalidate_all_model_objects = true;
|
||||
last_bed_idx = current_bed;
|
||||
}
|
||||
|
||||
// Apply variables to placeholder parser. The placeholder parser is currently used
|
||||
// only to generate the output file name.
|
||||
if (! placeholder_parser_diff.empty()) {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -656,6 +657,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
||||
std::shared_ptr<const indexed_triangle_set> preview_mesh_ptr = print_object->get_mesh_to_print();
|
||||
if (preview_mesh_ptr != nullptr)
|
||||
backend_mesh = TriangleMesh(*preview_mesh_ptr);
|
||||
backend_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
if (!backend_mesh.empty()) {
|
||||
backend_mesh.transform(mesh_trafo_inv);
|
||||
TriangleMesh convex_hull = backend_mesh.convex_hull_3d();
|
||||
@ -670,6 +672,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
||||
// Get the support mesh.
|
||||
if (milestone == SLAPrintObjectStep::slaposSupportTree) {
|
||||
TriangleMesh supports_mesh = print_object->support_mesh();
|
||||
supports_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
if (!supports_mesh.empty()) {
|
||||
supports_mesh.transform(mesh_trafo_inv);
|
||||
TriangleMesh convex_hull = supports_mesh.convex_hull_3d();
|
||||
@ -683,6 +686,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
||||
// Get the pad mesh.
|
||||
if (milestone == SLAPrintObjectStep::slaposPad) {
|
||||
TriangleMesh pad_mesh = print_object->pad_mesh();
|
||||
pad_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
if (!pad_mesh.empty()) {
|
||||
pad_mesh.transform(mesh_trafo_inv);
|
||||
TriangleMesh convex_hull = pad_mesh.convex_hull_3d();
|
||||
|
@ -109,10 +109,22 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user)
|
||||
int old_bed = s_multiple_beds.get_active_bed();
|
||||
if ((i == old_bed && !s_multiple_beds.is_autoslicing()) || i == -1)
|
||||
return;
|
||||
|
||||
if (current_printer_technology() == ptSLA) {
|
||||
// Close SlaSupports or Hollow gizmos before switching beds. They rely on having access to SLAPrintObject to work.
|
||||
if (GLGizmosManager::EType cur_giz = get_gizmos_manager().get_current_type();
|
||||
cur_giz == GLGizmosManager::EType::SlaSupports || cur_giz == GLGizmosManager::EType::Hollow) {
|
||||
if (! get_gizmos_manager().open_gizmo(get_gizmos_manager().get_current_type()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->m_process->stop();
|
||||
m_sequential_print_clearance.m_evaluating = true;
|
||||
reset_sequential_print_clearance();
|
||||
|
||||
|
||||
|
||||
|
||||
// The stop call above schedules some events that would be processed after the switch.
|
||||
// Among else, on_process_completed would be called, which would stop slicing of
|
||||
// the new bed. We need to stop the process, pump all the events out of the queue
|
||||
@ -6085,6 +6097,12 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
||||
m_volumes.set_show_sinking_contours(! m_gizmos.is_hiding_instances());
|
||||
m_volumes.set_show_non_manifold_edges(!m_gizmos.is_hiding_instances() && m_gizmos.get_current_type() != GLGizmosManager::Simplify);
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
auto trafo = camera.get_view_matrix();
|
||||
if (current_printer_technology() == ptSLA && wxGetApp().plater()->is_preview_shown()) {
|
||||
trafo.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()));
|
||||
}
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
@ -6096,8 +6114,8 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
||||
{
|
||||
if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
|
||||
int object_id = m_layers_editing.last_object_id;
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix(), [object_id](const GLVolume& volume) {
|
||||
|
||||
m_volumes.render(type, false, trafo, camera.get_projection_matrix(), [object_id](const GLVolume& volume) {
|
||||
// Which volume to paint without the layer height profile shader?
|
||||
return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
|
||||
});
|
||||
@ -6107,7 +6125,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
||||
else {
|
||||
// do not cull backfaces to show broken geometry, if any
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
m_volumes.render(type, m_picking_enabled, camera.get_view_matrix(), camera.get_projection_matrix(), [this](const GLVolume& volume) {
|
||||
m_volumes.render(type, m_picking_enabled, trafo, camera.get_projection_matrix(), [this](const GLVolume& volume) {
|
||||
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
|
||||
});
|
||||
}
|
||||
@ -6129,7 +6147,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
|
||||
case GLVolumeCollection::ERenderType::Transparent:
|
||||
{
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
m_volumes.render(type, false, camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
m_volumes.render(type, false, trafo, camera.get_projection_matrix());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -6382,6 +6400,7 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector()
|
||||
height = win_size.y;
|
||||
wxGetApp().imgui()->set_requires_extra_frame();
|
||||
}
|
||||
m_bed_selector_current_height = height;
|
||||
|
||||
float max_width = win_x_pos;
|
||||
if (is_legend_shown())
|
||||
@ -6739,7 +6758,7 @@ void GLCanvas3D::_render_camera_target_validation_box()
|
||||
}
|
||||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
||||
|
||||
static void render_sla_layer_legend(const SLAPrint& print, int layer_idx, int cnv_width)
|
||||
static void render_sla_layer_legend(const SLAPrint& print, int layer_idx, int cnv_width, float bed_sel_height)
|
||||
{
|
||||
const std::vector<double>& areas = print.print_statistics().layers_areas;
|
||||
const std::vector<double>& times = print.print_statistics().layers_times_running_total;
|
||||
@ -6750,7 +6769,7 @@ static void render_sla_layer_legend(const SLAPrint& print, int layer_idx, int cn
|
||||
const double time_until_layer = times[layer_idx];
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
ImGuiPureWrap::set_next_window_pos(float(cnv_width) - imgui.get_style_scaling() * 5.f, 5.f, ImGuiCond_Always, 1.0f, 0.0f);
|
||||
ImGuiPureWrap::set_next_window_pos(float(cnv_width) - imgui.get_style_scaling() * 5.f, 5.f + bed_sel_height, ImGuiCond_Always, 1.0f, 0.0f);
|
||||
ImGui::SetNextWindowBgAlpha(0.6f);
|
||||
|
||||
ImGuiPureWrap::begin(_u8L("Layer statistics"), ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoFocusOnAppearing);
|
||||
@ -6786,7 +6805,7 @@ void GLCanvas3D::_render_sla_slices()
|
||||
double slider_width = 0.;
|
||||
if (const Preview* preview = dynamic_cast<Preview*>(m_canvas->GetParent()))
|
||||
slider_width = preview->get_layers_slider_width();
|
||||
render_sla_layer_legend(*print, m_layer_slider_index, get_canvas_size().get_width() - slider_width);
|
||||
render_sla_layer_legend(*print, m_layer_slider_index, get_canvas_size().get_width() - slider_width, m_bed_selector_current_height);
|
||||
}
|
||||
|
||||
double clip_min_z = -m_clipping_planes[0].get_data()[3];
|
||||
@ -6887,6 +6906,7 @@ void GLCanvas3D::_render_sla_slices()
|
||||
for (const SLAPrintObject::Instance& inst : obj->instances()) {
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
Transform3d view_model_matrix = camera.get_view_matrix() *
|
||||
Geometry::translation_transform(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed())) *
|
||||
Geometry::translation_transform({ unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0.0 }) *
|
||||
Geometry::rotation_transform(inst.rotation * Vec3d::UnitZ());
|
||||
if (obj->is_left_handed())
|
||||
|
@ -512,6 +512,7 @@ private:
|
||||
// see request_extra_frame()
|
||||
bool m_extra_frame_requested;
|
||||
bool m_event_handlers_bound{ false };
|
||||
float m_bed_selector_current_height = 0.f;
|
||||
|
||||
GLVolumeCollection m_volumes;
|
||||
#if SLIC3R_OPENGL_ES
|
||||
|
@ -81,6 +81,12 @@ void GLGizmoHollow::data_changed(bool is_serializing)
|
||||
|
||||
void GLGizmoHollow::on_render()
|
||||
{
|
||||
if (! selected_print_object_exists(m_parent, wxEmptyString)) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Close current gizmo.
|
||||
m_parent.get_gizmos_manager().open_gizmo(m_parent.get_gizmos_manager().get_current_type());
|
||||
});
|
||||
}
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info();
|
||||
|
||||
@ -137,7 +143,7 @@ void GLGizmoHollow::render_points(const Selection& selection)
|
||||
if (!inst)
|
||||
return;
|
||||
|
||||
double shift_z = m_c->selection_info()->print_object()->get_current_elevation();
|
||||
double shift_z = m_c->selection_info()->print_object() ? m_c->selection_info()->print_object()->get_current_elevation() : 0.;
|
||||
Transform3d trafo(inst->get_transformation().get_matrix());
|
||||
trafo.translation()(2) += shift_z;
|
||||
const Geometry::Transformation transformation{trafo};
|
||||
@ -849,6 +855,14 @@ void GLGizmoHollow::on_set_state()
|
||||
if (m_state == m_old_state)
|
||||
return;
|
||||
|
||||
if (m_state == On) {
|
||||
// Make sure that current object is on current bed. Refuse to turn on otherwise.
|
||||
if (! selected_print_object_exists(m_parent, _L("Selected object has to be on the active bed."))) {
|
||||
m_state = Off;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == Off && m_old_state != Off) {
|
||||
// the gizmo was just turned Off
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE));
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
|
||||
#include "libslic3r/MultipleBeds.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -21,6 +25,22 @@ GLGizmoSlaBase::GLGizmoSlaBase(GLCanvas3D& parent, const std::string& icon_filen
|
||||
, m_min_sla_print_object_step((int)min_step)
|
||||
{}
|
||||
|
||||
/*static*/ bool GLGizmoSlaBase::selected_print_object_exists(const GLCanvas3D& canvas, const wxString& text)
|
||||
{
|
||||
if (const Selection& sel = canvas.get_selection(); !sel.is_single_full_instance() || !sel.get_model()->objects[sel.get_object_idx()]
|
||||
|| ! canvas.sla_print()->get_print_object_by_model_object_id(sel.get_model()->objects[sel.get_object_idx()]->id()))
|
||||
{
|
||||
if (! text.IsEmpty())
|
||||
wxGetApp().CallAfter([text]() {
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe, text,
|
||||
_L("Bed selection mismatch"), wxICON_INFORMATION | wxOK);
|
||||
dlg.ShowModal();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoSlaBase::reslice_until_step(SLAPrintObjectStep step, bool postpone_error_messages)
|
||||
{
|
||||
wxGetApp().CallAfter([this, step, postpone_error_messages]() {
|
||||
@ -94,12 +114,14 @@ void GLGizmoSlaBase::update_volumes()
|
||||
const Transform3d po_trafo_inverse = po->trafo().inverse();
|
||||
|
||||
// main mesh
|
||||
backend_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
backend_mesh.transform(po_trafo_inverse);
|
||||
add_volume(backend_mesh, 0, true);
|
||||
|
||||
// supports mesh
|
||||
TriangleMesh supports_mesh = po->support_mesh();
|
||||
if (!supports_mesh.empty()) {
|
||||
supports_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
supports_mesh.transform(po_trafo_inverse);
|
||||
add_volume(supports_mesh, -int(slaposSupportTree));
|
||||
}
|
||||
@ -107,6 +129,7 @@ void GLGizmoSlaBase::update_volumes()
|
||||
// pad mesh
|
||||
TriangleMesh pad_mesh = po->pad_mesh();
|
||||
if (!pad_mesh.empty()) {
|
||||
pad_mesh.translate(s_multiple_beds.get_bed_translation(s_multiple_beds.get_active_bed()).cast<float>());
|
||||
pad_mesh.transform(po_trafo_inverse);
|
||||
add_volume(pad_mesh, -int(slaposPad));
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ protected:
|
||||
|
||||
const GLVolumeCollection &volumes() const { return m_volumes; }
|
||||
|
||||
static bool selected_print_object_exists(const GLCanvas3D& canvas, const wxString& text);
|
||||
|
||||
private:
|
||||
GLVolumeCollection m_volumes;
|
||||
bool m_input_enabled{ false };
|
||||
|
@ -103,6 +103,13 @@ void GLGizmoSlaSupports::data_changed(bool is_serializing)
|
||||
|
||||
void GLGizmoSlaSupports::on_render()
|
||||
{
|
||||
if (! selected_print_object_exists(m_parent, wxEmptyString)) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Close current gizmo.
|
||||
m_parent.get_gizmos_manager().open_gizmo(m_parent.get_gizmos_manager().get_current_type());
|
||||
});
|
||||
}
|
||||
|
||||
if (m_state == On) {
|
||||
// This gizmo is showing the object elevated. Tell the common
|
||||
// SelectionInfo object to lie about the actual shift.
|
||||
@ -843,6 +850,13 @@ bool GLGizmoSlaSupports::ask_about_changes(std::function<void()> on_yes, std::fu
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
if (m_state == On) { // the gizmo was just turned on
|
||||
|
||||
// Make sure that current object is on current bed. Refuse to turn on otherwise.
|
||||
if (! selected_print_object_exists(m_parent, _L("Selected object has to be on the active bed."))) {
|
||||
m_state = Off;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
|
@ -2129,12 +2129,12 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
||||
|
||||
int active_bed = s_multiple_beds.get_active_bed();
|
||||
background_process.set_temp_output_path(active_bed);
|
||||
background_process.set_fff_print(fff_prints[active_bed].get());
|
||||
background_process.set_sla_print(sla_prints[active_bed].get());
|
||||
background_process.set_fff_print(&q->active_fff_print());
|
||||
background_process.set_sla_print(&q->active_sla_print());
|
||||
background_process.set_gcode_result(&gcode_results[active_bed]);
|
||||
background_process.select_technology(this->printer_technology);
|
||||
|
||||
if (s_beds_just_switched) {
|
||||
if (s_beds_just_switched && printer_technology == ptFFF) {
|
||||
PrintBase::SlicingStatus status(q->active_fff_print(), -1);
|
||||
SlicingStatusEvent evt(EVT_SLICING_UPDATE, 0, status);
|
||||
on_slicing_update(evt);
|
||||
@ -3077,10 +3077,10 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||
warning_steps.clear();
|
||||
if (flags == PrintBase::SlicingStatus::UPDATE_PRINT_STEP_WARNINGS) {
|
||||
int i = 0;
|
||||
while (i < int(psCount)) { warning_steps.push_back(i); ++i; }
|
||||
while (i < int(printer_technology == ptFFF ? psCount : slapsCount)) { warning_steps.push_back(i); ++i; }
|
||||
} else {
|
||||
int i = 0;
|
||||
while (i < int(posCount)) { warning_steps.push_back(i); ++i; }
|
||||
while (i < int(printer_technology == ptFFF ? posCount : slaposCount)) { warning_steps.push_back(i); ++i; }
|
||||
for (const PrintObject* po : wxGetApp().plater()->active_fff_print().objects())
|
||||
object_ids.push_back(po->id());
|
||||
}
|
||||
@ -5652,7 +5652,7 @@ void Plater::export_gcode(bool prefer_removable)
|
||||
start_dir,
|
||||
from_path(default_output_file.filename()),
|
||||
printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE, ext) :
|
||||
GUI::sla_wildcards(p->sla_prints.front()->printer_config().sla_archive_format.value.c_str(), ext),
|
||||
GUI::sla_wildcards(active_sla_print().printer_config().sla_archive_format.value.c_str(), ext),
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
|
||||
);
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
@ -5769,7 +5769,7 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
|
||||
auto mesh_to_export_sla = [&, this](const ModelObject& mo, int instance_id) {
|
||||
TriangleMesh mesh;
|
||||
|
||||
const SLAPrintObject *object; // LUKAS = this->p->sla_print.get_print_object_by_model_object_id(mo.id());
|
||||
const SLAPrintObject *object = this->active_sla_print().get_print_object_by_model_object_id(mo.id());
|
||||
|
||||
if (!object || !object->get_mesh_to_print() || object->get_mesh_to_print()->empty()) {
|
||||
if (!extended)
|
||||
@ -7330,7 +7330,11 @@ wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu()
|
||||
|
||||
|
||||
Print& Plater::active_fff_print() { return *p->fff_prints[s_multiple_beds.get_active_bed()]; }
|
||||
SLAPrint& Plater::active_sla_print() { return *p->sla_prints[s_multiple_beds.get_active_bed()]; }
|
||||
//SLAPrint& Plater::active_sla_print() { return *p->sla_prints[s_multiple_beds.get_active_bed()]; }
|
||||
|
||||
// For now, only use the first SLAPrint for all the beds - it means reslicing
|
||||
// everything when a bed is changed.
|
||||
SLAPrint& Plater::active_sla_print() { return *p->sla_prints.front(); }
|
||||
|
||||
|
||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||
|
Loading…
x
Reference in New Issue
Block a user