Merge remote-tracking branch 'origin/dev_native' into tm_sla_supports_backend

# Conflicts:
#	src/libslic3r/SLAPrint.hpp
This commit is contained in:
tamasmeszaros 2018-11-13 17:50:17 +01:00
commit 9a93b1d3e9
19 changed files with 441 additions and 167 deletions

View File

@ -1244,16 +1244,26 @@ size_t ModelVolume::split(unsigned int max_extruders)
std::string name = this->name; std::string name = this->name;
Model::reset_auto_extruder_id(); Model::reset_auto_extruder_id();
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3d offset = this->get_offset();
#endif // ENABLE_MODELVOLUME_TRANSFORM
for (TriangleMesh *mesh : meshptrs) { for (TriangleMesh *mesh : meshptrs) {
mesh->repair(); mesh->repair();
if (idx == 0) if (idx == 0)
{
this->mesh = std::move(*mesh); this->mesh = std::move(*mesh);
this->calculate_convex_hull();
}
else else
this->object->volumes.insert(this->object->volumes.begin() + (++ ivolume), new ModelVolume(object, *this, std::move(*mesh))); this->object->volumes.insert(this->object->volumes.begin() + (++ivolume), new ModelVolume(object, *this, std::move(*mesh)));
char str_idx[64];
sprintf(str_idx, "_%d", idx + 1); #if ENABLE_MODELVOLUME_TRANSFORM
this->object->volumes[ivolume]->name = name + str_idx; this->object->volumes[ivolume]->set_offset(Vec3d::Zero());
this->object->volumes[ivolume]->center_geometry();
this->object->volumes[ivolume]->translate(offset);
#endif // ENABLE_MODELVOLUME_TRANSFORM
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders));
delete mesh; delete mesh;
++ idx; ++ idx;

View File

@ -371,4 +371,14 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object):
SLAPrintObject::~SLAPrintObject() {} SLAPrintObject::~SLAPrintObject() {}
TriangleMesh SLAPrintObject::support_mesh() const
{
return make_cube(10., 10., 10.);
}
TriangleMesh SLAPrintObject::pad_mesh() const
{
return make_cube(10., 10., 10.);
}
} // namespace Slic3r } // namespace Slic3r

View File

@ -37,7 +37,23 @@ private: // Prevents erroneous use by other classes.
public: public:
const ModelObject* model_object() const { return m_model_object; } const ModelObject* model_object() const { return m_model_object; }
ModelObject* model_object() { return m_model_object; } ModelObject* model_object() { return m_model_object; }
const Transform3d& trafo() const { return m_trafo; }
struct Instance {
ModelID instance_id;
// Slic3r::Point objects in scaled G-code coordinates
Point shift;
// Rotation along the Z axis, in radians.
float rotation;
};
const std::vector<Instance>& instances() const { return m_instances; }
// Get a support mesh centered around origin in XY, and with zero rotation around Z applied.
// Support mesh is only valid if this->is_step_done(slaposSupportTree) is true.
TriangleMesh support_mesh() const; TriangleMesh support_mesh() const;
// Get a pad mesh centered around origin in XY, and with zero rotation around Z applied.
// Support mesh is only valid if this->is_step_done(slaposPad) is true.
TriangleMesh pad_mesh() const;
// I refuse to grantee copying (Tamas) // I refuse to grantee copying (Tamas)
SLAPrintObject(const SLAPrintObject&) = delete; SLAPrintObject(const SLAPrintObject&) = delete;
@ -55,14 +71,6 @@ protected:
{ this->m_config.apply_only(other, keys, ignore_nonexistent); } { this->m_config.apply_only(other, keys, ignore_nonexistent); }
void set_trafo(const Transform3d& trafo) { m_trafo = trafo; } void set_trafo(const Transform3d& trafo) { m_trafo = trafo; }
struct Instance {
// Slic3r::Point objects in scaled G-code coordinates
Point shift;
// Rotation along the Z axis, in radians.
float rotation;
Instance(const Point& tr, float rotZ): shift(tr), rotation(rotZ) {}
};
bool set_instances(const std::vector<Instance> &instances); bool set_instances(const std::vector<Instance> &instances);
// Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint. // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
bool invalidate_step(SLAPrintObjectStep step); bool invalidate_step(SLAPrintObjectStep step);
@ -152,6 +160,7 @@ public:
if(m_printer) m_printer->save<Fmt>(fname); if(m_printer) m_printer->save<Fmt>(fname);
std::cout << "Would export the SLA raster" << std::endl; std::cout << "Would export the SLA raster" << std::endl;
} }
const PrintObjects& objects() const { return m_objects; }
private: private:
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;

View File

