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

This commit is contained in:
tamasmeszaros 2018-11-07 15:30:41 +01:00
commit 97b3d94760
55 changed files with 1903 additions and 808 deletions

View file

@ -193,6 +193,7 @@ const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
GLVolume::GLVolume(float r, float g, float b, float a)
#if ENABLE_MODELVOLUME_TRANSFORM
@ -211,6 +212,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, composite_id(-1)
, extruder_id(0)
, selected(false)
, disabled(false)
, is_active(true)
, zoom_to_volumes(true)
, shader_outside_printer_detection_enabled(false)
@ -252,6 +254,8 @@ void GLVolume::set_render_color()
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
else if (hover)
set_render_color(HOVER_COLOR, 4);
else if (disabled)
set_render_color(DISABLED_COLOR, 4);
else if (is_outside && shader_outside_printer_detection_enabled)
set_render_color(OUTSIDE_COLOR, 4);
else
@ -723,7 +727,11 @@ std::vector<int> GLVolumeCollection::load_object(
for (int instance_idx : instance_idxs) {
const ModelInstance *instance = model_object->instances[instance_idx];
#if ENABLE_MODELVOLUME_TRANSFORM
const TriangleMesh& mesh = model_volume->mesh;
#else
TriangleMesh mesh = model_volume->mesh;
#endif // ENABLE_MODELVOLUME_TRANSFORM
volumes_idx.push_back(int(this->volumes.size()));
float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
@ -758,7 +766,8 @@ std::vector<int> GLVolumeCollection::load_object(
v.is_modifier = ! model_volume->is_model_part();
v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
#if ENABLE_MODELVOLUME_TRANSFORM
v.set_transformation(instance->get_transformation());
v.set_instance_transformation(instance->get_transformation());
v.set_volume_transformation(model_volume->get_transformation());
#else
v.set_offset(instance->get_offset());
v.set_rotation(instance->get_rotation());
@ -833,7 +842,11 @@ int GLVolumeCollection::load_wipe_tower_preview(
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
#if ENABLE_MODELVOLUME_TRANSFORM
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
#else
v.set_offset(Vec3d(pos_x, pos_y, 0.0));
#endif // ENABLE_MODELVOLUME_TRANSFORM
// 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();

View file

@ -249,13 +249,15 @@ public:
static const float HOVER_COLOR[4];
static const float OUTSIDE_COLOR[4];
static const float SELECTED_OUTSIDE_COLOR[4];
static const float DISABLED_COLOR[4];
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
private:
#if ENABLE_MODELVOLUME_TRANSFORM
Geometry::Transformation m_transformation;
Geometry::Transformation m_instance_transformation;
Geometry::Transformation m_volume_transformation;
#else
// Offset of the volume to be rendered.
Vec3d m_offset;
@ -294,6 +296,8 @@ public:
int extruder_id;
// Is this object selected?
bool selected;
// Is this object disabled from selection?
bool disabled;
// Whether or not this volume is active for rendering
bool is_active;
// Whether or not to use this volume when applying zoom_to_volumes()
@ -329,32 +333,59 @@ public:
void set_render_color();
#if ENABLE_MODELVOLUME_TRANSFORM
const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; set_bounding_boxes_as_dirty(); }
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_instance_rotation(Axis axis, double rotation) { m_instance_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
Vec3d get_instance_scaling_factor() const { return m_instance_transformation.get_scaling_factor(); }
double get_instance_scaling_factor(Axis axis) const { return m_instance_transformation.get_scaling_factor(axis); }
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
void set_instance_mirror(Axis axis, double mirror) { m_instance_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
#else
const Vec3d& get_rotation() const;
void set_rotation(const Vec3d& rotation);
@ -378,7 +409,7 @@ public:
int instance_idx() const { return this->composite_id % 1000; }
#if ENABLE_MODELVOLUME_TRANSFORM
const Transform3d& world_matrix() const { return m_transformation.get_matrix(); }
Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); }
#else
const Transform3f& world_matrix() const;
#endif // ENABLE_MODELVOLUME_TRANSFORM

View file

@ -1,6 +1,7 @@
#include "BackgroundSlicingProcess.hpp"
#include "GUI_App.hpp"
#include <wx/app.h>
#include <wx/event.h>
#include <wx/panel.h>
#include <wx/stdpaths.h>
@ -103,6 +104,15 @@ void BackgroundSlicingProcess::thread_proc()
// End of the background processing thread. The UI thread should join m_thread now.
}
void BackgroundSlicingProcess::thread_proc_safe()
{
try {
this->thread_proc();
} catch (...) {
wxTheApp->OnUnhandledException();
}
}
void BackgroundSlicingProcess::join_background_thread()
{
std::unique_lock<std::mutex> lck(m_mutex);
@ -127,7 +137,7 @@ bool BackgroundSlicingProcess::start()
if (m_state == STATE_INITIAL) {
// The worker thread is not running yet. Start it.
assert(! m_thread.joinable());
m_thread = std::thread([this]{this->thread_proc();});
m_thread = std::thread([this]{this->thread_proc_safe();});
// Wait until the worker thread is ready to execute the background processing task.
m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; });
}

View file

@ -80,6 +80,7 @@ public:
private:
void thread_proc();
void thread_proc_safe();
void join_background_thread();
// To be called by Print::apply() through the Print::m_cancel_callback to stop the background
// processing before changing any data of running or finalized milestones.

File diff suppressed because it is too large Load diff

View file

@ -358,9 +358,14 @@ public:
enum EMode : unsigned char
{
#if ENABLE_MODELVOLUME_TRANSFORM
Volume,
Instance
#else
Volume,
Instance,
Object
#endif // ENABLE_MODELVOLUME_TRANSFORM
};
enum EType : unsigned char
@ -368,9 +373,13 @@ public:
Invalid,
Empty,
WipeTower,
Modifier,
SingleModifier,
MultipleModifier,
SingleVolume,
MultipleVolume,
SingleFullObject,
SingleFullInstance,
MultipleFullInstance,
Mixed
};
@ -378,21 +387,57 @@ public:
struct VolumeCache
{
private:
#if ENABLE_MODELVOLUME_TRANSFORM
struct TransformCache
{
Vec3d position;
Vec3d rotation;
Vec3d scaling_factor;
Transform3d rotation_matrix;
Transform3d scale_matrix;
TransformCache();
explicit TransformCache(const Geometry::Transformation& transform);
};
TransformCache m_volume;
TransformCache m_instance;
#else
Vec3d m_position;
Vec3d m_rotation;
Vec3d m_scaling_factor;
Transform3d m_rotation_matrix;
Transform3d m_scale_matrix;
#endif // ENABLE_MODELVOLUME_TRANSFORM
public:
#if ENABLE_MODELVOLUME_TRANSFORM
VolumeCache() {}
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
#else
VolumeCache();
VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor);
#endif // ENABLE_MODELVOLUME_TRANSFORM
#if ENABLE_MODELVOLUME_TRANSFORM
const Vec3d& get_volume_position() const { return m_volume.position; }
const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
const Vec3d& get_instance_position() const { return m_instance.position; }
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; }
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
#else
const Vec3d& get_position() const { return m_position; }
const Vec3d& get_rotation() const { return m_rotation; }
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
const Transform3d& get_rotation_matrix() const { return m_rotation_matrix; }
const Transform3d& get_scale_matrix() const { return m_scale_matrix; }
#endif // ENABLE_MODELVOLUME_TRANSFORM
};
typedef std::map<unsigned int, VolumeCache> VolumesCache;
@ -435,14 +480,14 @@ public:
void add_instance(unsigned int object_idx, unsigned int instance_idx, bool as_single_selection = true);
void remove_instance(unsigned int object_idx, unsigned int instance_idx);
void add_volume(unsigned int object_idx, unsigned int volume_idx, bool as_single_selection = true);
void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection = true);
void remove_volume(unsigned int object_idx, unsigned int volume_idx);
void clear();
bool is_empty() const { return m_type == Empty; }
bool is_wipe_tower() const { return m_type == WipeTower; }
bool is_modifier() const { return m_type == Modifier; }
bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); }
bool is_single_full_instance() const;
bool is_single_full_object() const { return m_type == SingleFullObject; }
bool is_mixed() const { return m_type == Mixed; }
@ -455,6 +500,9 @@ public:
int get_object_idx() const;
// Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1
int get_instance_idx() const;
// Returns the indices of selected instances.
// Can only be called if selection is from a single object.
const InstanceIdxsList& get_instance_idxs() const;
const IndicesList& get_volume_idxs() const { return m_list; }
const GLVolume* get_volume(unsigned int volume_idx) const;
@ -466,13 +514,14 @@ public:
void translate(const Vec3d& displacement);
void rotate(const Vec3d& rotation);
void flattening_rotate(const Vec3d& normal);
void scale(const Vec3d& scale);
void mirror(Axis axis);
void translate(unsigned int object_idx, const Vec3d& displacement);
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
void render(bool show_indirect_selection) const;
void render() const;
private:
void _update_valid();
@ -486,9 +535,10 @@ public:
void _remove_object(unsigned int object_idx);
void _calc_bounding_box() const;
void _render_selected_volumes() const;
void _render_unselected_instances() const;
void _render_synchronized_volumes() const;
void _render_bounding_box(const BoundingBoxf3& box, float* color) const;
void _synchronize_unselected_instances();
void _synchronize_unselected_volumes();
};
private:
@ -556,7 +606,7 @@ private:
Vec3d get_rotation() const;
void set_rotation(const Vec3d& rotation);
Vec3d get_flattening_rotation() const;
Vec3d get_flattening_normal() const;
void set_flattening_data(const ModelObject* model_object);

