merge tm_sla_supports_backend with master, reapply fix for index slice invalidation, fix for autorotation z offset

This commit is contained in:
tamasmeszaros 2018-11-29 11:45:02 +01:00
commit 980c53970b
13 changed files with 304 additions and 174 deletions

View file

@ -1322,11 +1322,11 @@ void GCode::process_layer(
// In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all.
// (Layers can be close to each other, model could have been resliced with bigger layer height, ...). // (Layers can be close to each other, model could have been resliced with bigger layer height, ...).
bool colorprint_change = false; bool colorprint_change = false;
while (!m_colorprint_heights.empty() && m_colorprint_heights.front()/*-EPSILON*/ < layer.print_z-EPSILON) { while (!m_colorprint_heights.empty() && m_colorprint_heights.front()-EPSILON < layer.print_z) {
m_colorprint_heights.erase(m_colorprint_heights.begin()); m_colorprint_heights.erase(m_colorprint_heights.begin());
colorprint_change = true; colorprint_change = true;
} }
if (colorprint_change) if (colorprint_change && print.extruders().size()==1)
gcode += "M600\n"; gcode += "M600\n";

View file

@ -382,7 +382,7 @@ std::string GCodePreviewData::get_legend_title() const
return ""; return "";
} }
GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::vector<float>& tool_colors, const std::vector<double>& cp_values) const GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::vector<float>& tool_colors, const std::vector</*double*/std::pair<double, double>>& cp_values) const
{ {
struct Helper struct Helper
{ {
@ -465,15 +465,16 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
break; break;
} }
if (i == 0) { if (i == 0) {
items.emplace_back((boost::format(Slic3r::I18N::translate(L("up to %.2f mm"))) % cp_values[0]).str(), color); items.emplace_back((boost::format(Slic3r::I18N::translate(L("up to %.2f mm"))) % cp_values[0].first).str(), color);
break; break;
} }
if (i == color_print_cnt) { if (i == color_print_cnt) {
items.emplace_back((boost::format(Slic3r::I18N::translate(L("above %.2f mm"))) % cp_values[i-1]).str(), color); items.emplace_back((boost::format(Slic3r::I18N::translate(L("above %.2f mm"))) % cp_values[i-1].second).str(), color);
continue; continue;
} }
items.emplace_back((boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i-1] % cp_values[i]).str(), color); // items.emplace_back((boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i-1] % cp_values[i]).str(), color);
items.emplace_back((boost::format(Slic3r::I18N::translate(L("%.2f - %.2f mm"))) % cp_values[i-1].second % cp_values[i].first).str(), color);
} }
break; break;
} }

View file

@ -198,7 +198,7 @@ public:
void set_extrusion_paths_colors(const std::vector<std::string>& colors); void set_extrusion_paths_colors(const std::vector<std::string>& colors);
std::string get_legend_title() const; std::string get_legend_title() const;
LegendItemsList get_legend_items(const std::vector<float>& tool_colors, const std::vector<double>& cp_values) const; LegendItemsList get_legend_items(const std::vector<float>& tool_colors, const std::vector</*double*/std::pair<double, double>>& cp_values) const;
}; };
GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2); GCodePreviewData::Color operator + (const GCodePreviewData::Color& c1, const GCodePreviewData::Color& c2);

View file

@ -908,12 +908,12 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
std::vector<SLAPrintObjectStep> steps; std::vector<SLAPrintObjectStep> steps;
bool invalidated = false; bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) { for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "support_head_front_radius" if ( opt_key == "supports_enable"
|| opt_key == "support_head_front_diameter"
|| opt_key == "support_head_penetration" || opt_key == "support_head_penetration"
|| opt_key == "support_head_back_radius"
|| opt_key == "support_head_width" || opt_key == "support_head_width"
|| opt_key == "support_pillar_radius" || opt_key == "support_pillar_diameter"
|| opt_key == "support_base_radius" || opt_key == "support_base_diameter"
|| opt_key == "support_base_height" || opt_key == "support_base_height"
|| opt_key == "support_critical_angle" || opt_key == "support_critical_angle"
|| opt_key == "support_max_bridge_length" || opt_key == "support_max_bridge_length"
@ -945,18 +945,21 @@ bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step)
if (step == slaposObjectSlice) { if (step == slaposObjectSlice) {
invalidated |= this->invalidate_all_steps(); invalidated |= this->invalidate_all_steps();
} else if (step == slaposSupportIslands) { } else if (step == slaposSupportIslands) {
invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposBasePool, slaposSliceSupports }); invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposSupportPoints) { } else if (step == slaposSupportPoints) {
invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports }); invalidated |= this->invalidate_steps({ slaposSupportTree, slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposSupportTree) { } else if (step == slaposSupportTree) {
invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports }); invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposBasePool) { } else if (step == slaposBasePool) {
invalidated |= this->invalidate_step(slaposSliceSupports); invalidated |= this->invalidate_steps({slaposSliceSupports, slaposIndexSlices});
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposSliceSupports) { } else if (step == slaposSliceSupports) {
invalidated |= this->invalidate_step(slaposIndexSlices);
invalidated |= m_print->invalidate_step(slapsRasterize);
} else if(step == slaposIndexSlices) {
invalidated |= m_print->invalidate_step(slapsRasterize); invalidated |= m_print->invalidate_step(slapsRasterize);
} }
return invalidated; return invalidated;