@ -2,13 +2,14 @@
#include "3DScene.hpp" #include "3DScene.hpp"
#include "../../libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntity.hpp"
#include "../../libslic3r/ExtrusionEntityCollection.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp"
#include "../../libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#include "../../libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#include "../../libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "../../libslic3r/Slicing.hpp" #include "libslic3r/SLAPrint.hpp"
#include "../../slic3r/GUI/PresetBundle.hpp" #include "libslic3r/Slicing.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "GCode/Analyzer.hpp" #include "GCode/Analyzer.hpp"
#include <stdio.h> #include <stdio.h>
@ -209,7 +210,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
#endif // ENABLE_MODELVOLUME_TRANSFORM #endif // ENABLE_MODELVOLUME_TRANSFORM
, m_transformed_convex_hull_bounding_box_dirty(true) , m_transformed_convex_hull_bounding_box_dirty(true)
, m_convex_hull(nullptr) , m_convex_hull(nullptr)
, composite_id(-1) , object_id(-1)
, volume_id(-1)
, instance_id(-1)
, extruder_id(0) , extruder_id(0)
, selected(false) , selected(false)
, disabled(false) , disabled(false)
@ -755,7 +758,9 @@ std::vector<int> GLVolumeCollection::load_object(
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box(); v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs); v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx; v.object_id = obj_idx;
v.volume_id = volume_idx;
v.instance_id = instance_idx;
if (model_volume->is_model_part()) if (model_volume->is_model_part())
{ {
v.set_convex_hull(model_volume->get_convex_hull()); v.set_convex_hull(model_volume->get_convex_hull());
@ -780,6 +785,61 @@ std::vector<int> GLVolumeCollection::load_object(
return volumes_idx; return volumes_idx;
} }
// Load SLA auxiliary GLVolumes (for support trees or pad).
std::vector<int> GLVolumeCollection::load_object_auxiliary(
const ModelObject *model_object,
const SLAPrintObject *print_object,
int obj_idx,
SLAPrintObjectStep milestone,
bool use_VBOs)
{
std::vector<int> volumes_idx;
// Find the SLAPrintObject's instance to it.
if (print_object->is_step_done(milestone)) {
// Get the support mesh.
TriangleMesh mesh;
switch (milestone) {
case slaposSupportTree: mesh = print_object->support_mesh(); break;
case slaposBasePool: mesh = print_object->pad_mesh(); break;
default:
assert(false);
}
// Convex hull is required for out of print bed detection.
TriangleMesh convex_hull = mesh.convex_hull_3d();
const std::vector<SLAPrintObject::Instance> &instances = print_object->instances();
std::map<ModelID, int> map_instances;
for (int i = 0; i < (int)model_object->instances.size(); ++ i)
map_instances[model_object->instances[i]->id()] = i;
for (const SLAPrintObject::Instance &instance : instances) {
auto model_instance_it = map_instances.find(instance.instance_id);
assert(model_instance_it != map_instances.end());
const int instance_idx = model_instance_it->second;
const ModelInstance *model_instance = model_object->instances[instance_idx];
volumes_idx.push_back(int(this->volumes.size()));
float color[4] { 0.f, 0.f, 1.f, 1.f };
this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back();
if (use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.object_id = obj_idx;
v.volume_id = -1; // SLA supports
v.instance_id = instance_idx;
v.set_convex_hull(convex_hull);
v.is_modifier = false;
v.shader_outside_printer_detection_enabled = true;
v.set_instance_transformation(model_instance->get_transformation());
// Leave the volume transformation at identity.
// v.set_volume_transformation(model_volume->get_transformation());
}
}
return volumes_idx;
}
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width) int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width)
@ -851,7 +911,9 @@ int GLVolumeCollection::load_wipe_tower_preview(
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry(). // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box(); v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs); v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.composite_id = obj_idx * 1000000; v.object_id = obj_idx;
v.volume_id = 0;
v.instance_id = 0;
v.is_wipe_tower = true; v.is_wipe_tower = true;
v.shader_outside_printer_detection_enabled = ! size_unknown; v.shader_outside_printer_detection_enabled = ! size_unknown;
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
@ -1848,6 +1910,11 @@ void _3DScene::set_print(wxGLCanvas* canvas, Print* print)
s_canvas_mgr.set_print(canvas, print); s_canvas_mgr.set_print(canvas, print);
} }
void _3DScene::set_SLA_print(wxGLCanvas* canvas, SLAPrint* print)
{
s_canvas_mgr.set_SLA_print(canvas, print);
}
void _3DScene::set_model(wxGLCanvas* canvas, Model* model) void _3DScene::set_model(wxGLCanvas* canvas, Model* model)
{ {
s_canvas_mgr.set_model(canvas, model); s_canvas_mgr.set_model(canvas, model);

View File

@ -1,13 +1,13 @@
#ifndef slic3r_3DScene_hpp_ #ifndef slic3r_3DScene_hpp_
#define slic3r_3DScene_hpp_ #define slic3r_3DScene_hpp_
#include "../../libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "../../libslic3r/Point.hpp" #include "libslic3r/Point.hpp"
#include "../../libslic3r/Line.hpp" #include "libslic3r/Line.hpp"
#include "../../libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMesh.hpp"
#include "../../libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "../../libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "../../slic3r/GUI/GLCanvas3DManager.hpp" #include "slic3r/GUI/GLCanvas3DManager.hpp"
class wxBitmap; class wxBitmap;
class wxWindow; class wxWindow;
@ -16,6 +16,9 @@ namespace Slic3r {
class Print; class Print;
class PrintObject; class PrintObject;
class SLAPrint;
class SLAPrintObject;
enum SLAPrintObjectStep;
class Model; class Model;
class ModelObject; class ModelObject;
class GCodePreviewData; class GCodePreviewData;
@ -290,8 +293,15 @@ public:
float color[4]; float color[4];
// Color used to render this volume. // Color used to render this volume.
float render_color[4]; float render_color[4];
// An ID containing the object ID, volume ID and instance ID. // Object ID, which is equal to the index of the respective ModelObject in Model.objects array.
int composite_id; int object_id;
// Volume ID, which is equal to the index of the respective ModelVolume in ModelObject.volumes array.
// If negative, it is an index of a geometry produced by the PrintObject for the respective ModelObject,
// and which has no associated ModelVolume in ModelObject.volumes. For example, SLA supports.
// Volume with a negative volume_id cannot be picked independently, it will pick the associated instance.
int volume_id;
// Instance ID, which is equal to the index of the respective ModelInstance in ModelObject.instances array.
int instance_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;
// Is this object selected? // Is this object selected?
@ -404,9 +414,9 @@ public:
void set_convex_hull(const TriangleMesh& convex_hull); void set_convex_hull(const TriangleMesh& convex_hull);
int object_idx() const { return this->composite_id / 1000000; } int object_idx() const { return this->object_id; }
int volume_idx() const { return (this->composite_id / 1000) % 1000; } int volume_idx() const { return this->volume_id; }
int instance_idx() const { return this->composite_id % 1000; } int instance_idx() const { return this->instance_id; }
#if ENABLE_MODELVOLUME_TRANSFORM #if ENABLE_MODELVOLUME_TRANSFORM
Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); } Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); }
@ -489,6 +499,14 @@ public:
const std::string &color_by, const std::string &color_by,
bool use_VBOs); bool use_VBOs);
// Load SLA auxiliary GLVolumes (for support trees or pad).
std::vector<int> load_object_auxiliary(
const ModelObject *model_object,
const SLAPrintObject *print_object,
int obj_idx,
SLAPrintObjectStep milestone,
bool use_VBOs);
int load_wipe_tower_preview( int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width);
@ -556,6 +574,7 @@ public:
static void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); static void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config);
static void set_print(wxGLCanvas* canvas, Print* print); static void set_print(wxGLCanvas* canvas, Print* print);
static void set_SLA_print(wxGLCanvas* canvas, SLAPrint* print);
static void set_model(wxGLCanvas* canvas, Model* model); static void set_model(wxGLCanvas* canvas, Model* model);
static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); static void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape);

View File