View file

@ -720,7 +720,11 @@ void GLGizmoScale3D::on_process_double_click()
void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
{
bool single_instance = selection.is_single_full_instance();
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>() : 100.0f * m_scale.cast<float>();
#else
Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_scaling_factor().cast<float>() : 100.0f * m_scale.cast<float>();
#endif // ENABLE_MODELVOLUME_TRANSFORM
if ((single_instance && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging)
set_tooltip("X: " + format(scale(0), 4) + "%");
@ -762,10 +766,18 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
#endif // ENABLE_MODELVOLUME_TRANSFORM
// gets angles from first selected volume
#if ENABLE_MODELVOLUME_TRANSFORM
angles = v->get_instance_rotation();
#else
angles = v->get_rotation();
#endif // ENABLE_MODELVOLUME_TRANSFORM
// consider rotation+mirror only components of the transform for offsets
#if ENABLE_MODELVOLUME_TRANSFORM
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
#else
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror());
#endif // ENABLE_MODELVOLUME_TRANSFORM
}
else
box = selection.get_bounding_box();
@ -1165,38 +1177,41 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection)
void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const
{
// the dragged_offset is a vector measuring where was the object moved
// with the gizmo being on. This is reset in set_flattening_data and
// does not work correctly when there are multiple copies.
// The planes are rendered incorrectly when the object is being moved. We better won't render anything in that case.
// This indeed has a better solution (to be implemented when there is more time)
Vec3d dragged_offset(Vec3d::Zero());
if (m_starting_center == Vec3d::Zero())
m_starting_center = selection.get_bounding_box().center();
dragged_offset = selection.get_bounding_box().center() - m_starting_center;
if (dragged_offset.norm() > 0.001)
return;
::glEnable(GL_BLEND);
::glEnable(GL_DEPTH_TEST);
::glDisable(GL_CULL_FACE);
for (int i=0; i<(int)m_planes.size(); ++i) {
if (i == m_hover_id)
::glColor4f(0.9f, 0.9f, 0.9f, 0.75f);
else
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
if (selection.is_from_single_object()) {
const std::set<int>& instances_list = selection.get_instance_idxs();
int instance_idx = selection.get_instance_idx();
if ((instance_idx != -1) && (m_model_object != nullptr))
{
if (!instances_list.empty() && m_model_object) {
for (const int instance_idx : instances_list) {
Transform3d m = m_model_object->instances[instance_idx]->get_matrix();
m.pretranslate(dragged_offset);
::glPushMatrix();
::glMultMatrixd(m.data());
::glBegin(GL_POLYGON);
for (const Vec3d& vertex : m_planes[i].vertices)
{
::glVertex3dv(vertex.data());
for (int i=0; i<(int)m_planes.size(); ++i) {
if (i == m_hover_id)
::glColor4f(0.9f, 0.9f, 0.9f, 0.75f);
else
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
m.pretranslate(dragged_offset);
::glPushMatrix();
::glMultMatrixd(m.data());
::glBegin(GL_POLYGON);
for (const Vec3d& vertex : m_planes[i].vertices)
::glVertex3dv(vertex.data());
::glEnd();
::glPopMatrix();
}
}
::glEnd();
::glPopMatrix();
}
}
@ -1208,22 +1223,21 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
{
::glEnable(GL_DEPTH_TEST);
::glDisable(GL_CULL_FACE);
for (unsigned int i = 0; i < m_planes.size(); ++i)
{
::glColor3f(1.0f, 1.0f, picking_color_component(i));
int instance_idx = selection.get_instance_idx();
if ((instance_idx != -1) && (m_model_object != nullptr))
{
::glPushMatrix();
::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data());
::glBegin(GL_POLYGON);
for (const Vec3d& vertex : m_planes[i].vertices)
{
::glVertex3dv(vertex.data());
if (selection.is_from_single_object()) {
const std::set<int>& instances_list = selection.get_instance_idxs();
if (!instances_list.empty() && m_model_object) {
for (const int instance_idx : instances_list) {
for (int i=0; i<(int)m_planes.size(); ++i) {
::glColor3f(1.0f, 1.0f, picking_color_component(i));
::glPushMatrix();
::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data());
::glBegin(GL_POLYGON);
for (const Vec3d& vertex : m_planes[i].vertices)
::glVertex3dv(vertex.data());
::glEnd();
::glPopMatrix();
}
}
::glEnd();
::glPopMatrix();
}
}
@ -1233,9 +1247,10 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
{
m_starting_center = Vec3d::Zero();
bool object_changed = m_model_object != model_object;
m_model_object = model_object;
if (is_plane_update_necessary())
if (object_changed && is_plane_update_necessary())
update_planes();
}
@ -1243,7 +1258,15 @@ void GLGizmoFlatten::update_planes()
{
TriangleMesh ch;
for (const ModelVolume* vol : m_model_object->volumes)
#if ENABLE_MODELVOLUME_TRANSFORM
{
TriangleMesh vol_ch = vol->get_convex_hull();
vol_ch.transform(vol->get_matrix());
ch.merge(vol_ch);
}
#else
ch.merge(vol->get_convex_hull());
#endif // ENABLE_MODELVOLUME_TRANSFORM
ch = ch.convex_hull_3d();
@ -1438,20 +1461,14 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
return false;
}
Vec3d GLGizmoFlatten::get_flattening_rotation() const
Vec3d GLGizmoFlatten::get_flattening_normal() const
{
// calculates the rotations in model space, taking in account the scaling factors
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m = m_model_object->instances.front()->get_matrix(true, true).matrix().block(0, 0, 3, 3).inverse().transpose();
Eigen::Quaterniond q;
Vec3d angles = Geometry::extract_euler_angles(q.setFromTwoVectors(m * m_normal, -Vec3d::UnitZ()).toRotationMatrix());
Vec3d out = m_normal;
m_normal = Vec3d::Zero();
m_starting_center = Vec3d::Zero();
return angles;
return out;
}
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent)
: GLGizmoBase(parent), m_starting_center(Vec3d::Zero())
{
@ -1478,11 +1495,14 @@ bool GLGizmoSlaSupports::on_init()
void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object)
{
m_starting_center = Vec3d::Zero();
m_model_object = model_object;
m_model_object_matrix = model_object->instances.front()->get_matrix();
if (is_mesh_update_necessary())
update_mesh();
if (model_object != nullptr)
{
m_starting_center = Vec3d::Zero();
m_model_object = model_object;
m_model_object_matrix = model_object->instances.front()->get_matrix();
if (is_mesh_update_necessary())
update_mesh();
}
}
void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const

View file

@ -359,6 +359,7 @@ private:
std::vector<PlaneData> m_planes;
mutable Vec3d m_starting_center;
const ModelObject* m_model_object = nullptr;
std::vector<const Transform3d*> instances_matrices;
void update_planes();
bool is_plane_update_necessary() const;
@ -367,12 +368,12 @@ public:
explicit GLGizmoFlatten(GLCanvas3D& parent);
void set_flattening_data(const ModelObject* model_object);
Vec3d get_flattening_rotation() const;
Vec3d get_flattening_normal() const;
protected:
virtual bool on_init();
virtual std::string on_get_name() const;
virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return selection.is_single_full_instance(); }
virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return (selection.is_from_single_object() && !selection.is_wipe_tower() && !selection.is_modifier()); }
virtual void on_start_dragging(const GLCanvas3D::Selection& selection);
virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) {}
virtual void on_render(const GLCanvas3D::Selection& selection) const;

View file

@ -60,7 +60,7 @@ enum ConfigMenuIDs {
class Tab;
static wxString dots("", wxConvUTF8);
static wxString dots("", wxConvUTF8);
class GUI_App : public wxApp
{

View file

@ -36,11 +36,11 @@ ObjectList::ObjectList(wxWindow* parent) :
CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG);
}
init_icons();
// create control
create_objects_ctrl();
init_icons();
// describe control behavior
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) {
selection_changed();
@ -213,17 +213,27 @@ void ObjectList::update_extruder_in_config(const wxString& selection)
void ObjectList::init_icons()
{
m_bmp_modifiermesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
m_bmp_solidmesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
m_bmp_modifiermesh = wxBitmap(from_u8(var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
m_bmp_solidmesh = wxBitmap(from_u8(var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
m_bmp_support_enforcer = wxBitmap(from_u8(var("support_enforcer_.png")), wxBITMAP_TYPE_PNG);
m_bmp_support_blocker = wxBitmap(from_u8(var("support_blocker_.png")), wxBITMAP_TYPE_PNG);
m_bmp_vector.reserve(4); // bitmaps for different types of parts
m_bmp_vector.push_back(&m_bmp_solidmesh); // Add part
m_bmp_vector.push_back(&m_bmp_modifiermesh); // Add modifier
m_bmp_vector.push_back(&m_bmp_support_enforcer); // Add support enforcer
m_bmp_vector.push_back(&m_bmp_support_blocker); // Add support blocker
m_objects_model->SetVolumeBitmaps(m_bmp_vector);
// init icon for manifold warning
m_bmp_manifold_warning = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
m_bmp_manifold_warning = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
// init bitmap for "Split to sub-objects" context menu
m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG);
m_bmp_split = wxBitmap(from_u8(var("split.png")), wxBITMAP_TYPE_PNG);
// init bitmap for "Add Settings" context menu
m_bmp_cog = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
m_bmp_cog = wxBitmap(from_u8(var("cog.png")), wxBITMAP_TYPE_PNG);
}
@ -377,7 +387,8 @@ void ObjectList::on_drop(wxDataViewEvent &event)
wxDataViewItem item(event.GetItem());
// only allow drops for item, not containers
if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
if (m_selected_object_id < 0 ||
item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->GetItemType(item) != itVolume) {
event.Veto();
return;
@ -518,16 +529,24 @@ void ObjectList::get_settings_choice(wxMenu *menu, int id, bool is_part)
wxGetApp().obj_manipul()->update_settings_list();
}
void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id) {
void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id, const int type) {
auto sub_menu = new wxMenu;
const wxString menu_load = _(L("Load")) +" "+ dots;
sub_menu->Append(new wxMenuItem(sub_menu, id++, menu_load));
sub_menu->AppendSeparator();
std::vector<std::string> menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") };
for (auto& item : menu_items)
sub_menu->Append(new wxMenuItem(sub_menu, ++id, _(item)));
sub_menu->Append(new wxMenuItem(sub_menu, id++, _(item)));
#ifndef __WXMSW__
sub_menu->Bind(wxEVT_MENU, [this, sub_menu](wxEvent &event) {
load_lambda(sub_menu->GetLabel(event.GetId()).ToStdString());
sub_menu->Bind(wxEVT_MENU, [sub_menu, type, menu_load, this](wxEvent &event) {
auto selection = sub_menu->GetLabel(event.GetId());
if (selection == menu_load)
load_subobject(type);
else
load_generic_subobject(selection.ToStdString(), type);
});
#endif //no __WXMSW__
@ -552,55 +571,53 @@ wxMenuItem* ObjectList::menu_item_settings(wxMenu* menu, int id, const bool is_p
wxMenu* ObjectList::create_add_part_popupmenu()
{
wxMenu *menu = new wxMenu;
std::vector<std::string> menu_items = { L("Add part"), L("Add modifier"), L("Add generic") };
// Note: id accords to type of the sub-object, so sequence of the menu items is important
std::vector<std::string> menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART
L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER
L("Add support enforcer"), // ~ModelVolume::SUPPORT_ENFORCER
L("Add support bloker") }; // ~ModelVolume::SUPPORT_BLOCKER
const int obj_types_count = menu_object_types_items.size();
const int generics_count = 5; // "Load ...", "Box", "Cylinder", "Sphere", "Slab"
wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size() + 4 + 2);
wxWindowID config_id_base = NewControlId(generics_count*obj_types_count + 2);
int i = 0;
for (auto& item : menu_items) {
auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item));
menu_item->SetBitmap(i == 0 ? m_bmp_solidmesh : m_bmp_modifiermesh);
if (item == "Add generic")
menu_item_add_generic(menu_item, config_id_base + i);
// Add first 4 menu items
for (int type = 0; type < obj_types_count; type++) {
auto& item = menu_object_types_items[type];
auto menu_item = new wxMenuItem(menu, config_id_base + type, _(item));
menu_item->SetBitmap(*m_bmp_vector[type]);
menu_item_add_generic(menu_item, config_id_base + type*generics_count, type);
menu->Append(menu_item);
i++;
}
// Split object to parts
menu->AppendSeparator();
auto menu_item = menu_item_split(menu, config_id_base + i + 4);
auto menu_item = menu_item_split(menu, config_id_base + obj_types_count * generics_count);
menu->Append(menu_item);
menu_item->Enable(is_splittable_object(false));
// Settings
menu->AppendSeparator();
// Append settings popupmenu
menu->Append(menu_item_settings(menu, config_id_base + i + 5, false));
menu->Append(menu_item_settings(menu, config_id_base + obj_types_count * generics_count+1, false));
menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) {
switch (event.GetId() - config_id_base) {
case 0:
load_subobject();
break;
case 1:
load_subobject(true);
break;
case 2:
case 3:
case 4:
case 5:
case 6:
#ifdef __WXMSW__
load_lambda(menu->GetLabel(event.GetId()).ToStdString());
#endif // __WXMSW__
break;
case 7: //3:
menu->Bind(wxEVT_MENU, [config_id_base, menu, obj_types_count, generics_count, this](wxEvent &event) {
auto selection = event.GetId() - config_id_base;
if ( selection == 0 * generics_count || // ~ModelVolume::MODEL_PART
selection == 1 * generics_count || // ~ModelVolume::PARAMETER_MODIFIER
selection == 2 * generics_count || // ~ModelVolume::SUPPORT_ENFORCER
selection == 3 * generics_count ) // ~ModelVolume::SUPPORT_BLOCKER
load_subobject(int(selection / generics_count));
else if ( selection == obj_types_count * generics_count)
split(false);
break;
default:
#ifdef __WXMSW__
else if ( selection > obj_types_count * generics_count) // "Add Settings" is selected
get_settings_choice(menu, event.GetId(), false);
else // Some generic model is selected
load_generic_subobject(menu->GetLabel(event.GetId()).ToStdString(), int(selection / generics_count));
#endif // __WXMSW__
break;
}
});
return menu;
@ -609,24 +626,33 @@ wxMenu* ObjectList::create_add_part_popupmenu()
wxMenu* ObjectList::create_part_settings_popupmenu()
{
wxMenu *menu = new wxMenu;
wxWindowID config_id_base = wxWindow::NewControlId(2);
wxWindowID config_id_base = NewControlId(3);
auto menu_item = menu_item_split(menu, config_id_base);
menu->Append(menu_item);
menu_item->Enable(is_splittable_object(true));
// Append change part type
menu->AppendSeparator();
menu->Append(new wxMenuItem(menu, config_id_base + 1, _(L("Change type"))));
// Append settings popupmenu
menu->Append(menu_item_settings(menu, config_id_base + 1, true));
menu->AppendSeparator();
menu_item = menu_item_settings(menu, config_id_base + 2, true);
menu->Append(menu_item);
menu_item->Enable(get_selected_model_volume()->type() <= ModelVolume::PARAMETER_MODIFIER);
menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) {
switch (event.GetId() - config_id_base) {
case 0:
split(true);
break;
default:{
case 1:
change_part_type();
break;
default:
get_settings_choice(menu, event.GetId(), true);
break; }
break;
}
});
@ -655,31 +681,21 @@ wxMenu* ObjectList::create_add_settings_popupmenu(bool is_part)
return menu;
}
// Load SubObjects (parts and modifiers)
void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* = false*/)
void ObjectList::load_subobject(int type)
{
auto item = GetSelection();
if (!item)
return;
int obj_idx = -1;
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
obj_idx = m_objects_model->GetIdByItem(item);
else
if (!item || m_objects_model->GetParent(item) != wxDataViewItem(0))
return;
int obj_idx = m_objects_model->GetIdByItem(item);
if (obj_idx < 0) return;
wxArrayString part_names;
if (is_lambda)
load_lambda((*m_objects)[obj_idx], part_names, is_modifier);
else
load_part((*m_objects)[obj_idx], part_names, is_modifier);
load_part((*m_objects)[obj_idx], part_names, type);
parts_changed(obj_idx);
for (int i = 0; i < part_names.size(); ++i) {
const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i),
is_modifier ? m_bmp_modifiermesh : m_bmp_solidmesh);
const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), /**m_bmp_vector[*/type/*]*/);
if (i == part_names.size() - 1)
select_item(sel_item);
@ -688,11 +704,12 @@ void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* =
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
// selection_changed();
#endif //no __WXOSX__//__WXMSW__
}
void ObjectList::load_part( ModelObject* model_object,
wxArrayString& part_names,
const bool is_modifier)
int type)
{
wxWindow* parent = wxGetApp().tab_panel()->GetPage(0);
@ -717,19 +734,27 @@ void ObjectList::load_part( ModelObject* model_object,
if (model_object->origin_translation != Vec3d::Zero())
{
object->center_around_origin();
#if !ENABLE_MODELVOLUME_TRANSFORM
object->ensure_on_bed();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
delta = model_object->origin_translation - object->origin_translation;
}
for (auto volume : object->volumes) {
#if ENABLE_MODELVOLUME_TRANSFORM
Vec3d shift = volume->mesh.bounding_box().center();
volume->translate_geometry(-shift);
volume->translate(delta + shift);
#endif // ENABLE_MODELVOLUME_TRANSFORM
auto new_volume = model_object->add_volume(*volume);
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
boost::filesystem::path(input_file).filename().string();
new_volume->set_type(static_cast<ModelVolume::Type>(type));
new_volume->name = boost::filesystem::path(input_file).filename().string();
part_names.Add(new_volume->name);
#if !ENABLE_MODELVOLUME_TRANSFORM
if (delta != Vec3d::Zero())
new_volume->translate(delta);
#endif // !ENABLE_MODELVOLUME_TRANSFORM
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -738,98 +763,46 @@ void ObjectList::load_part( ModelObject* model_object,
}
}
}
}
void ObjectList::load_lambda( ModelObject* model_object,
wxArrayString& part_names,
const bool is_modifier)
void ObjectList::load_generic_subobject(const std::string& type_name, const int type)
{
auto dlg = new LambdaObjectDialog(GetMainWindow());
if (dlg->ShowModal() == wxID_CANCEL) {
m_parts_changed = false;
return;
}
std::string name = "lambda-";
TriangleMesh mesh;
auto params = dlg->ObjectParameters();
switch (params.type)
{
case LambdaTypeBox:{
mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
name += "Box";
break; }
case LambdaTypeCylinder:{
mesh = make_cylinder(params.cyl_r, params.cyl_h);
name += "Cylinder";
break; }
case LambdaTypeSphere:{
mesh = make_sphere(params.sph_rho);
name += "Sphere";
break; }
case LambdaTypeSlab:{
const auto& size = model_object->bounding_box().size();
mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h);
// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z);
name += "Slab";
break; }
default:
break;
}
mesh.repair();
auto new_volume = model_object->add_volume(mesh);
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
new_volume->name = name;
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
part_names.Add(name);
m_parts_changed = true;
}
void ObjectList::load_lambda(const std::string& type_name)
{
if (m_selected_object_id < 0) return;
auto dlg = new LambdaObjectDialog(GetMainWindow(), type_name);
if (dlg->ShowModal() == wxID_CANCEL)
return;
const auto obj_idx = get_selected_obj_idx();
if (obj_idx < 0) return;
const std::string name = "lambda-" + type_name;
TriangleMesh mesh;
const auto params = dlg->ObjectParameters();
auto& bed_shape = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionPoints>("bed_shape")->values;
const auto& sz = BoundingBoxf(bed_shape).size();
const auto side = 0.1 * std::max(sz(0), sz(1));
if (type_name == _("Box"))
mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
mesh = make_cube(side, side, side);
else if (type_name == _("Cylinder"))
mesh = make_cylinder(params.cyl_r, params.cyl_h);
mesh = make_cylinder(0.5*side, side);
else if (type_name == _("Sphere"))
mesh = make_sphere(params.sph_rho);
mesh = make_sphere(side, PI/18);
else if (type_name == _("Slab")) {
const auto& size = (*m_objects)[m_selected_object_id]->bounding_box().size();
mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h);
const auto& size = (*m_objects)[obj_idx]->bounding_box().size();
mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5);
// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z);
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0);
}
mesh.repair();
auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh);
new_volume->set_type(ModelVolume::PARAMETER_MODIFIER);
auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh);
new_volume->set_type(static_cast<ModelVolume::Type>(type));
new_volume->name = name;
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
m_parts_changed = true;
parts_changed(m_selected_object_id);
parts_changed(obj_idx);
select_item(m_objects_model->AddVolumeChild(GetSelection(),
name, m_bmp_modifiermesh));
select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type));
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
@ -927,8 +900,10 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
void ObjectList::split(const bool split_part)
{
const auto item = GetSelection();
if (!item || m_selected_object_id < 0)
const int obj_idx = get_selected_obj_idx();
if (!item || obj_idx < 0)
return;
ModelVolume* volume;
if (!get_volume_by_item(split_part, item, volume)) return;
DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
@ -938,52 +913,54 @@ void ObjectList::split(const bool split_part)
return;
}
auto model_object = (*m_objects)[m_selected_object_id];
auto model_object = (*m_objects)[obj_idx];
if (split_part) {
auto parent = m_objects_model->GetParent(item);
m_objects_model->DeleteChildren(parent);
auto parent = m_objects_model->GetTopParent(item);
if (parent)
m_objects_model->DeleteVolumeChildren(parent);
else
parent = item;
for (auto id = 0; id < model_object->volumes.size(); id++)
m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name,
model_object->volumes[id]->is_modifier() ? m_bmp_modifiermesh : m_bmp_solidmesh,
model_object->volumes[id]->config.has("extruder") ?
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
false);
for (auto id = 0; id < model_object->volumes.size(); id++) {
const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name,
model_object->volumes[id]->is_modifier() ?
ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART,
model_object->volumes[id]->config.has("extruder") ?
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
false);
// add settings to the part, if it has those
auto opt_keys = model_object->volumes[id]->config.keys();
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
select_item(m_objects_model->AddSettingsChild(vol_item));
Collapse(vol_item);
}
}
if (parent == item)
Expand(parent);
}
else {
for (auto id = 0; id < model_object->volumes.size(); id++)
m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name,
m_bmp_solidmesh,
model_object->volumes[id]->config.has("extruder") ?
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
false);
Expand(item);
}
m_parts_changed = true;
parts_changed(m_selected_object_id);
// restores selection
_3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id);
parts_changed(obj_idx);
}
bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume)
{
if (!item || m_selected_object_id < 0)
auto obj_idx = get_selected_obj_idx();
if (!item || obj_idx < 0)
return false;
const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
// object is selected
if (volume_id < 0) {
if (split_part) return false;
volume = (*m_objects)[m_selected_object_id]->volumes[0];
if ( split_part || (*m_objects)[obj_idx]->volumes.size() > 1 )
return false;
volume = (*m_objects)[obj_idx]->volumes[0];
}
// volume is selected
else
volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
if (volume)
return true;
return false;
volume = (*m_objects)[obj_idx]->volumes[volume_id];
return true;
}
bool ObjectList::is_splittable_object(const bool split_part)
@ -991,20 +968,14 @@ bool ObjectList::is_splittable_object(const bool split_part)
const wxDataViewItem item = GetSelection();
if (!item) return false;
wxDataViewItemArray children;
if (!split_part && m_objects_model->GetChildren(item, children) > 0)
return false;
ModelVolume* volume;
if (!get_volume_by_item(split_part, item, volume) || !volume)
return false;
TriangleMeshPtrs meshptrs = volume->mesh.split();
bool splittable = meshptrs.size() > 1;
for (TriangleMesh* m : meshptrs)
{
delete m;
}
for (TriangleMesh* m : meshptrs) { delete m; }
return splittable;
}
@ -1017,7 +988,7 @@ void ObjectList::part_settings_changed()
void ObjectList::parts_changed(int obj_idx)
{
wxGetApp().plater()->changed_object(get_selected_obj_idx());
wxGetApp().plater()->changed_object(obj_idx);
m_parts_changed = false;
}
@ -1105,19 +1076,28 @@ void ObjectList::add_object_to_list(size_t obj_idx)
m_objects_model->SetValue(variant, item, 0);
}
// add volumes to the object
if (model_object->volumes.size() > 1) {
for (auto id = 0; id < model_object->volumes.size(); id++)
m_objects_model->AddVolumeChild(item,
model_object->volumes[id]->name,
m_bmp_solidmesh,
ModelVolume::MODEL_PART,
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value,
false);
Expand(item);
}
// add instances to the object, if it has those
if (model_object->instances.size()>1)
increase_object_instances(obj_idx, model_object->instances.size());
// add settings to the object, if it has those
auto opt_keys = model_object->config.keys();
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
select_item(m_objects_model->AddSettingsChild(item));
Collapse(item);
}
#ifndef __WXOSX__
selection_changed();
#endif //__WXMSW__
@ -1227,11 +1207,18 @@ void ObjectList::update_selections()
auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection();
wxDataViewItemArray sels;
for (auto idx: selection.get_volume_idxs())
{
const auto gl_vol = selection.get_volume(idx);
sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
if (selection.is_single_full_object()) {
for (auto idx : selection.get_volume_idxs()) {
const auto gl_vol = selection.get_volume(idx);
sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
}
}
else if (selection.is_single_full_instance()) {
for (auto idx : selection.get_instance_idxs()) {
sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), idx));
}
}
select_items(sels);
}
@ -1256,7 +1243,7 @@ void ObjectList::update_selections_on_canvas()
if (m_objects_model->GetItemType(item) == itVolume) {
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
selection.add_volume(obj_idx, vol_idx, as_single_selection);
selection.add_volume(obj_idx, vol_idx, 0, as_single_selection);
}
else if (m_objects_model->GetItemType(item) == itInstance) {
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
@ -1334,5 +1321,53 @@ void ObjectList::fix_multiselection_conflicts()
m_prevent_list_events = false;
}
ModelVolume* ObjectList::get_selected_model_volume()
{
auto item = GetSelection();
if (!item || m_objects_model->GetItemType(item) != itVolume)
return nullptr;
const auto vol_idx = m_objects_model->GetVolumeIdByItem(item);
const auto obj_idx = get_selected_obj_idx();
if (vol_idx < 0 || obj_idx < 0)
return nullptr;
return (*m_objects)[obj_idx]->volumes[vol_idx];
}
void ObjectList::change_part_type()
{
ModelVolume* volume = get_selected_model_volume();
if (!volume)
return;
const auto type = volume->type();
const wxString names[] = { "Part", "Modifier", "Support Enforcer", "Support Blocker" };
auto new_type = wxGetSingleChoiceIndex("Type: ", _(L("Select type of part")), wxArrayString(4, names), type);
if (new_type == type || new_type < 0)
return;
const auto item = GetSelection();
volume->set_type(static_cast<ModelVolume::Type>(new_type));
m_objects_model->SetVolumeType(item, new_type);
m_parts_changed = true;
parts_changed(get_selected_obj_idx());
// Update settings showing, if we have it
//(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer)
const auto settings_item = m_objects_model->GetSettingsItem(item);
if (settings_item &&
new_type == ModelVolume::SUPPORT_ENFORCER || new_type == ModelVolume::SUPPORT_BLOCKER) {
m_objects_model->Delete(settings_item);
}
else if (!settings_item &&
new_type == ModelVolume::MODEL_PART || new_type == ModelVolume::PARAMETER_MODIFIER) {
select_item(m_objects_model->AddSettingsChild(item));
}
}
} //namespace GUI
} //namespace Slic3r