View file

@ -3115,16 +3115,38 @@ GLCanvas3D::LegendTexture::LegendTexture()
{ {
} }
bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors) bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors, const GLCanvas3D& canvas)
{ {
reset(); reset();
// collects items to render // collects items to render
auto title = _(preview_data.get_legend_title()); auto title = _(preview_data.get_legend_title());
std::vector<std::pair<double, double>> cp_legend_values;
if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint)
{
const auto& config = wxGetApp().preset_bundle->full_config(); const auto& config = wxGetApp().preset_bundle->full_config();
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values; const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values;
const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors, color_print_values); const int values_cnt = color_print_values.size();
if (values_cnt > 0) {
auto print_zs = canvas.get_current_print_zs(true);
auto z = 0;
for (auto i = 0; i < values_cnt; ++i)
{
double prev_z = -1.0;
for (z; z < print_zs.size(); ++z)
if (fabs(color_print_values[i] - print_zs[z]) < EPSILON) {
prev_z = print_zs[z - 1];
break;
}
if (prev_z < 0)
continue;
cp_legend_values.push_back(std::pair<double, double>(prev_z, color_print_values[i]));
}
}
}
const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors, /*color_print_values*/cp_legend_values);
unsigned int items_count = (unsigned int)items.size(); unsigned int items_count = (unsigned int)items.size();
if (items_count == 0) if (items_count == 0)
@ -4400,6 +4422,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
// key B/b // key B/b
case 66: case 66:
case 98: { zoom_to_bed(); break; } case 98: { zoom_to_bed(); break; }
// key I/i
case 73:
case 105: { set_camera_zoom(1.0f); break; }
// key O/o
case 79:
case 111: { set_camera_zoom(-1.0f); break; }
#if ENABLE_MODIFIED_CAMERA_TARGET #if ENABLE_MODIFIED_CAMERA_TARGET
// key Z/z // key Z/z
case 90: case 90:
@ -4464,18 +4492,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
// Calculate the zoom delta and apply it to the current zoom factor // Calculate the zoom delta and apply it to the current zoom factor
float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta();
zoom = std::max(std::min(zoom, 4.0f), -4.0f) / 10.0f; set_camera_zoom(zoom);
zoom = get_camera_zoom() / (1.0f - zoom);
// Don't allow to zoom too far outside the scene.
float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box());
if (zoom_min > 0.0f)
zoom = std::max(zoom, zoom_min * 0.8f);
m_camera.zoom = zoom;
viewport_changed();
_refresh_if_shown_on_screen();
} }
void GLCanvas3D::on_timer(wxTimerEvent& evt) void GLCanvas3D::on_timer(wxTimerEvent& evt)
@ -5229,6 +5246,21 @@ void GLCanvas3D::do_mirror()
post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
} }
void GLCanvas3D::set_camera_zoom(float zoom)
{
zoom = std::max(std::min(zoom, 4.0f), -4.0f) / 10.0f;
zoom = get_camera_zoom() / (1.0f - zoom);
// Don't allow to zoom too far outside the scene.
float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box());
if (zoom_min > 0.0f)
zoom = std::max(zoom, zoom_min * 0.8f);
m_camera.zoom = zoom;
viewport_changed();
_refresh_if_shown_on_screen();
}
bool GLCanvas3D::_is_shown_on_screen() const bool GLCanvas3D::_is_shown_on_screen() const
{ {
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@ -5908,7 +5940,6 @@ void GLCanvas3D::_render_sla_slices() const
{ {
if (obj->is_step_done(slaposIndexSlices)) if (obj->is_step_done(slaposIndexSlices))
{ {
const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
const std::vector<ExPolygons>& model_slices = obj->get_model_slices(); const std::vector<ExPolygons>& model_slices = obj->get_model_slices();
const std::vector<ExPolygons>& support_slices = obj->get_support_slices(); const std::vector<ExPolygons>& support_slices = obj->get_support_slices();
const std::vector<SLAPrintObject::Instance>& instances = obj->instances(); const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
@ -5928,14 +5959,25 @@ void GLCanvas3D::_render_sla_slices() const
double min_z = clip_min_z - shift_z; double min_z = clip_min_z - shift_z;
double max_z = clip_max_z - shift_z; double max_z = clip_max_z - shift_z;
Pointf3s bottom_triangles;
Pointf3s top_triangles;
if (m_sla_caps[0].matches(min_z))
bottom_triangles = m_sla_caps[0].triangles;
if (m_sla_caps[1].matches(max_z))
top_triangles = m_sla_caps[1].triangles;
if (bottom_triangles.empty() || top_triangles.empty())
{
const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; }); SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; }); SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
::glColor3f(1.0f, 0.37f, 0.0f); if (bottom_triangles.empty() && (it_min_z != index.end()))
if (it_min_z != index.end())
{ {
// render model bottom slices // calculate model bottom cap
if (it_min_z->second.model_slices_idx < model_slices.size()) if (it_min_z->second.model_slices_idx < model_slices.size())
{ {
const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx]; const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx];
@ -5943,31 +5985,17 @@ void GLCanvas3D::_render_sla_slices() const
{ {
Polygons triangles; Polygons triangles;
poly.triangulate(&triangles); poly.triangulate(&triangles);
if (!triangles.empty()) for (const Polygon& t : triangles)
{ {
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i) for (int v = 2; v >= 0; --v)
{ {
::glPushMatrix(); bottom_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z));
::glTranslated(instance_transforms[i].offset(0), instance_transforms[i].offset(1), instance_transforms[i].offset(2));
::glRotatef(instance_transforms[i].rotation, 0.0, 0.0, 1.0);
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, -1.0f);
for (const Polygon& p : triangles)
{
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[2]), min_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[1]), min_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[0]), min_z).data());
}
::glEnd();
::glPopMatrix();
} }
} }
} }
} }
// render support bottom slices // calculate support bottom cap
if (it_min_z->second.support_slices_idx < support_slices.size()) if (it_min_z->second.support_slices_idx < support_slices.size())
{ {
const ExPolygons& polys = support_slices[it_min_z->second.support_slices_idx]; const ExPolygons& polys = support_slices[it_min_z->second.support_slices_idx];
@ -5975,34 +6003,22 @@ void GLCanvas3D::_render_sla_slices() const
{ {
Polygons triangles; Polygons triangles;
poly.triangulate(&triangles); poly.triangulate(&triangles);
if (!triangles.empty()) for (const Polygon& t : triangles)
{ {
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i) for (int v = 2; v >= 0; --v)
{ {
::glPushMatrix(); bottom_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z));
::glTranslated(instance_transforms[i].offset(0), instance_transforms[i].offset(1), instance_transforms[i].offset(2));
::glRotatef(instance_transforms[i].rotation, 0.0, 0.0, 1.0);
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, -1.0f);
for (const Polygon& p : triangles)
{
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[2]), min_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[1]), min_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[0]), min_z).data());
}
::glEnd();
::glPopMatrix();
} }
} }
} }
} }
m_sla_caps[0].z = min_z;
m_sla_caps[0].triangles = bottom_triangles;
} }
if (it_max_z != index.end()) if (top_triangles.empty() && (it_max_z != index.end()))
{ {
// render model top slices // calculate model top cap
if (it_max_z->second.model_slices_idx < model_slices.size()) if (it_max_z->second.model_slices_idx < model_slices.size())
{ {
const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx]; const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx];
@ -6010,31 +6026,17 @@ void GLCanvas3D::_render_sla_slices() const
{ {
Polygons triangles; Polygons triangles;
poly.triangulate(&triangles); poly.triangulate(&triangles);
if (!triangles.empty()) for (const Polygon& t : triangles)
{ {
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i) for (int v = 0; v < 3; ++v)
{ {
::glPushMatrix(); top_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z));
::glTranslated(instance_transforms[i].offset(0), instance_transforms[i].offset(1), instance_transforms[i].offset(2));
::glRotatef(instance_transforms[i].rotation, 0.0, 0.0, 1.0);
::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, 1.0f);
for (const Polygon& p : triangles)
{
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[0]), max_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[1]), max_z).data());
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[2]), max_z).data());
}
::glEnd();
::glPopMatrix();
} }
} }
} }
} }
// render support top slices // calculate support top cap
if (it_max_z->second.support_slices_idx < support_slices.size()) if (it_max_z->second.support_slices_idx < support_slices.size())
{ {
const ExPolygons& polys = support_slices[it_max_z->second.support_slices_idx]; const ExPolygons& polys = support_slices[it_max_z->second.support_slices_idx];
@ -6042,22 +6044,48 @@ void GLCanvas3D::_render_sla_slices() const
{ {
Polygons triangles; Polygons triangles;
poly.triangulate(&triangles); poly.triangulate(&triangles);
if (!triangles.empty()) for (const Polygon& t : triangles)
{ {
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i) for (int v = 0; v < 3; ++v)
{
top_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z));
}
}
}
}
m_sla_caps[1].z = max_z;
m_sla_caps[1].triangles = top_triangles;
}
}
if (!bottom_triangles.empty() || !top_triangles.empty())
{
::glColor3f(1.0f, 0.37f, 0.0f);
for (const InstanceTransform& inst : instance_transforms)
{ {
::glPushMatrix(); ::glPushMatrix();
::glTranslated(instance_transforms[i].offset(0), instance_transforms[i].offset(1), instance_transforms[i].offset(2)); ::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2));
::glRotatef(instance_transforms[i].rotation, 0.0, 0.0, 1.0); ::glRotatef(inst.rotation, 0.0, 0.0, 1.0);
::glBegin(GL_TRIANGLES); ::glBegin(GL_TRIANGLES);
::glNormal3f(0.0f, 0.0f, 1.0f);
for (const Polygon& p : triangles) if (!bottom_triangles.empty())
{ {
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[0]), max_z).data()); for (const Vec3d& v : bottom_triangles)
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[1]), max_z).data()); {
::glVertex3dv((GLdouble*)to_3d(unscale(p.points[2]), max_z).data()); ::glVertex3dv((GLdouble*)v.data());
} }
}
if (!top_triangles.empty())
{
for (const Vec3d& v : top_triangles)
{
::glVertex3dv((GLdouble*)v.data());
}
}
::glEnd(); ::glEnd();
::glPopMatrix(); ::glPopMatrix();
@ -6066,9 +6094,6 @@ void GLCanvas3D::_render_sla_slices() const
} }
} }
} }
}
}
}
void GLCanvas3D::_update_volumes_hover_state() const void GLCanvas3D::_update_volumes_hover_state() const
{ {
@ -7414,7 +7439,7 @@ void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data,
return; return;
#endif // !ENABLE_USE_UNIQUE_GLCONTEXT #endif // !ENABLE_USE_UNIQUE_GLCONTEXT
m_legend_texture.generate(preview_data, tool_colors); m_legend_texture.generate(preview_data, tool_colors, *this);
} }
void GLCanvas3D::_generate_warning_texture(const std::string& msg) void GLCanvas3D::_generate_warning_texture(const std::string& msg)