@ -294,6 +294,12 @@ void BackgroundSlicingProcess::stop_internal()
m_print->set_cancel_callback([](){}); m_print->set_cancel_callback([](){});
} }
bool BackgroundSlicingProcess::empty() const
{
assert(m_print != nullptr);
return m_print->empty();
}
std::string BackgroundSlicingProcess::validate() std::string BackgroundSlicingProcess::validate()
{ {
assert(m_print != nullptr); assert(m_print != nullptr);

View File

@ -51,11 +51,15 @@ public:
// Useful when the Model or configuration is being changed drastically. // Useful when the Model or configuration is being changed drastically.
bool reset(); bool reset();
// Validate the print. Returns an empty string if valid, returns an error message if invalid.
std::string validate();
// Apply config over the print. Returns false, if the new config values caused any of the already // Apply config over the print. Returns false, if the new config values caused any of the already
// processed steps to be invalidated, therefore the task will need to be restarted. // processed steps to be invalidated, therefore the task will need to be restarted.
Print::ApplyStatus apply(const Model &model, const DynamicPrintConfig &config); Print::ApplyStatus apply(const Model &model, const DynamicPrintConfig &config);
// After calling apply, the empty() call will report whether there is anything to slice.
bool empty() const;
// Validate the print. Returns an empty string if valid, returns an error message if invalid.
// Call validate before calling start().
std::string validate();
// Set the export path of the G-code. // Set the export path of the G-code.
// Once the path is set, the G-code // Once the path is set, the G-code
void schedule_export(const std::string &path); void schedule_export(const std::string &path);

View File

@ -1,16 +1,16 @@
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include "../../admesh/stl.h" #include "admesh/stl.h"
#include "../../libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "../../slic3r/GUI/3DScene.hpp" #include "slic3r/GUI/3DScene.hpp"
#include "../../slic3r/GUI/GLShader.hpp" #include "slic3r/GUI/GLShader.hpp"
#include "../../slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI.hpp"
#include "../../slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/PresetBundle.hpp"
#include "../../slic3r/GUI/GLGizmo.hpp" #include "slic3r/GUI/GLGizmo.hpp"
#include "../../libslic3r/ClipperUtils.hpp" #include "libslic3r/ClipperUtils.hpp"
#include "../../libslic3r/PrintConfig.hpp" #include "libslic3r/PrintConfig.hpp"
#include "../../libslic3r/GCode/PreviewData.hpp" #include "libslic3r/GCode/PreviewData.hpp"
#include "../../libslic3r/Geometry.hpp" #include "libslic3r/Geometry.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "GUI_ObjectList.hpp" #include "GUI_ObjectList.hpp"
#include "GUI_ObjectManipulation.hpp" #include "GUI_ObjectManipulation.hpp"
@ -25,7 +25,8 @@
#include <wx/tooltip.h> #include <wx/tooltip.h>
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
#include "../../libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h> #include <tbb/spin_mutex.h>
@ -3065,6 +3066,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
, m_toolbar(*this) , m_toolbar(*this)
, m_config(nullptr) , m_config(nullptr)
, m_print(nullptr) , m_print(nullptr)
, m_sla_print(nullptr)
, m_model(nullptr) , m_model(nullptr)
, m_dirty(true) , m_dirty(true)
, m_initialized(false) , m_initialized(false)
@ -3247,7 +3249,11 @@ bool GLCanvas3D::move_volume_up(unsigned int id)
if ((id > 0) && (id < (unsigned int)m_volumes.volumes.size())) if ((id > 0) && (id < (unsigned int)m_volumes.volumes.size()))
{ {
std::swap(m_volumes.volumes[id - 1], m_volumes.volumes[id]); std::swap(m_volumes.volumes[id - 1], m_volumes.volumes[id]);
std::swap(m_volumes.volumes[id - 1]->composite_id, m_volumes.volumes[id]->composite_id); GLVolume &v1 = *m_volumes.volumes[id - 1];
GLVolume &v2 = *m_volumes.volumes[id];
std::swap(v1.object_id, v2.object_id);
std::swap(v1.volume_id, v2.volume_id);
std::swap(v1.instance_id, v2.instance_id);
return true; return true;
} }
@ -3259,7 +3265,11 @@ bool GLCanvas3D::move_volume_down(unsigned int id)
if ((id >= 0) && (id + 1 < (unsigned int)m_volumes.volumes.size())) if ((id >= 0) && (id + 1 < (unsigned int)m_volumes.volumes.size()))
{ {
std::swap(m_volumes.volumes[id + 1], m_volumes.volumes[id]); std::swap(m_volumes.volumes[id + 1], m_volumes.volumes[id]);
std::swap(m_volumes.volumes[id + 1]->composite_id, m_volumes.volumes[id]->composite_id); GLVolume &v1 = *m_volumes.volumes[id + 1];
GLVolume &v2 = *m_volumes.volumes[id];
std::swap(v1.object_id, v2.object_id);
std::swap(v1.volume_id, v2.volume_id);
std::swap(v1.instance_id, v2.instance_id);
return true; return true;
} }
@ -3276,6 +3286,11 @@ void GLCanvas3D::set_print(Print* print)
m_print = print; m_print = print;
} }
void GLCanvas3D::set_SLA_print(SLAPrint* print)
{
m_sla_print = print;
}
void GLCanvas3D::set_model(Model* model) void GLCanvas3D::set_model(Model* model)
{ {
m_model = model; m_model = model;
@ -3631,6 +3646,13 @@ std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
return std::vector<int>(); return std::vector<int>();
} }
std::vector<int> GLCanvas3D::load_support_meshes(const Model& model, int obj_idx)
{
std::vector<int> volumes = m_volumes.load_object_auxiliary(model.objects[obj_idx], m_sla_print->objects()[obj_idx], obj_idx, slaposSupportTree, m_use_VBOs && m_initialized);
append(volumes, m_volumes.load_object_auxiliary(model.objects[obj_idx], m_sla_print->objects()[obj_idx], obj_idx, slaposBasePool, m_use_VBOs && m_initialized));
return volumes;
}
int GLCanvas3D::get_first_volume_id(int obj_idx) const int GLCanvas3D::get_first_volume_id(int obj_idx) const
{ {
for (int i = 0; i < (int)m_volumes.volumes.size(); ++i) for (int i = 0; i < (int)m_volumes.volumes.size(); ++i)
@ -3682,11 +3704,14 @@ void GLCanvas3D::reload_scene(bool force)
m_reload_delayed = false; m_reload_delayed = false;
PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
if (m_regenerate_volumes) if (m_regenerate_volumes)
{ {
for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx) for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++obj_idx)
{ {
load_object(*m_model, obj_idx); load_object(*m_model, obj_idx);
if (printer_technology == ptSLA)
load_support_meshes(*m_model, obj_idx);
} }
} }
@ -3694,7 +3719,8 @@ void GLCanvas3D::reload_scene(bool force)
if (m_regenerate_volumes) if (m_regenerate_volumes)
{ {
if (m_config->has("nozzle_diameter") && wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) PrinterTechnology printer_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
if (printer_technology == ptFFF && m_config->has("nozzle_diameter"))
{ {
// Should the wipe tower be visualized ? // Should the wipe tower be visualized ?
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size(); unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();

View File

@ -22,6 +22,7 @@ namespace Slic3r {
class GLShader; class GLShader;
class ExPolygon; class ExPolygon;
class SLAPrint;
namespace GUI { namespace GUI {
@ -447,17 +448,25 @@ public:
struct Cache struct Cache
{ {
// Cache of GLVolume derived transformation matrices, valid during mouse dragging.
VolumesCache volumes_data; VolumesCache volumes_data;
// Center of the dragged selection, valid during mouse dragging.
Vec3d dragging_center; Vec3d dragging_center;
// Map from indices of ModelObject instances in Model::objects
// to a set of indices of ModelVolume instances in ModelObject::instances
// Here the index means a position inside the respective std::vector, not ModelID.
ObjectIdxsToInstanceIdxsMap content; ObjectIdxsToInstanceIdxsMap content;
}; };
// Volumes owned by GLCanvas3D.
GLVolumePtrs* m_volumes; GLVolumePtrs* m_volumes;
// Model, not owned.
Model* m_model; Model* m_model;
bool m_valid; bool m_valid;
EMode m_mode; EMode m_mode;
EType m_type; EType m_type;
// set of indices to m_volumes
IndicesList m_list; IndicesList m_list;
Cache m_cache; Cache m_cache;
mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_bounding_box;
@ -692,6 +701,7 @@ private:
Selection m_selection; Selection m_selection;
DynamicPrintConfig* m_config; DynamicPrintConfig* m_config;
Print* m_print; Print* m_print;
SLAPrint* m_sla_print;
Model* m_model; Model* m_model;
bool m_dirty; bool m_dirty;
@ -745,6 +755,7 @@ public:
void set_config(DynamicPrintConfig* config); void set_config(DynamicPrintConfig* config);
void set_print(Print* print); void set_print(Print* print);
void set_SLA_print(SLAPrint* print);
void set_model(Model* model); void set_model(Model* model);
const Selection& get_selection() const { return m_selection; } const Selection& get_selection() const { return m_selection; }
@ -810,6 +821,9 @@ public:
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs); std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
std::vector<int> load_object(const Model& model, int obj_idx); std::vector<int> load_object(const Model& model, int obj_idx);
// Load SLA support tree and SLA pad meshes into the scene, if available at the respective SLAPrintObject instances.
std::vector<int> load_support_meshes(const Model& model, int obj_idx);
int get_first_volume_id(int obj_idx) const; int get_first_volume_id(int obj_idx) const;
int get_in_object_volume_id(int scene_vol_idx) const; int get_in_object_volume_id(int scene_vol_idx) const;

View File

@ -284,6 +284,14 @@ void GLCanvas3DManager::set_print(wxGLCanvas* canvas, Print* print)
it->second->set_print(print); it->second->set_print(print);
} }
void GLCanvas3DManager::set_SLA_print(wxGLCanvas* canvas, SLAPrint* print)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->set_SLA_print(print);
}
void GLCanvas3DManager::set_model(wxGLCanvas* canvas, Model* model) void GLCanvas3DManager::set_model(wxGLCanvas* canvas, Model* model)
{ {
CanvasesMap::iterator it = _get_canvas(canvas); CanvasesMap::iterator it = _get_canvas(canvas);

View File

@ -14,6 +14,7 @@ namespace Slic3r {
class DynamicPrintConfig; class DynamicPrintConfig;
class Print; class Print;
class SLAPrint;
class Model; class Model;
class ExPolygon; class ExPolygon;
typedef std::vector<ExPolygon> ExPolygons; typedef std::vector<ExPolygon> ExPolygons;
@ -95,6 +96,7 @@ public:
void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config); void set_config(wxGLCanvas* canvas, DynamicPrintConfig* config);
void set_print(wxGLCanvas* canvas, Print* print); void set_print(wxGLCanvas* canvas, Print* print);
void set_SLA_print(wxGLCanvas* canvas, SLAPrint* print);
void set_model(wxGLCanvas* canvas, Model* model); void set_model(wxGLCanvas* canvas, Model* model);
void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape); void set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape);

View File

@ -494,7 +494,7 @@ void GLGizmoRotate::render_angle() const
void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
{ {
double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset); double grabber_radius = (double)m_radius * (1.0 + (double)GrabberOffset) + 2.0 * (double)m_axis * box.max_size() * (double)Grabber::SizeFactor;
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
m_grabbers[0].angles(2) = m_angle; m_grabbers[0].angles(2) = m_angle;

View File

@ -482,18 +482,16 @@ ConfigMenuIDs GUI_App::get_view_mode()
// Update view mode according to selected menu // Update view mode according to selected menu
void GUI_App::update_mode() void GUI_App::update_mode()
{ {
wxWindowUpdateLocker noUpdates(mainframe->m_plater); wxWindowUpdateLocker noUpdates(&sidebar());
ConfigMenuIDs mode = wxGetApp().get_view_mode(); ConfigMenuIDs mode = wxGetApp().get_view_mode();
obj_list()->get_sizer()->Show(mode == ConfigMenuModeExpert); obj_list()->get_sizer()->Show(mode == ConfigMenuModeExpert);
sidebar().show_info_sizer(mode == ConfigMenuModeExpert); sidebar().set_mode_value(mode);
sidebar().show_buttons(mode == ConfigMenuModeExpert); sidebar().show_buttons(mode == ConfigMenuModeExpert);
obj_manipul()->show_object_name(mode == ConfigMenuModeSimple); obj_list()->update_selections();
obj_list()->update_manipulation_sizer(mode == ConfigMenuModeSimple);
sidebar().Layout(); sidebar().Layout();
mainframe->m_plater->Layout();
ConfigOptionMode opt_mode = mode == ConfigMenuModeSimple ? comSimple : ConfigOptionMode opt_mode = mode == ConfigMenuModeSimple ? comSimple :
mode == ConfigMenuModeExpert ? comExpert : comAdvanced; mode == ConfigMenuModeExpert ? comExpert : comAdvanced;

View File

@ -823,9 +823,12 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const int
#endif //no __WXOSX__ //__WXMSW__ #endif //no __WXOSX__ //__WXMSW__
} }
void ObjectList::del_object(const int obj_idx)
{
wxGetApp().plater()->delete_object_from_model(obj_idx);
}
// Delete subobject // Delete subobject
void ObjectList::del_subobject_item(wxDataViewItem& item) void ObjectList::del_subobject_item(wxDataViewItem& item)
{ {
if (!item) return; if (!item) return;
@ -1016,7 +1019,6 @@ void ObjectList::part_selection_changed()
bool update_and_show_manipulations = false; bool update_and_show_manipulations = false;
bool update_and_show_settings = false; bool update_and_show_settings = false;
bool show_info_sizer = false;
if (multiple_selection()) { if (multiple_selection()) {
og_name = _(L("Group manipulation")); og_name = _(L("Group manipulation"));
@ -1033,7 +1035,6 @@ void ObjectList::part_selection_changed()
og_name = _(L("Object manipulation")); og_name = _(L("Object manipulation"));
m_config = &(*m_objects)[obj_idx]->config; m_config = &(*m_objects)[obj_idx]->config;
update_and_show_manipulations = true; update_and_show_manipulations = true;
show_info_sizer = true;
} }
else { else {
auto parent = m_objects_model->GetParent(item); auto parent = m_objects_model->GetParent(item);
@ -1082,25 +1083,15 @@ void ObjectList::part_selection_changed()
if (update_and_show_settings) if (update_and_show_settings)
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " "); wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
auto panel = wxGetApp().sidebar().scrolled_panel(); Sidebar& panel = wxGetApp().sidebar();
panel->Freeze(); panel.Freeze();
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations); wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings); wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
show_info_sizer ? wxGetApp().sidebar().update_info_sizer() : wxGetApp().sidebar().show_info_sizer(false); wxGetApp().sidebar().show_info_sizer();
panel->Thaw(); panel.Layout();
} panel.Thaw();
void ObjectList::update_manipulation_sizer(const bool is_simple_mode)
{
auto item = GetSelection(); /// #ys_FIXME_to_multi_sel
if (!item || !is_simple_mode)
return;
if (m_objects_model->IsSettingsItem(item)) {
select_item(m_objects_model->GetParent(item));
}
} }
void ObjectList::add_object_to_list(size_t obj_idx) void ObjectList::add_object_to_list(size_t obj_idx)
@ -1167,6 +1158,49 @@ void ObjectList::delete_volume_from_list(const size_t obj_idx, const size_t vol_
select_item(m_objects_model->Delete(m_objects_model->GetItemByVolumeId(obj_idx, vol_idx))); select_item(m_objects_model->Delete(m_objects_model->GetItemByVolumeId(obj_idx, vol_idx)));
} }
void ObjectList::delete_instance_from_list(const size_t obj_idx, const size_t inst_idx)
{
select_item(m_objects_model->Delete(m_objects_model->GetItemByInstanceId(obj_idx, inst_idx)));
}
void ObjectList::delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx)
{
if ( !(type&(itObject|itVolume|itInstance)) )
return;
if (type&itObject) {
del_object(obj_idx);
delete_object_from_list(obj_idx);
}
else {
del_subobject_from_object(obj_idx, sub_obj_idx, type);
type == itVolume ? delete_volume_from_list(obj_idx, sub_obj_idx) :
delete_instance_from_list(obj_idx, sub_obj_idx);
}
}
void ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete> * items_for_delete)
{
for (auto& item : *items_for_delete)
{
if ( !(item.type&(itObject|itVolume|itInstance)) )
continue;
if (item.type&itObject) {
del_object(item.obj_idx);
m_objects_model->Delete(m_objects_model->GetItemById(item.obj_idx));
}
else {
del_subobject_from_object(item.obj_idx, item.sub_obj_idx, item.type);
if (item.type&itVolume)
m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item.obj_idx, item.sub_obj_idx));
else
m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item.obj_idx, item.sub_obj_idx));
}
}
part_selection_changed();
}
void ObjectList::delete_all_objects_from_list() void ObjectList::delete_all_objects_from_list()
{ {
m_objects_model->DeleteAll(); m_objects_model->DeleteAll();

View File

@ -5,7 +5,9 @@
#include <wx/dataview.h> #include <wx/dataview.h>
#include <map> #include <map>
#include <vector> #include <vector>
#include "Event.hpp" #include "Event.hpp"
#include "wxExtensions.hpp"
class wxBoxSizer; class wxBoxSizer;
class PrusaObjectDataViewModel; class PrusaObjectDataViewModel;
@ -20,6 +22,13 @@ namespace GUI {
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent); wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
struct ItemForDelete
{
ItemType type;
int obj_idx;
int sub_obj_idx;
};
class ObjectList : public wxDataViewCtrl class ObjectList : public wxDataViewCtrl
{ {
wxBoxSizer *m_sizer {nullptr}; wxBoxSizer *m_sizer {nullptr};
@ -92,6 +101,7 @@ public:
void load_subobject(int type); void load_subobject(int type);
void load_part(ModelObject* model_object, wxArrayString& part_names, int type); void load_part(ModelObject* model_object, wxArrayString& part_names, int type);
void load_generic_subobject(const std::string& type_name, const int type); void load_generic_subobject(const std::string& type_name, const int type);
void del_object(const int obj_idx);
void del_subobject_item(wxDataViewItem& item); void del_subobject_item(wxDataViewItem& item);
void del_settings_from_config(); void del_settings_from_config();
void del_instances_from_object(const int obj_idx); void del_instances_from_object(const int obj_idx);
@ -110,14 +120,15 @@ public:
void parts_changed(int obj_idx); void parts_changed(int obj_idx);
void part_selection_changed(); void part_selection_changed();
void update_manipulation_sizer(const bool is_simple_mode);
// Add object to the list // Add object to the list
void add_object_to_list(size_t obj_idx); void add_object_to_list(size_t obj_idx);
// Delete object from the list // Delete object from the list
void delete_object_from_list(); void delete_object_from_list();
void delete_object_from_list(const size_t obj_idx); void delete_object_from_list(const size_t obj_idx);
void delete_volume_from_list(const size_t obj_idx, const size_t vol_idx); void delete_volume_from_list(const size_t obj_idx, const size_t vol_idx);
void delete_instance_from_list(const size_t obj_idx, const size_t inst_idx);
void delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx);
void delete_from_model_and_list(const std::vector<ItemForDelete> * items_for_delete);
// Delete all objects from the list // Delete all objects from the list
void delete_all_objects_from_list(); void delete_all_objects_from_list();
// Increase instances count // Increase instances count

View File

@ -87,7 +87,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent):
if (option_name == "Rotation") if (option_name == "Rotation")
def.min = -360; def.min = -360;
else else
def.min == -1000; def.min = -1000;
const std::string lower_name = boost::algorithm::to_lower_copy(option_name); const std::string lower_name = boost::algorithm::to_lower_copy(option_name);

View File

@ -38,7 +38,7 @@ void OG_Settings::Hide()
void OG_Settings::UpdateAndShow(const bool show) void OG_Settings::UpdateAndShow(const bool show)
{ {
Show(show); Show(show);
m_parent->Layout(); // m_parent->Layout();
} }
wxSizer* OG_Settings::get_sizer() wxSizer* OG_Settings::get_sizer()

View File

@ -447,7 +447,7 @@ struct Sidebar::priv
void Sidebar::priv::show_preset_comboboxes() void Sidebar::priv::show_preset_comboboxes()
{ {
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; const bool showSLA = plater->printer_technology() == ptSLA;
wxWindowUpdateLocker noUpdates_scrolled(scrolled); wxWindowUpdateLocker noUpdates_scrolled(scrolled);
// scrolled->Freeze(); // scrolled->Freeze();
@ -630,9 +630,8 @@ void Sidebar::update_presets(Preset::Type preset_type)
case Preset::TYPE_PRINTER: case Preset::TYPE_PRINTER:
{ {
PrinterTechnology printer_technology = preset_bundle.printers.get_edited_preset().printer_technology();
// Update the print choosers to only contain the compatible presets, update the dirty flags. // Update the print choosers to only contain the compatible presets, update the dirty flags.
if (printer_technology == ptFFF) if (p->plater->printer_technology() == ptFFF)
preset_bundle.prints.update_platter_ui(p->combo_print); preset_bundle.prints.update_platter_ui(p->combo_print);
else else
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
@ -640,7 +639,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
preset_bundle.printers.update_platter_ui(p->combo_printer); preset_bundle.printers.update_platter_ui(p->combo_printer);
// Update the filament choosers to only contain the compatible presets, update the color preview, // Update the filament choosers to only contain the compatible presets, update the color preview,
// update the dirty flags. // update the dirty flags.
if (printer_technology == ptFFF) { if (p->plater->printer_technology() == ptFFF) {
for (size_t i = 0; i < p->combos_filament.size(); ++ i) for (size_t i = 0; i < p->combos_filament.size(); ++ i)
preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]); preset_bundle.update_platter_filament_ui(i, p->combos_filament[i]);
} }
@ -690,32 +689,31 @@ void Sidebar::update_objects_list_extruder_column(int extruders_count)
p->object_list->update_objects_list_extruder_column(extruders_count); p->object_list->update_objects_list_extruder_column(extruders_count);
} }
void Sidebar::show_info_sizer(const bool show) void Sidebar::show_info_sizer()
{ {
p->object_info->show_sizer(show); if (!p->plater->is_single_full_object_selection() ||
p->scrolled->Layout(); m_mode < ConfigMenuModeExpert ) {
}
void Sidebar::update_info_sizer()
{
wxWindowUpdateLocker freeze_guard(p->scrolled);
if (/*obj_idx < 0 || */!p->plater->is_single_full_object_selection()) {
p->object_info->Show(false); p->object_info->Show(false);
p->scrolled->Layout();
return; return;
} }
int obj_idx = p->plater->get_selected_object_idx(); int obj_idx = p->plater->get_selected_object_idx();
const ModelObject* model_object = (*wxGetApp().model_objects())[obj_idx]; const ModelObject* model_object = (*wxGetApp().model_objects())[obj_idx];
// hack to avoid crash when deleting the last object on the bed
if (model_object->volumes.empty())
{
p->object_info->Show(false);
return;
}
const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr; const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr;
auto size = model_object->instance_bounding_box(0).size(); auto size = model_object->instance_bounding_box(0).size();
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2))); p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2)));
p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count()))); p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count())));
auto& stats = model_object->volumes[0]->mesh.stl.stats; auto& stats = model_object->volumes.front()->mesh.stl.stats;
auto sf = model_instance->get_scaling_factor(); auto sf = model_instance->get_scaling_factor();
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume * sf(0) * sf(1) * sf(2))); p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume * sf(0) * sf(1) * sf(2)));
p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast<int>(model_object->facets_count()), stats.number_of_parts)); p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast<int>(model_object->facets_count()), stats.number_of_parts));
@ -743,12 +741,11 @@ void Sidebar::update_info_sizer()
} }
p->object_info->show_sizer(true); p->object_info->show_sizer(true);
p->scrolled->Layout();
} }
void Sidebar::show_sliced_info_sizer(const bool show) void Sidebar::show_sliced_info_sizer(const bool show)
{ {
wxWindowUpdateLocker freeze_guard(p->scrolled); wxWindowUpdateLocker freeze_guard(this);
p->sliced_info->Show(show); p->sliced_info->Show(show);
if (show) { if (show) {
@ -777,7 +774,7 @@ void Sidebar::show_sliced_info_sizer(const bool show)
p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->print().wipe_tower_data().number_of_toolchanges) : "N/A"); p->sliced_info->SetTextAndShow(siWTNumbetOfToolchanges, is_wipe_tower ? wxString::Format("%.d", p->plater->print().wipe_tower_data().number_of_toolchanges) : "N/A");
} }
p->scrolled->Layout(); Layout();
} }
void Sidebar::show_buttons(const bool show) void Sidebar::show_buttons(const bool show)
@ -787,7 +784,7 @@ void Sidebar::show_buttons(const bool show)
TabPrinter *tab = dynamic_cast<TabPrinter*>(wxGetApp().tab_panel()->GetPage(i)); TabPrinter *tab = dynamic_cast<TabPrinter*>(wxGetApp().tab_panel()->GetPage(i));
if (!tab) if (!tab)
continue; continue;
if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) { if (p->plater->printer_technology() == ptFFF) {
p->btn_send_gcode->Show(show && !tab->m_config->opt_string("print_host").empty()); p->btn_send_gcode->Show(show && !tab->m_config->opt_string("print_host").empty());
} }
break; break;
@ -877,10 +874,11 @@ struct Plater::priv
// Data // Data
Slic3r::DynamicPrintConfig *config; Slic3r::DynamicPrintConfig *config;
Slic3r::Print print; Slic3r::Print print;
Slic3r::SLAPrint sla_print; Slic3r::SLAPrint sla_print;
Slic3r::Model model; Slic3r::Model model;
Slic3r::GCodePreviewData gcode_preview_data; PrinterTechnology printer_technology = ptFFF;
Slic3r::GCodePreviewData gcode_preview_data;
// GUI elements // GUI elements
wxNotebook *notebook; wxNotebook *notebook;
@ -916,14 +914,28 @@ struct Plater::priv
void object_list_changed(); void object_list_changed();
void remove(size_t obj_idx); void remove(size_t obj_idx);
void delete_object_from_model(size_t obj_idx);
void reset(); void reset();
void mirror(Axis axis); void mirror(Axis axis);
void arrange(); void arrange();
void split_object(); void split_object();
void split_volume(); void split_volume();
void schedule_background_process(); void schedule_background_process();
// Update background processing thread from the current config and Model.
enum UpdateBackgroundProcessReturnState {
// update_background_process() reports, that the Print / SLAPrint was updated in a way,
// that the background process was invalidated and it needs to be re-run.
UPDATE_BACKGROUND_PROCESS_RESTART = 1,
// update_background_process() reports, that the Print / SLAPrint was updated in a way,
// that a scene needs to be refreshed (you should call _3DScene::reload_scene(canvas3D, false))
UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE = 2,
// update_background_process() reports, that the Print / SLAPrint is invalid, and the error message
// was sent to the status line.
UPDATE_BACKGROUND_PROCESS_INVALID = 4,
};
// returns bit mask of UpdateBackgroundProcessReturnState
unsigned int update_background_process();
void async_apply_config(); void async_apply_config();
void start_background_process();
void reload_from_disk(); void reload_from_disk();
void export_object_stl(); void export_object_stl();
void fix_through_netfabb(const int obj_idx); void fix_through_netfabb(const int obj_idx);
@ -989,7 +1001,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
background_process.set_sliced_event(EVT_SLICING_COMPLETED); background_process.set_sliced_event(EVT_SLICING_COMPLETED);
background_process.set_finished_event(EVT_PROCESS_COMPLETED); background_process.set_finished_event(EVT_PROCESS_COMPLETED);
// Default printer technology for default config. // Default printer technology for default config.
background_process.select_technology(q->printer_technology()); background_process.select_technology(this->printer_technology);
// Register progress callback from the Print class to the Platter. // Register progress callback from the Print class to the Platter.
auto statuscb = [this](int percent, const std::string &message) { auto statuscb = [this](int percent, const std::string &message) {
@ -1013,6 +1025,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) :
// XXX: more config from 3D.pm // XXX: more config from 3D.pm
_3DScene::set_model(canvas3D, &model); _3DScene::set_model(canvas3D, &model);
_3DScene::set_print(canvas3D, &print); _3DScene::set_print(canvas3D, &print);
_3DScene::set_SLA_print(canvas3D, &sla_print);
_3DScene::set_config(canvas3D, config); _3DScene::set_config(canvas3D, config);
_3DScene::enable_gizmos(canvas3D, true); _3DScene::enable_gizmos(canvas3D, true);
_3DScene::enable_toolbar(canvas3D, true); _3DScene::enable_toolbar(canvas3D, true);
@ -1095,6 +1108,11 @@ void Plater::priv::update(bool force_autocenter)
model.center_instances_around_point(bed_center); model.center_instances_around_point(bed_center);
} }
if (this->printer_technology == ptSLA) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data.
this->update_background_process();
}
_3DScene::reload_scene(canvas3D, false); _3DScene::reload_scene(canvas3D, false);
preview->reset_gcode_preview_data(); preview->reset_gcode_preview_data();
preview->reload_print(); preview->reload_print();
@ -1416,8 +1434,6 @@ void Plater::priv::selection_changed()
_3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed()); _3DScene::enable_toolbar_item(canvas3D, "layersediting", layers_height_allowed());
// forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears) // forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears)
_3DScene::render(canvas3D); _3DScene::render(canvas3D);
sidebar->update_info_sizer();
} }
void Plater::priv::object_list_changed() void Plater::priv::object_list_changed()
@ -1450,6 +1466,12 @@ void Plater::priv::remove(size_t obj_idx)
update(); update();
} }
void Plater::priv::delete_object_from_model(size_t obj_idx)
{
model.delete_object(obj_idx);
}
void Plater::priv::reset() void Plater::priv::reset()
{ {
// Prevent toolpaths preview from rendering while we modify the Print object // Prevent toolpaths preview from rendering while we modify the Print object
@ -1610,10 +1632,18 @@ void Plater::priv::schedule_background_process()
this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); this->background_process_timer.Start(500, wxTIMER_ONE_SHOT);
} }
void Plater::priv::async_apply_config() // Update background processing thread from the current config and Model.
// Returns a bitmask of UpdateBackgroundProcessReturnState.
unsigned int Plater::priv::update_background_process()
{ {
// bitmap of enum UpdateBackgroundProcessReturnState
unsigned int return_state = 0;
// If the async_apply_config() was not called by the timer, kill the timer, so the async_apply_config()
// will not be called again in vain.
this->background_process_timer.Stop();
DynamicPrintConfig config = wxGetApp().preset_bundle->full_config(); DynamicPrintConfig config = wxGetApp().preset_bundle->full_config();
auto printer_technology = config.opt_enum<PrinterTechnology>("printer_technology");
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.opt<ConfigOptionPoints>("bed_shape")->values)); BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.opt<ConfigOptionPoints>("bed_shape")->values));
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.opt_float("max_print_height")))); BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.opt_float("max_print_height"))));
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced. // Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
@ -1634,40 +1664,55 @@ void Plater::priv::async_apply_config()
// Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
// Otherwise they will be just refreshed. // Otherwise they will be just refreshed.
this->gcode_preview_data.reset(); this->gcode_preview_data.reset();
if (printer_technology == ptFFF) { switch (this->printer_technology) {
case ptFFF:
if (this->preview != nullptr) if (this->preview != nullptr)
// If the preview is not visible, the following line just invalidates the preview,
// but the G-code paths are calculated first once the preview is made visible.
this->preview->reload_print(); this->preview->reload_print();
// We also need to reload 3D scene because of the wipe tower preview box // We also need to reload 3D scene because of the wipe tower preview box
if (this->config->opt_bool("wipe_tower")) { if (this->config->opt_bool("wipe_tower")) {
// std::vector<int> selections = this->collect_selections(); // std::vector<int> selections = this->collect_selections();
// Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections); // Slic3r::_3DScene::set_objects_selections(this->canvas3D, selections);
// Slic3r::_3DScene::reload_scene(this->canvas3D, 1); return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
} }
break;
case ptSLA:
//FIXME as of now the Print::APPLY_STATUS_INVALIDATED is not reliable, and
// currently the scene refresh is expensive and loses selection.
//return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE;
break;
} }
} }
if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->get_config("background_processing") == "1" &&
this->background_process.start()) if (! this->background_process.empty()) {
this->statusbar()->set_cancel_callback([this]() { std::string err = this->background_process.validate();
this->statusbar()->set_status_text(L("Cancelling")); if (err.empty()) {
this->background_process.stop(); if (invalidated != Print::APPLY_STATUS_UNCHANGED)
}); return_state |= UPDATE_BACKGROUND_PROCESS_RESTART;
} else {
// The print is not valid.
GUI::show_error(this->q, _(err));
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
}
}
return return_state;
} }
void Plater::priv::start_background_process() void Plater::priv::async_apply_config()
{ {
if (this->background_process.running()) // bitmask of UpdateBackgroundProcessReturnState
return; unsigned int state = this->update_background_process();
// Don't start process thread if Print is not valid. if (state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE)
std::string err = this->background_process.validate(); _3DScene::reload_scene(canvas3D, false);
if (! err.empty()) { if ((state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 && this->get_config("background_processing") == "1") {
this->statusbar()->set_status_text(err); // The print is valid and it can be started.
} else { if (this->background_process.start())
// Copy the names of active presets into the placeholder parser. this->statusbar()->set_cancel_callback([this]() {
//FIXME how to generate a file name for the SLA printers? this->statusbar()->set_status_text(L("Cancelling"));
wxGetApp().preset_bundle->export_selections(this->q->print().placeholder_parser()); this->background_process.stop();
// Start the background process. });
this->background_process.start(); }
}
} }
void Plater::priv::reload_from_disk() void Plater::priv::reload_from_disk()
@ -1716,6 +1761,13 @@ void Plater::priv::on_notebook_changed(wxBookCtrlEvent&)
const auto current_id = notebook->GetCurrentPage()->GetId(); const auto current_id = notebook->GetCurrentPage()->GetId();
if (current_id == canvas3D->GetId()) { if (current_id == canvas3D->GetId()) {
if (_3DScene::is_reload_delayed(canvas3D)) { if (_3DScene::is_reload_delayed(canvas3D)) {
// Delayed loading of the 3D scene.
if (this->printer_technology == ptSLA) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data.
if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART)
this->schedule_background_process();
}
_3DScene::reload_scene(canvas3D, true); _3DScene::reload_scene(canvas3D, true);
} }
// sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
@ -1811,22 +1863,18 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
//$self->object_list_changed; //$self->object_list_changed;
// refresh preview // refresh preview
if (this->preview != nullptr) switch (this->printer_technology) {
this->preview->reload_print(); case ptFFF:
if (this->preview != nullptr)
// TODO: this needs to be implemented somehow this->preview->reload_print();
if(q->printer_technology() == PrinterTechnology::ptSLA) { break;
case ptSLA:
class Renderer: public SLASupportRenderer { // Update the SLAPrint from the current Model, so that the reload_scene()
public: // pulls the correct data.
void add_pillar(const Mesh&, ClickCb ) override {} if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART)
void add_head(const Mesh&, ClickCb) override {} this->schedule_background_process();
void add_bridge(const Mesh&, ClickCb) override {} _3DScene::reload_scene(canvas3D, true);
void add_junction(const Mesh&, ClickCb) override {} break;
void add_pad(const Mesh&, ClickCb) override {}
} renderer;
sla_print.render_supports(renderer);
} }
} }
@ -2069,6 +2117,7 @@ void Plater::update(bool force_autocenter) { p->update(force_autocenter); }
void Plater::select_view(const std::string& direction) { p->select_view(direction); } void Plater::select_view(const std::string& direction) { p->select_view(direction); }
void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::remove(size_t obj_idx) { p->remove(obj_idx); }
void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); }
void Plater::remove_selected() void Plater::remove_selected()
{ {
@ -2285,21 +2334,24 @@ void Plater::export_3mf()
} }
} }
void Plater::reslice() void Plater::reslice()
{ {
// explicitly cancel a previous thread and start a new one. //FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// Don't reslice if export of G-code or sending to OctoPrint is running. // bitmask of UpdateBackgroundProcessReturnState
// if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) { unsigned int state = this->p->update_background_process();
// Stop the background processing threads, stop the async update timer. if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE)
// this->p->stop_background_process(); _3DScene::reload_scene(this->p->canvas3D, false);
// Rather perform one additional unnecessary update of the print object instead of skipping a pending async update. if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) == 0 && !this->p->background_process.running()) {
this->p->async_apply_config(); // The print is valid and it can be started.
this->p->statusbar()->set_cancel_callback([this]() { // Copy the names of active presets into the placeholder parser.
this->p->statusbar()->set_status_text(L("Cancelling")); //FIXME how to generate a file name for the SLA printers?
this->p->background_process.stop(); wxGetApp().preset_bundle->export_selections(this->print().placeholder_parser());
}); if (this->p->background_process.start())
this->p->start_background_process(); this->p->statusbar()->set_cancel_callback([this]() {
this->p->statusbar()->set_status_text(L("Cancelling"));
this->p->background_process.stop();
});
}
} }
void Plater::send_gcode() void Plater::send_gcode()
@ -2338,8 +2390,10 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
bool update_scheduled = false; bool update_scheduled = false;
for (auto opt_key : p->config->diff(config)) { for (auto opt_key : p->config->diff(config)) {
p->config->set_key_value(opt_key, config.option(opt_key)->clone()); p->config->set_key_value(opt_key, config.option(opt_key)->clone());
if (opt_key == "printer_technology") if (opt_key == "printer_technology") {
p->background_process.select_technology(config.opt_enum<PrinterTechnology>(opt_key)); p->printer_technology = config.opt_enum<PrinterTechnology>(opt_key);
p->background_process.select_technology(this->printer_technology());
}
else if (opt_key == "bed_shape") { else if (opt_key == "bed_shape") {
if (p->canvas3D) _3DScene::set_bed_shape(p->canvas3D, p->config->option<ConfigOptionPoints>(opt_key)->values); if (p->canvas3D) _3DScene::set_bed_shape(p->canvas3D, p->config->option<ConfigOptionPoints>(opt_key)->values);
if (p->preview) p->preview->set_bed_shape(p->config->option<ConfigOptionPoints>(opt_key)->values); if (p->preview) p->preview->set_bed_shape(p->config->option<ConfigOptionPoints>(opt_key)->values);
@ -2393,7 +2447,7 @@ int Plater::get_selected_object_idx()
return p->get_selected_object_idx(); return p->get_selected_object_idx();
} }
bool Plater::is_single_full_object_selection() bool Plater::is_single_full_object_selection() const
{ {
return p->get_selection().is_single_full_object(); return p->get_selection().is_single_full_object();
} }
@ -2405,7 +2459,7 @@ wxGLCanvas* Plater::canvas3D()
PrinterTechnology Plater::printer_technology() const PrinterTechnology Plater::printer_technology() const
{ {
return wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); return p->printer_technology;
} }
void Plater::changed_object(int obj_idx) void Plater::changed_object(int obj_idx)

View File

@ -62,6 +62,7 @@ enum ButtonAction
class Sidebar : public wxPanel class Sidebar : public wxPanel
{ {
/*ConfigMenuIDs*/int m_mode;
public: public:
Sidebar(Plater *parent); Sidebar(Plater *parent);
Sidebar(Sidebar &&) = delete; Sidebar(Sidebar &&) = delete;
@ -82,13 +83,13 @@ public:
ConfigOptionsGroup* og_freq_chng_params(); ConfigOptionsGroup* og_freq_chng_params();
wxButton* get_wiping_dialog_button(); wxButton* get_wiping_dialog_button();
void update_objects_list_extruder_column(int extruders_count); void update_objects_list_extruder_column(int extruders_count);
void show_info_sizer(const bool show); void show_info_sizer();
void update_info_sizer();
void show_sliced_info_sizer(const bool show); void show_sliced_info_sizer(const bool show);
void show_buttons(const bool show); void show_buttons(const bool show);
void show_button(ButtonAction but_action, bool show); void show_button(ButtonAction but_action, bool show);
void enable_buttons(bool enable); void enable_buttons(bool enable);
bool is_multifilament(); bool is_multifilament();
void set_mode_value(const /*ConfigMenuIDs*/int mode) { m_mode = mode; }
std::vector<PresetComboBox*>& combos_filament(); std::vector<PresetComboBox*>& combos_filament();
private: private:
@ -118,6 +119,7 @@ public:
void select_view(const std::string& direction); void select_view(const std::string& direction);
void remove(size_t obj_idx); void remove(size_t obj_idx);
void delete_object_from_model(size_t obj_idx);
void remove_selected(); void remove_selected();
void increase_instances(size_t num = 1); void increase_instances(size_t num = 1);
void decrease_instances(size_t num = 1); void decrease_instances(size_t num = 1);
@ -137,7 +139,7 @@ public:
void on_config_change(const DynamicPrintConfig &config); void on_config_change(const DynamicPrintConfig &config);
int get_selected_object_idx(); int get_selected_object_idx();
bool is_single_full_object_selection(); bool is_single_full_object_selection() const;
wxGLCanvas* canvas3D(); wxGLCanvas* canvas3D();
PrinterTechnology printer_technology() const; PrinterTechnology printer_technology() const;