View file

@ -28,10 +28,14 @@ class ObjectList : public wxDataViewCtrl
wxBitmap m_bmp_modifiermesh;
wxBitmap m_bmp_solidmesh;
wxBitmap m_bmp_support_enforcer;
wxBitmap m_bmp_support_blocker;
wxBitmap m_bmp_manifold_warning;
wxBitmap m_bmp_cog;
wxBitmap m_bmp_split;
std::vector<wxBitmap*> m_bmp_vector;
int m_selected_object_id = -1;
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
// happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler
@ -78,17 +82,16 @@ public:
void on_drop(wxDataViewEvent &event);
void get_settings_choice(wxMenu *menu, int id, bool is_part);
void menu_item_add_generic(wxMenuItem* &menu, int id);
void menu_item_add_generic(wxMenuItem* &menu, int id, const int type);
wxMenuItem* menu_item_split(wxMenu* menu, int id);
wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part);
wxMenu* create_add_part_popupmenu();
wxMenu* create_part_settings_popupmenu();
wxMenu* create_add_settings_popupmenu(bool is_part);
void load_subobject(bool is_modifier = false, bool is_lambda = false);
void load_part(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier);
void load_lambda(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier);
void load_lambda(const std::string& type_name);
void load_subobject(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 del_subobject_item(wxDataViewItem& item);
void del_settings_from_config();
void del_instances_from_object(const int obj_idx);
@ -142,6 +145,9 @@ public:
void select_all();
// correct current selections to avoid of the possible conflicts
void fix_multiselection_conflicts();
ModelVolume* get_selected_model_volume();
void change_part_type();
};