View file

@ -677,6 +677,16 @@ private:
GLGizmoBase* _get_current() const; GLGizmoBase* _get_current() const;
}; };
struct SlaCap
{
double z;
Pointf3s triangles;
SlaCap() { reset(); }
void reset() { z = DBL_MAX; triangles.clear(); }
bool matches(double z) const { return this->z == z; }
};
class WarningTexture : public GUI::GLTexture class WarningTexture : public GUI::GLTexture
{ {
static const unsigned char Background_Color[3]; static const unsigned char Background_Color[3];
@ -710,7 +720,7 @@ private:
public: public:
LegendTexture(); LegendTexture();
bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors); bool generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors, const GLCanvas3D& canvas);
void render(const GLCanvas3D& canvas) const; void render(const GLCanvas3D& canvas) const;
}; };
@ -731,6 +741,7 @@ private:
mutable GLToolbar m_toolbar; mutable GLToolbar m_toolbar;
ClippingPlane m_clipping_planes[2]; ClippingPlane m_clipping_planes[2];
bool m_use_clipping_planes; bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2];
mutable GLVolumeCollection m_volumes; mutable GLVolumeCollection m_volumes;
Selection m_selection; Selection m_selection;
@ -809,7 +820,10 @@ public:
void set_clipping_plane(unsigned int id, const ClippingPlane& plane) void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
{ {
if (id < 2) if (id < 2)
{
m_clipping_planes[id] = plane; m_clipping_planes[id] = plane;
m_sla_caps[id].reset();
}
} }
void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; } void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; }
@ -905,6 +919,8 @@ public:
void do_flatten(); void do_flatten();
void do_mirror(); void do_mirror();
void set_camera_zoom(float zoom);
private: private:
bool _is_shown_on_screen() const; bool _is_shown_on_screen() const;
void _force_zoom_to_bed(); void _force_zoom_to_bed();