View file

@ -268,6 +268,9 @@ void ObjectManipulation::update_settings_list()
void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection)
{
#if ENABLE_MODELVOLUME_TRANSFORM
if (selection.is_single_full_instance())
#else
if (selection.is_single_full_object())
{
auto obj_idx = selection.get_object_idx();
@ -284,30 +287,49 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
reset_settings_value();
}
else if (selection.is_single_full_instance())
#endif // ENABLE_MODELVOLUME_TRANSFORM
{
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_MODELVOLUME_TRANSFORM
update_position_value(volume->get_instance_offset());
update_rotation_value(volume->get_instance_rotation());
update_scale_value(volume->get_instance_scaling_factor());
#else
update_position_value(volume->get_offset());
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
}
else if (selection.is_wipe_tower())
{
// the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_MODELVOLUME_TRANSFORM
update_position_value(volume->get_volume_offset());
update_rotation_value(volume->get_volume_rotation());
update_scale_value(volume->get_volume_scaling_factor());
#else
update_position_value(volume->get_offset());
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
}
else if (selection.is_modifier())
{
// the selection contains a single volume
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
#if ENABLE_MODELVOLUME_TRANSFORM
update_position_value(volume->get_volume_offset());
update_rotation_value(volume->get_volume_rotation());
update_scale_value(volume->get_volume_scaling_factor());
#else
update_position_value(volume->get_offset());
update_rotation_value(volume->get_rotation());
update_scale_value(volume->get_scaling_factor());
#endif // ENABLE_MODELVOLUME_TRANSFORM
m_og->enable();
}
else

View file

@ -1,5 +1,6 @@
#include "../../libslic3r/libslic3r.h"
#include "GUI_Preview.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#include "AppConfig.hpp"
#include "3DScene.hpp"
@ -22,6 +23,7 @@
namespace Slic3r {
namespace GUI {
Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data)
: m_canvas(nullptr)
, m_double_slider_sizer(nullptr)
@ -482,6 +484,11 @@ void Preview::create_double_slider()
if (IsShown())
m_canvas->Refresh();
});
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
auto& config = wxGetApp().preset_bundle->project_config;
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
});
}
void Preview::update_double_slider(bool force_sliders_full_range)
@ -495,6 +502,11 @@ void Preview::update_double_slider(bool force_sliders_full_range)
m_slider->SetMaxValue(layers_z.size() - 1);
m_slider->SetSliderValues(values);
const auto& config = wxGetApp().preset_bundle->project_config;
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
m_slider->SetTicksValues(ticks_from_config);
set_double_slider_thumbs(force_sliders_full_range, layers_z, z_low, z_high);
}
@ -515,6 +527,15 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
break;
}
}
// All ticks that would end up outside the slider range should be erased.
// TODO: this should probably be placed into more appropriate part of code,
// this way it relies on the Preview tab being active.
auto& config = wxGetApp().preset_bundle->project_config;
std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
[values](double val) { return values.back().second < val; }),
ticks_from_config.end());
}
void Preview::set_double_slider_thumbs(const bool force_sliders_full_range,

View file

@ -49,15 +49,15 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent,
def.type = coFloat;
def.default_value = new ConfigOptionFloat{ 1.0 };
def.label = L("L");
def.label = L("Length");
Option option(def, "l");
optgroup->append_single_option_line(option);
def.label = L("W");
def.label = L("Width");
option = Option(def, "w");
optgroup->append_single_option_line(option);
def.label = L("H");
def.label = L("Height");
option = Option(def, "h");
optgroup->append_single_option_line(option);
}
@ -112,7 +112,7 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent,
def.type = coFloat;
def.default_value = new ConfigOptionFloat{ 1.0 };
def.label = L("H");
def.label = L("Height");
auto option = Option(def, "slab_h");
optgroup->append_single_option_line(option);

View file

@ -596,8 +596,7 @@ void MainFrame::load_config_file(wxString file/* = wxEmptyString*/)
// if (Slic3r::GUI::catch_error(this))
// return;
}
for (auto tab : m_options_tabs )
tab.second->load_current_preset();
wxGetApp().load_current_presets();
wxGetApp().app_config->update_config_dir(get_dir_name(file));
m_last_config = file;
}
@ -659,8 +658,7 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
}
// Load the currently selected preset into the GUI, update the preset selection box.
for (auto tab : m_options_tabs)
tab.second->load_current_preset();
wxGetApp().load_current_presets();
const auto message = wxString::Format(_(L("%d presets successfully imported.")), presets_imported);
Slic3r::GUI::show_info(this, message, "Info");

View file

@ -22,18 +22,18 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
// is the normal type.
if (opt.gui_type.compare("select") == 0) {
} else if (opt.gui_type.compare("select_open") == 0) {
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
} else if (opt.gui_type.compare("color") == 0) {
m_fields.emplace(id, STDMOVE(ColourPicker::Create<ColourPicker>(parent(), opt, id)));
m_fields.emplace(id, std::move(ColourPicker::Create<ColourPicker>(parent(), opt, id)));
} else if (opt.gui_type.compare("f_enum_open") == 0 ||
opt.gui_type.compare("i_enum_open") == 0 ||
opt.gui_type.compare("i_enum_closed") == 0) {
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
} else if (opt.gui_type.compare("slider") == 0) {
m_fields.emplace(id, STDMOVE(SliderCtrl::Create<SliderCtrl>(parent(), opt, id)));
m_fields.emplace(id, std::move(SliderCtrl::Create<SliderCtrl>(parent(), opt, id)));
} else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl
} else if (opt.gui_type.compare("legend") == 0) { // StaticText
m_fields.emplace(id, STDMOVE(StaticText::Create<StaticText>(parent(), opt, id)));
m_fields.emplace(id, std::move(StaticText::Create<StaticText>(parent(), opt, id)));
} else {
switch (opt.type) {
case coFloatOrPercent:
@ -43,21 +43,21 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
case coPercents:
case coString:
case coStrings:
m_fields.emplace(id, STDMOVE(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
break;
case coBool:
case coBools:
m_fields.emplace(id, STDMOVE(CheckBox::Create<CheckBox>(parent(), opt, id)));
m_fields.emplace(id, std::move(CheckBox::Create<CheckBox>(parent(), opt, id)));
break;
case coInt:
case coInts:
m_fields.emplace(id, STDMOVE(SpinCtrl::Create<SpinCtrl>(parent(), opt, id)));
m_fields.emplace(id, std::move(SpinCtrl::Create<SpinCtrl>(parent(), opt, id)));
break;
case coEnum:
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
break;
case coPoints:
m_fields.emplace(id, STDMOVE(PointCtrl::Create<PointCtrl>(parent(), opt, id)));
m_fields.emplace(id, std::move(PointCtrl::Create<PointCtrl>(parent(), opt, id)));
break;
case coNone: break;
default:

View file

@ -1154,16 +1154,25 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
try {
if (type_3mf || type_zip_amf) {
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
model = Slic3r::Model::read_from_archive(path.string(), &config, false);
Preset::normalize(config);
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
for (const auto &kv : main_frame->options_tabs()) { kv.second->load_current_preset(); }
{
DynamicPrintConfig config_loaded;
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false);
if (! config_loaded.empty()) {
// Based on the printer technology field found in the loaded config, select the base for the config,
PrinterTechnology printer_technology = Preset::printer_technology(config_loaded);
config.apply(printer_technology == ptFFF ?
static_cast<const ConfigBase&>(FullPrintConfig::defaults()) :
static_cast<const ConfigBase&>(SLAFullPrintConfig::defaults()));
// and place the loaded config over the base.
config += std::move(config_loaded);
}
}
if (! config.empty()) {
Preset::normalize(config);
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
wxGetApp().load_current_presets();
}
wxGetApp().app_config->update_config_dir(path.parent_path().string());
// forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer
// and if the config contains a "layer_height" different from the current defined one
// TODO:
// $self->async_apply_config;
} else {
model = Slic3r::Model::read_from_file(path.string(), nullptr, false);
for (auto obj : model.objects)
@ -1230,7 +1239,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects)
{
const BoundingBoxf bed_shape = bed_shape_bb();
#if !ENABLE_MODELVOLUME_TRANSFORM
const Vec3d bed_center = Slic3r::to_3d(bed_shape.center().cast<double>(), 0.0);
#endif // !ENABLE_MODELVOLUME_TRANSFORM
const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast<double>(), 1.0);
bool need_arrange = false;
@ -1249,8 +1260,12 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
auto *instance = object->add_instance();
ModelInstance* instance = object->add_instance();
#if ENABLE_MODELVOLUME_TRANSFORM
instance->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -object->origin_translation(2)));
#else
instance->set_offset(bed_center);
#endif // ENABLE_MODELVOLUME_TRANSFORM
}
const Vec3d size = object->bounding_box().size();
@ -1438,7 +1453,9 @@ void Plater::priv::mirror(Axis axis)
void Plater::priv::arrange()
{
this->background_process.stop();
main_frame->app_controller()->arrange_model();
this->schedule_background_process();
// ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
// when parts don't fit in print bed
@ -1471,13 +1488,7 @@ void Plater::priv::split_object()
{
unsigned int counter = 1;
for (ModelObject* m : new_objects)
{
m->name = current_model_object->name + "_" + std::to_string(counter++);
for (ModelInstance* i : current_model_object->instances)
{
m->add_instance(*i);
}
}
remove(obj_idx);
@ -2108,7 +2119,8 @@ void Plater::export_amf()
wxString path = dialog->GetPath();
auto path_cstr = path.c_str();
if (Slic3r::store_amf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) {
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config();
if (Slic3r::store_amf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
// Success
p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path));
} else {
@ -2127,7 +2139,8 @@ void Plater::export_3mf()
wxString path = dialog->GetPath();
auto path_cstr = path.c_str();
if (Slic3r::store_3mf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) {
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config();
if (Slic3r::store_3mf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
// Success
p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path));
} else {
@ -2256,7 +2269,9 @@ void Plater::changed_object(int obj_idx)
if (list->is_parts_changed()) {
// recenter and re - align to Z = 0
auto model_object = p->model.objects[obj_idx];
#if !ENABLE_MODELVOLUME_TRANSFORM
model_object->center_around_origin();
#endif // !ENABLE_MODELVOLUME_TRANSFORM
model_object->ensure_on_bed();
_3DScene::reload_scene(p->canvas3D, false);
}

View file

@ -170,10 +170,12 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr
{
const auto &defaults = FullPrintConfig::defaults();
for (const std::string &key : Preset::nozzle_options()) {
if (key == "default_filament_profile")
continue;
auto *opt = config.option(key, false);
assert(opt != nullptr);
assert(opt->is_vector());
if (opt != nullptr && opt->is_vector() && key != "default_filament_profile")
if (opt != nullptr && opt->is_vector())
static_cast<ConfigOptionVectorBase*>(opt)->resize(num_extruders, defaults.option(key));
}
}
@ -202,8 +204,7 @@ void Preset::normalize(DynamicPrintConfig &config)
// The following keys are mandatory for the UI, but they are not part of FullPrintConfig, therefore they are handled separately.
for (const std::string &key : { "filament_settings_id" }) {
auto *opt = config.option(key, false);
assert(opt != nullptr);
assert(opt->type() == coStrings);
assert(opt == nullptr || opt->type() == coStrings);
if (opt != nullptr && opt->type() == coStrings)
static_cast<ConfigOptionStrings*>(opt)->values.resize(n, std::string());
}
@ -534,7 +535,8 @@ Preset& PresetCollection::load_external_preset(
cfg.apply_only(config, cfg.keys(), true);
// Is there a preset already loaded with the name stored inside the config?
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
if (it != m_presets.end() && it->name == original_name && profile_print_params_same(it->config, cfg)) {
bool found = it != m_presets.end() && it->name == original_name;
if (found && profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_preset(it - m_presets.begin());
@ -542,7 +544,7 @@ Preset& PresetCollection::load_external_preset(
}
// Update the "inherits" field.
std::string &inherits = Preset::inherits(cfg);
if (it != m_presets.end() && inherits.empty()) {
if (found && inherits.empty()) {
// There is a profile with the same name already loaded. Should we update the "inherits" field?
if (it->vendor == nullptr)
inherits = it->inherits();

View file

@ -36,6 +36,7 @@
namespace Slic3r {
static std::vector<std::string> s_project_options {
"colorprint_heights",
"wiping_volumes_extruders",
"wiping_volumes_matrix"
};
@ -617,18 +618,6 @@ void PresetBundle::load_config_file(const std::string &path)
}
}
void PresetBundle::load_config_string(const char* str, const char* source_filename)
{
if (str != nullptr)
{
DynamicPrintConfig config;
config.apply(FullPrintConfig::defaults());
config.load_from_gcode_string(str);
Preset::normalize(config);
load_config_file_config((source_filename == nullptr) ? "" : source_filename, true, std::move(config));
}
}
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config)
{
@ -676,7 +665,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
compatible_printers_condition = compatible_printers_condition_values[idx];
if (is_external)
presets.load_external_preset(name_or_path, name,
config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_id") : "printer_settings_id", true),
config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_settings_id") : "printer_settings_id", true),
config);
else
presets.load_preset(presets.path_from_name(name), name, config).save();

View file

@ -84,11 +84,6 @@ public:
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
void load_config_file(const std::string &path);
// Load an external config source containing the print, filament and printer presets.
// The given string must contain the full set of parameters (same as those exported to gcode).
// If the string is parsed successfully, its print / filament / printer profiles will be activated.
void load_config_string(const char* str, const char* source_filename = nullptr);
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
// Load settings into the provided settings instance.

View file

@ -108,7 +108,7 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters)
m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} );
Refresh(this);
Refresh(true); // erase background
}
void RammingPanel::line_parameters_changed() {

View file

@ -9,6 +9,9 @@
#include <wx/numformatter.h>
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
#include "Model.hpp"
wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, const std::string& icon, wxEvtHandler* event_handler)
@ -400,10 +403,9 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
m_opt_categories = categories;
m_name = wxEmptyString;
// m_icon = m_empty_icon;
m_bmp = m_empty_bmp;
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;//Slic3r::GUI::get_category_icon();
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
for (auto& cat : m_opt_categories)
m_name += cat + "; ";
@ -453,29 +455,34 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name)
wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item,
const wxString &name,
const wxBitmap& icon,
const int volume_type,
const int extruder/* = 0*/,
const bool create_frst_child/* = true*/)
{
PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID();
if (!root) return wxDataViewItem(0);
const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
// because of istance_root is a last item of the object
int insert_position = root->GetChildCount() - 1;
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
insert_position = -1;
if (create_frst_child && root->m_volumes_cnt == 0)
{
const auto bmp_solid_mesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);
const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, bmp_solid_mesh, extruder_str, 0);
root->Append(node);
const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0);
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
root->m_volumes_cnt++;
if (insert_position > 0) insert_position++;
}
const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, root->m_volumes_cnt);
root->Append(node);
const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[volume_type], extruder_str, root->m_volumes_cnt);
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
@ -499,15 +506,13 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem &
int get_istances_root_idx(PrusaObjectDataViewModelNode *parent_node)
{
int inst_root_id = -1;
int stop_search_i = parent_node->GetChildCount();
if (stop_search_i > 2) stop_search_i = 2;
for (int i = 0; i < stop_search_i; ++i)
if (parent_node->GetNthChild(i)->m_type & itInstanceRoot) {
inst_root_id = i;
break;
}
return inst_root_id;
// because of istance_root is a last item of the object
const int inst_root_idx = parent_node->GetChildCount()-1;
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->m_type == itInstanceRoot)
return inst_root_idx;
return -1;
}
wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
@ -524,8 +529,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &
const wxDataViewItem inst_root_item((void*)inst_root_node);
if (inst_root_id < 0) {
const unsigned insert_pos = parent_node->GetChildCount() == 0 || parent_node->GetNthChild(0)->m_type != itSettings ? 0 : 1;
parent_node->Insert(inst_root_node, insert_pos);
parent_node->Append(inst_root_node);
// notify control
ItemAdded(parent_item, inst_root_item);
if (num == 1) num++;
@ -563,6 +567,10 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
auto id = node_parent->GetChildren().Index(node);
auto idx = node->GetIdx();
node_parent->GetChildren().Remove(node);
if (node->m_type == itVolume)
node_parent->m_volumes_cnt--;
if (id > 0) {
if(id == node_parent->GetChildCount()) id--;
ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
@ -692,6 +700,9 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
auto item = wxDataViewItem(node);
children.RemoveAt(id);
if (node->m_type == itVolume)
root->m_volumes_cnt--;
// free the node
delete node;
@ -705,6 +716,39 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
#endif //__WXGTK__
}
void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent)
{
PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent.GetID();
if (!root) // happens if item.IsOk()==false
return;
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
auto& children = root->GetChildren();
for (int id = root->GetChildCount() - 1; id >= 0; --id)
{
auto node = children[id];
if (node->m_type != itVolume)
continue;
auto item = wxDataViewItem(node);
children.RemoveAt(id);
root->m_volumes_cnt--;
// free the node
delete node;
// notify control
ItemDeleted(parent, item);
}
// set m_containet to FALSE if parent has no child
#ifndef __WXGTK__
root->m_container = false;
#endif //__WXGTK__
}
wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
{
if (obj_idx >= m_objects.size())
@ -718,7 +762,7 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx)
{
if (obj_idx >= m_objects.size()) {
if (obj_idx >= m_objects.size() || obj_idx < 0) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
@ -740,6 +784,25 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu
return wxDataViewItem(0);
}
wxDataViewItem PrusaObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
{
if (obj_idx >= m_objects.size() || obj_idx < 0) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
if (!instances_item)
return wxDataViewItem(0);
auto parent = (PrusaObjectDataViewModelNode*)instances_item.GetID();;
for (size_t i = 0; i < parent->GetChildCount(); i++)
if (parent->GetNthChild(i)->m_idx == inst_idx)
return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0);
}
int PrusaObjectDataViewModel::GetIdByItem(const wxDataViewItem& item)
{
wxASSERT(item.IsOk());
@ -1015,21 +1078,33 @@ ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
return node->m_type;
}
wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
wxDataViewItem PrusaObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
{
if (!item.IsOk())
if (!parent_item.IsOk())
return wxDataViewItem(0);
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent_item.GetID();
if (node->GetChildCount() == 0)
return wxDataViewItem(0);
if (node->GetNthChild(0)->m_type == itSettings)
return wxDataViewItem((void*)node->GetNthChild(0));
for (int i = 0; i < node->GetChildCount(); i++) {
if (node->GetNthChild(i)->m_type == type)
return wxDataViewItem((void*)node->GetNthChild(i));
}
return wxDataViewItem(0);
}
wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itSettings);
}
wxDataViewItem PrusaObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itInstanceRoot);
}
bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
{
if (!item.IsOk())
@ -1050,6 +1125,16 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
ItemChanged(item);
}
void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const int type)
{
if (!item.IsOk() || GetItemType(item) != itVolume)
return;
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
node->SetBitmap(*m_volume_bmps[type]);
ItemChanged(item);
}
//-----------------------------------------------------------------------------
// PrusaDataViewBitmapText
//-----------------------------------------------------------------------------
@ -1106,7 +1191,6 @@ wxSize PrusaBitmapTextRenderer::GetSize() const
// ----------------------------------------------------------------------------
// PrusaDoubleSlider
// ----------------------------------------------------------------------------
PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent,
wxWindowID id,
int lowerValue,
@ -1288,6 +1372,34 @@ double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) cons
return m_values[selection == ssLower ? m_lower_value : m_higher_value].second;
}
std::vector<double> PrusaDoubleSlider::GetTicksValues() const
{
std::vector<double> values;
if (!m_values.empty())
for (auto tick : m_ticks)
values.push_back(m_values[tick].second);
return values;
}
void PrusaDoubleSlider::SetTicksValues(const std::vector<double>& heights)
{
if (m_values.empty())
return;
m_ticks.clear();
unsigned int i = 0;
for (auto h : heights) {
while (i < m_values.size() && m_values[i].second - 1e-6 < h)
++i;
if (i == m_values.size())
return;
m_ticks.insert(i);
}
}
void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
{
const double step = get_scroll_step();
@ -1712,10 +1824,13 @@ void PrusaDoubleSlider::action_tick(const TicksAction action)
m_ticks.insert(tick);
else if (it != m_ticks.end() && action == taDel)
m_ticks.erase(tick);
else
else {
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
return;
}
}
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
Refresh();
Update();
}