View file

@ -256,6 +256,15 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
} }
} }
void GLGizmoBase::render_grabbers(float size) const
{
for (int i = 0; i < (int)m_grabbers.size(); ++i)
{
if (m_grabbers[i].enabled)
m_grabbers[i].render((m_hover_id == i), size);
}
}
void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
{ {
float size = (float)box.max_size(); float size = (float)box.max_size();
@ -821,6 +830,8 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
Vec3d angles = Vec3d::Zero(); Vec3d angles = Vec3d::Zero();
Transform3d offsets_transform = Transform3d::Identity(); Transform3d offsets_transform = Transform3d::Identity();
Vec3d grabber_size = Vec3d::Zero();
if (single_instance) if (single_instance)
{ {
// calculate bounding box in instance local reference system // calculate bounding box in instance local reference system
@ -839,6 +850,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
angles = v->get_instance_rotation(); angles = v->get_instance_rotation();
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
grabber_size = v->get_instance_transformation().get_matrix(true, true, false, true) * box.size();
#else #else
transform = v->world_matrix().cast<double>(); transform = v->world_matrix().cast<double>();
// gets angles from first selected volume // gets angles from first selected volume
@ -856,6 +868,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
angles = Geometry::extract_euler_angles(transform); angles = Geometry::extract_euler_angles(transform);
// consider rotation+mirror only components of the transform for offsets // consider rotation+mirror only components of the transform for offsets
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
grabber_size = v->get_volume_transformation().get_matrix(true, true, false, true) * box.size();
#else #else
transform = v->world_matrix().cast<double>(); transform = v->world_matrix().cast<double>();
angles = Geometry::extract_euler_angles(transform); angles = Geometry::extract_euler_angles(transform);
@ -864,7 +877,10 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
#endif // ENABLE_MODELVOLUME_TRANSFORM #endif // ENABLE_MODELVOLUME_TRANSFORM
} }
else else
{
box = selection.get_bounding_box(); box = selection.get_bounding_box();
grabber_size = box.size();
}
m_box = box; m_box = box;
@ -909,7 +925,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f);
float box_max_size = (float)m_box.max_size(); float grabber_max_size = (float)std::max(grabber_size(0), std::max(grabber_size(1), grabber_size(2)));
if (m_hover_id == -1) if (m_hover_id == -1)
{ {
@ -935,7 +951,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
render_grabbers_connection(8, 9); render_grabbers_connection(8, 9);
render_grabbers_connection(9, 6); render_grabbers_connection(9, 6);
// draw grabbers // draw grabbers
render_grabbers(m_box); render_grabbers(grabber_max_size);
} }
else if ((m_hover_id == 0) || (m_hover_id == 1)) else if ((m_hover_id == 0) || (m_hover_id == 1))
{ {
@ -943,8 +959,8 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
::glColor3fv(m_grabbers[0].color); ::glColor3fv(m_grabbers[0].color);
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers // draw grabbers
m_grabbers[0].render(true, box_max_size); m_grabbers[0].render(true, grabber_max_size);
m_grabbers[1].render(true, box_max_size); m_grabbers[1].render(true, grabber_max_size);
} }
else if ((m_hover_id == 2) || (m_hover_id == 3)) else if ((m_hover_id == 2) || (m_hover_id == 3))
{ {
@ -952,8 +968,8 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
::glColor3fv(m_grabbers[2].color); ::glColor3fv(m_grabbers[2].color);
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers // draw grabbers
m_grabbers[2].render(true, box_max_size); m_grabbers[2].render(true, grabber_max_size);
m_grabbers[3].render(true, box_max_size); m_grabbers[3].render(true, grabber_max_size);
} }
else if ((m_hover_id == 4) || (m_hover_id == 5)) else if ((m_hover_id == 4) || (m_hover_id == 5))
{ {
@ -961,8 +977,8 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
::glColor3fv(m_grabbers[4].color); ::glColor3fv(m_grabbers[4].color);
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers // draw grabbers
m_grabbers[4].render(true, box_max_size); m_grabbers[4].render(true, grabber_max_size);
m_grabbers[5].render(true, box_max_size); m_grabbers[5].render(true, grabber_max_size);
} }
else if (m_hover_id >= 6) else if (m_hover_id >= 6)
{ {
@ -975,7 +991,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
// draw grabbers // draw grabbers
for (int i = 6; i < 10; ++i) for (int i = 6; i < 10; ++i)
{ {
m_grabbers[i].render(true, box_max_size); m_grabbers[i].render(true, grabber_max_size);
} }
} }
} }

View file

@ -175,6 +175,7 @@ protected:
float picking_color_component(unsigned int id) const; float picking_color_component(unsigned int id) const;
void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) const; void render_grabbers_for_picking(const BoundingBoxf3& box) const;
void set_tooltip(const std::string& tooltip) const; void set_tooltip(const std::string& tooltip) const;

View file

@ -426,6 +426,14 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool for
m_slider->SetTicksValues(ticks_from_config); m_slider->SetTicksValues(ticks_from_config);
set_double_slider_thumbs(layers_z, z_low, z_high); set_double_slider_thumbs(layers_z, z_low, z_high);
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
if (color_print_enable) {
const auto& config = wxGetApp().preset_bundle->full_config();
if (config.opt<ConfigOptionFloats>("nozzle_diameter")->values.size() > 1)
color_print_enable = false;
}
m_slider->EnableTickManipulation(color_print_enable);
} }
void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values, void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,

View file

@ -1,7 +1,7 @@
#ifndef slic3r_GUI_Utils_hpp_ #ifndef slic3r_GUI_Utils_hpp_
#define slic3r_GUI_Utils_hpp_ #define slic3r_GUI_Utils_hpp_
#include <functional> #include <memory>
#include <string> #include <string>
#include <boost/optional.hpp> #include <boost/optional.hpp>
@ -10,6 +10,7 @@
#include <wx/filedlg.h> #include <wx/filedlg.h>
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/debug.h>
class wxCheckBox; class wxCheckBox;
class wxTopLevelWindow; class wxTopLevelWindow;
@ -25,40 +26,80 @@ wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
class EventGuard class EventGuard
{ {
// This is a RAII-style smart-ptr-like guard that will bind any event to any event handler
// and unbind it as soon as it goes out of scope or unbind() is called.
// This can be used to solve the annoying problem of wx events being delivered to freed objects.
private:
// This is a way to type-erase both the event type as well as the handler:
struct EventStorageBase {
virtual ~EventStorageBase() {}
};
template<class EvTag, class Fun>
struct EventStorageFun : EventStorageBase {
wxEvtHandler *emitter;
EvTag tag;
Fun fun;
EventStorageFun(wxEvtHandler *emitter, const EvTag &tag, Fun fun)
: emitter(emitter)
, tag(tag)
, fun(std::move(fun))
{
emitter->Bind(this->tag, this->fun);
}
virtual ~EventStorageFun() { emitter->Unbind(tag, fun); }
};
template<typename EvTag, typename Class, typename EvArg, typename EvHandler>
struct EventStorageMethod : EventStorageBase {
typedef void(Class::* MethodPtr)(EvArg &);
wxEvtHandler *emitter;
EvTag tag;
MethodPtr method;
EvHandler *handler;
EventStorageMethod(wxEvtHandler *emitter, const EvTag &tag, MethodPtr method, EvHandler *handler)
: emitter(emitter)
, tag(tag)
, method(method)
, handler(handler)
{
emitter->Bind(tag, method, handler);
}
virtual ~EventStorageMethod() { emitter->Unbind(tag, method, handler); }
};
std::unique_ptr<EventStorageBase> event_storage;
public: public:
EventGuard() {} EventGuard() {}
EventGuard(const EventGuard&) = delete; EventGuard(const EventGuard&) = delete;
EventGuard(EventGuard &&other) : unbinder(std::move(other.unbinder)) {} EventGuard(EventGuard &&other) : event_storage(std::move(other.event_storage)) {}
~EventGuard() { template<class EvTag, class Fun>
if (unbinder) { EventGuard(wxEvtHandler *emitter, const EvTag &tag, Fun fun)
unbinder(false); :event_storage(new EventStorageFun<EvTag, Fun>(emitter, tag, std::move(fun)))
} {}
}
template<class EvTag, class Fun> void bind(wxEvtHandler *emitter, const EvTag &type, Fun fun) template<typename EvTag, typename Class, typename EvArg, typename EvHandler>
{ EventGuard(wxEvtHandler *emitter, const EvTag &tag, void(Class::* method)(EvArg &), EvHandler *handler)
// This is a way to type-erase both the event type as well as the handler: :event_storage(new EventStorageMethod<EvTag, Class, EvArg, EvHandler>(emitter, tag, method, handler))
{}
unbinder = std::move([=](bool bind) {
if (bind) {
emitter->Bind(type, fun);
} else {
emitter->Unbind(type, fun);
}
});
unbinder(true);
}
EventGuard& operator=(const EventGuard&) = delete; EventGuard& operator=(const EventGuard&) = delete;
EventGuard& operator=(EventGuard &&other) EventGuard& operator=(EventGuard &&other)
{ {
unbinder.swap(other.unbinder); event_storage = std::move(other.event_storage);
return *this; return *this;
} }
private:
std::function<void(bool)> unbinder; void unbind() { event_storage.reset(nullptr); }
explicit operator bool() const noexcept { return !!event_storage; }
}; };