View file

@ -424,7 +424,9 @@ private:
class PrusaObjectDataViewModel :public wxDataViewModel
{
std::vector<PrusaObjectDataViewModelNode*> m_objects;
std::vector<PrusaObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
public:
PrusaObjectDataViewModel();
~PrusaObjectDataViewModel();
@ -432,7 +434,7 @@ public:
wxDataViewItem Add(const wxString &name);
wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item,
const wxString &name,
const wxBitmap& icon,
const int volume_type,
const int extruder = 0,
const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
@ -441,8 +443,10 @@ public:
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
void DeleteAll();
void DeleteChildren(wxDataViewItem& parent);
void DeleteVolumeChildren(wxDataViewItem& parent);
wxDataViewItem GetItemById(int obj_idx);
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
int GetIdByItem(const wxDataViewItem& item);
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetVolumeIdByItem(const wxDataViewItem& item) const;
@ -488,9 +492,14 @@ public:
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
ItemType GetItemType(const wxDataViewItem &item) const ;
wxDataViewItem GetItemByType(const wxDataViewItem &parent_item, ItemType type) const;
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
bool IsSettingsItem(const wxDataViewItem &item) const;
void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetVolumeType(const wxDataViewItem &item, const int type);
};
// ----------------------------------------------------------------------------
@ -613,6 +622,9 @@ private:
// PrusaDoubleSlider
// ----------------------------------------------------------------------------
// custom message the slider sends to its parent to notify a tick-change:
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
enum SelectedSlider {
ssUndef,
ssLower,
@ -623,6 +635,7 @@ enum TicksAction{
taAdd,
taDel
};
class PrusaDoubleSlider : public wxControl
{
public:
@ -660,6 +673,8 @@ public:
m_values = values;
}
void ChangeOneLayerLock();
std::vector<double> GetTicksValues() const;
void SetTicksValues(const std::vector<double>& heights);
void OnPaint(wxPaintEvent& ) { render();}
void OnLeftDown(wxMouseEvent& event);