View file

@ -914,6 +914,10 @@ struct Plater::priv
// GUI elements // GUI elements
wxNotebook *notebook; wxNotebook *notebook;
EventGuard guard_on_notebook_changed;
// Note: ^ The on_notebook_changed is guarded here because the wxNotebook d-tor tends to generate
// wxEVT_NOTEBOOK_PAGE_CHANGED events on some platforms, which causes them to be received by a freed Plater.
// EventGuard unbinds the handler in its d-tor.
Sidebar *sidebar; Sidebar *sidebar;
#if !ENABLE_IMGUI #if !ENABLE_IMGUI
wxPanel *panel3d; wxPanel *panel3d;
@ -1042,6 +1046,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology" "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology"
})) }))
, notebook(new wxNotebook(q, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM)) , notebook(new wxNotebook(q, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM))
, guard_on_notebook_changed(notebook, wxEVT_NOTEBOOK_PAGE_CHANGED, &priv::on_notebook_changed, this)
, sidebar(new Sidebar(q)) , sidebar(new Sidebar(q))
#if ENABLE_IMGUI #if ENABLE_IMGUI
, canvas3Dwidget(GLCanvas3DManager::create_wxglcanvas(notebook)) , canvas3Dwidget(GLCanvas3DManager::create_wxglcanvas(notebook))
@ -1124,9 +1129,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Events: // Events:
// Notebook page change event
notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &priv::on_notebook_changed, this);
// Preset change event // Preset change event
sidebar->Bind(wxEVT_COMBOBOX, &priv::on_select_preset, this); sidebar->Bind(wxEVT_COMBOBOX, &priv::on_select_preset, this);
@ -1606,6 +1608,10 @@ void Plater::priv::reset()
sidebar->obj_list()->delete_all_objects_from_list(); sidebar->obj_list()->delete_all_objects_from_list();
object_list_changed(); object_list_changed();
update(); update();
auto& config = wxGetApp().preset_bundle->project_config;
config.option<ConfigOptionFloats>("colorprint_heights")->values.clear();
} }
void Plater::priv::mirror(Axis axis) void Plater::priv::mirror(Axis axis)
@ -1740,6 +1746,9 @@ void Plater::priv::sla_optimize_rotation() {
if(rotoptimizing.load()) // wasn't canceled if(rotoptimizing.load()) // wasn't canceled
for(ModelInstance * oi : o->instances) oi->set_rotation({r[X], r[Y], r[Z]}); for(ModelInstance * oi : o->instances) oi->set_rotation({r[X], r[Y], r[Z]});
// Correct the z offset of the object which was corrupted be the rotation
o->ensure_on_bed();
stfn(0, L("Orientation found.")); stfn(0, L("Orientation found."));
statusbar()->set_range(prev_range); statusbar()->set_range(prev_range);
statusbar()->set_cancel_callback(); statusbar()->set_cancel_callback();
@ -1935,6 +1944,8 @@ void Plater::priv::fix_through_netfabb(const int obj_idx)
void Plater::priv::on_notebook_changed(wxBookCtrlEvent&) void Plater::priv::on_notebook_changed(wxBookCtrlEvent&)
{ {
wxCHECK_RET(canvas3D != nullptr, "on_notebook_changed on freed Plater");
const auto current_id = notebook->GetCurrentPage()->GetId(); const auto current_id = notebook->GetCurrentPage()->GetId();
#if ENABLE_IMGUI #if ENABLE_IMGUI
if (current_id == canvas3Dwidget->GetId()) { if (current_id == canvas3Dwidget->GetId()) {

View file

@ -1446,7 +1446,7 @@ void PrusaDoubleSlider::get_size(int *w, int *h)
double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection)
{ {
if (m_values.empty()) if (m_values.empty() || m_lower_value<0)
return 0.0; return 0.0;
if (m_values.size() <= m_higher_value) { if (m_values.size() <= m_higher_value) {
correct_higher_value(); correct_higher_value();
@ -1569,6 +1569,7 @@ void PrusaDoubleSlider::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, c
dc.DrawLine(pt_beg, pt_end); dc.DrawLine(pt_beg, pt_end);
//draw action icon //draw action icon
if (m_is_enabled_tick_manipulation)
draw_action_icon(dc, pt_beg, pt_end); draw_action_icon(dc, pt_beg, pt_end);
} }
} }
@ -1677,7 +1678,7 @@ void PrusaDoubleSlider::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wx
void PrusaDoubleSlider::draw_ticks(wxDC& dc) void PrusaDoubleSlider::draw_ticks(wxDC& dc)
{ {
dc.SetPen(DARK_GREY_PEN); dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
int height, width; int height, width;
get_size(&width, &height); get_size(&width, &height);
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width; const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
@ -1794,7 +1795,7 @@ void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
this->CaptureMouse(); this->CaptureMouse();
wxClientDC dc(this); wxClientDC dc(this);
wxPoint pos = event.GetLogicalPosition(dc); wxPoint pos = event.GetLogicalPosition(dc);
if (is_point_in_rect(pos, m_rect_tick_action)) { if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) {
action_tick(taOnIcon); action_tick(taOnIcon);
return; return;
} }
@ -1812,7 +1813,7 @@ void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
else else
detect_selected_slider(pos); detect_selected_slider(pos);
if (!m_selection) { if (!m_selection && m_is_enabled_tick_manipulation) {
const auto tick = is_point_near_tick(pos); const auto tick = is_point_near_tick(pos);
if (tick >= 0) if (tick >= 0)
{ {

View file

@ -683,6 +683,12 @@ public:
void ChangeOneLayerLock(); void ChangeOneLayerLock();
std::vector<double> GetTicksValues() const; std::vector<double> GetTicksValues() const;
void SetTicksValues(const std::vector<double>& heights); void SetTicksValues(const std::vector<double>& heights);
void EnableTickManipulation(bool enable = true) {
m_is_enabled_tick_manipulation = enable;
}
void DisableTickManipulation() {
EnableTickManipulation(false);
}
void OnPaint(wxPaintEvent& ) { render();} void OnPaint(wxPaintEvent& ) { render();}
void OnLeftDown(wxMouseEvent& event); void OnLeftDown(wxMouseEvent& event);
@ -753,6 +759,7 @@ private:
bool m_is_focused = false; bool m_is_focused = false;
bool m_is_action_icon_focesed = false; bool m_is_action_icon_focesed = false;
bool m_is_one_layer_icon_focesed = false; bool m_is_one_layer_icon_focesed = false;
bool m_is_enabled_tick_manipulation = true;
wxRect m_rect_lower_thumb; wxRect m_rect_lower_thumb;
wxRect m_rect_higher_thumb; wxRect m_rect_higher_thumb;