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.
// (Layers can be close to each other, model could have been resliced with bigger layer height, ...).
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());
colorprint_change = true;
}
if (colorprint_change)
if (colorprint_change && print.extruders().size()==1)
gcode += "M600\n";

View File

@ -382,7 +382,7 @@ std::string GCodePreviewData::get_legend_title() const
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
{
@ -465,15 +465,16 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std::
break;
}
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;
}
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;
}
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;
}

View File

@ -198,7 +198,7 @@ public:
void set_extrusion_paths_colors(const std::vector<std::string>& colors);
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);

View File

@ -908,12 +908,12 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
std::vector<SLAPrintObjectStep> steps;
bool invalidated = false;
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_back_radius"
|| opt_key == "support_head_width"
|| opt_key == "support_pillar_radius"
|| opt_key == "support_base_radius"
|| opt_key == "support_pillar_diameter"
|| opt_key == "support_base_diameter"
|| opt_key == "support_base_height"
|| opt_key == "support_critical_angle"
|| opt_key == "support_max_bridge_length"
@ -945,18 +945,21 @@ bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step)
if (step == slaposObjectSlice) {
invalidated |= this->invalidate_all_steps();
} 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);
} 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);
} else if (step == slaposSupportTree) {
invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports });
invalidated |= this->invalidate_steps({ slaposBasePool, slaposSliceSupports, slaposIndexSlices });
invalidated |= m_print->invalidate_step(slapsRasterize);
} else if (step == slaposBasePool) {
invalidated |= this->invalidate_step(slaposSliceSupports);
invalidated |= this->invalidate_steps({slaposSliceSupports, slaposIndexSlices});
invalidated |= m_print->invalidate_step(slapsRasterize);
} 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);
}
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();
// collects items to render
auto title = _(preview_data.get_legend_title());
const auto& config = wxGetApp().preset_bundle->full_config();
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);
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 std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->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();
if (items_count == 0)
@ -4400,6 +4422,12 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
// key B/b
case 66:
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
// key Z/z
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
float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta();
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();
set_camera_zoom(zoom);
}
void GLCanvas3D::on_timer(wxTimerEvent& evt)
@ -5229,6 +5246,21 @@ void GLCanvas3D::do_mirror()
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
{
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@ -5908,7 +5940,6 @@ void GLCanvas3D::_render_sla_slices() const
{
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>& support_slices = obj->get_support_slices();
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
@ -5928,142 +5959,136 @@ void GLCanvas3D::_render_sla_slices() const
double min_z = clip_min_z - shift_z;
double max_z = clip_max_z - shift_z;
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; });
::glColor3f(1.0f, 0.37f, 0.0f);
Pointf3s bottom_triangles;
Pointf3s top_triangles;
if (it_min_z != index.end())
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())
{
// render model bottom slices
if (it_min_z->second.model_slices_idx < model_slices.size())
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_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; });
if (bottom_triangles.empty() && (it_min_z != index.end()))
{
const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx];
for (const ExPolygon& poly : polys)
// calculate model bottom cap
if (it_min_z->second.model_slices_idx < model_slices.size())
{
Polygons triangles;
poly.triangulate(&triangles);
if (!triangles.empty())
const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx];
for (const ExPolygon& poly : polys)
{
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i)
Polygons triangles;
poly.triangulate(&triangles);
for (const Polygon& t : triangles)
{
::glPushMatrix();
::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)
for (int v = 2; v >= 0; --v)
{
::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());
bottom_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z));
}
::glEnd();
::glPopMatrix();
}
}
}
// calculate support bottom cap
if (it_min_z->second.support_slices_idx < support_slices.size())
{
const ExPolygons& polys = support_slices[it_min_z->second.support_slices_idx];
for (const ExPolygon& poly : polys)
{
Polygons triangles;
poly.triangulate(&triangles);
for (const Polygon& t : triangles)
{
for (int v = 2; v >= 0; --v)
{
bottom_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z));
}
}
}
}
m_sla_caps[0].z = min_z;
m_sla_caps[0].triangles = bottom_triangles;
}
// render support bottom slices
if (it_min_z->second.support_slices_idx < support_slices.size())
if (top_triangles.empty() && (it_max_z != index.end()))
{
const ExPolygons& polys = support_slices[it_min_z->second.support_slices_idx];
for (const ExPolygon& poly : polys)
// calculate model top cap
if (it_max_z->second.model_slices_idx < model_slices.size())
{
Polygons triangles;
poly.triangulate(&triangles);
if (!triangles.empty())
const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx];
for (const ExPolygon& poly : polys)
{
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i)
Polygons triangles;
poly.triangulate(&triangles);
for (const Polygon& t : triangles)
{
::glPushMatrix();
::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)
for (int v = 0; v < 3; ++v)
{
::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());
top_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z));
}
::glEnd();
::glPopMatrix();
}
}
}
// calculate support top cap
if (it_max_z->second.support_slices_idx < support_slices.size())
{
const ExPolygons& polys = support_slices[it_max_z->second.support_slices_idx];
for (const ExPolygon& poly : polys)
{
Polygons triangles;
poly.triangulate(&triangles);
for (const Polygon& t : triangles)
{
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 (it_max_z != index.end())
if (!bottom_triangles.empty() || !top_triangles.empty())
{
// render model top slices
if (it_max_z->second.model_slices_idx < model_slices.size())
::glColor3f(1.0f, 0.37f, 0.0f);
for (const InstanceTransform& inst : instance_transforms)
{
const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx];
for (const ExPolygon& poly : polys)
::glPushMatrix();
::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2));
::glRotatef(inst.rotation, 0.0, 0.0, 1.0);
::glBegin(GL_TRIANGLES);
if (!bottom_triangles.empty())
{
Polygons triangles;
poly.triangulate(&triangles);
if (!triangles.empty())
for (const Vec3d& v : bottom_triangles)
{
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i)
{
::glPushMatrix();
::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();
}
::glVertex3dv((GLdouble*)v.data());
}
}
}
// render support top slices
if (it_max_z->second.support_slices_idx < support_slices.size())
{
const ExPolygons& polys = support_slices[it_max_z->second.support_slices_idx];
for (const ExPolygon& poly : polys)
if (!top_triangles.empty())
{
Polygons triangles;
poly.triangulate(&triangles);
if (!triangles.empty())
for (const Vec3d& v : top_triangles)
{
for (unsigned int i = 0; i < (unsigned int)instances.size(); ++i)
{
::glPushMatrix();
::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();
}
::glVertex3dv((GLdouble*)v.data());
}
}
::glEnd();
::glPopMatrix();
}
}
}
@ -7414,7 +7439,7 @@ void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data,
return;
#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)

View File

@ -677,6 +677,16 @@ private:
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
{
static const unsigned char Background_Color[3];
@ -710,7 +720,7 @@ private:
public:
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;
};
@ -731,6 +741,7 @@ private:
mutable GLToolbar m_toolbar;
ClippingPlane m_clipping_planes[2];
bool m_use_clipping_planes;
mutable SlaCap m_sla_caps[2];
mutable GLVolumeCollection m_volumes;
Selection m_selection;
@ -809,7 +820,10 @@ public:
void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
{
if (id < 2)
{
m_clipping_planes[id] = plane;
m_sla_caps[id].reset();
}
}
void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; }
@ -905,6 +919,8 @@ public:
void do_flatten();
void do_mirror();
void set_camera_zoom(float zoom);
private:
bool _is_shown_on_screen() const;
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
{
float size = (float)box.max_size();
@ -821,6 +830,8 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
Vec3d angles = Vec3d::Zero();
Transform3d offsets_transform = Transform3d::Identity();
Vec3d grabber_size = Vec3d::Zero();
if (single_instance)
{
// 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();
// consider rotation+mirror only components of the transform for offsets
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
transform = v->world_matrix().cast<double>();
// 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);
// consider rotation+mirror only components of the transform for offsets
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
transform = v->world_matrix().cast<double>();
angles = Geometry::extract_euler_angles(transform);
@ -864,7 +877,10 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
#endif // ENABLE_MODELVOLUME_TRANSFORM
}
else
{
box = selection.get_bounding_box();
grabber_size = box.size();
}
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);
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)
{
@ -935,7 +951,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
render_grabbers_connection(8, 9);
render_grabbers_connection(9, 6);
// draw grabbers
render_grabbers(m_box);
render_grabbers(grabber_max_size);
}
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);
render_grabbers_connection(0, 1);
// draw grabbers
m_grabbers[0].render(true, box_max_size);
m_grabbers[1].render(true, box_max_size);
m_grabbers[0].render(true, grabber_max_size);
m_grabbers[1].render(true, grabber_max_size);
}
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);
render_grabbers_connection(2, 3);
// draw grabbers
m_grabbers[2].render(true, box_max_size);
m_grabbers[3].render(true, box_max_size);
m_grabbers[2].render(true, grabber_max_size);
m_grabbers[3].render(true, grabber_max_size);
}
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);
render_grabbers_connection(4, 5);
// draw grabbers
m_grabbers[4].render(true, box_max_size);
m_grabbers[5].render(true, box_max_size);
m_grabbers[4].render(true, grabber_max_size);
m_grabbers[5].render(true, grabber_max_size);
}
else if (m_hover_id >= 6)
{
@ -975,7 +991,7 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
// draw grabbers
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;
void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) 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);
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,

View File

@ -1,7 +1,7 @@
#ifndef slic3r_GUI_Utils_hpp_
#define slic3r_GUI_Utils_hpp_
#include <functional>
#include <memory>
#include <string>
#include <boost/optional.hpp>
@ -10,6 +10,7 @@
#include <wx/filedlg.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/debug.h>
class wxCheckBox;
class wxTopLevelWindow;
@ -25,40 +26,80 @@ wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
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:
EventGuard() {}
EventGuard(const EventGuard&) = delete;
EventGuard(EventGuard &&other) : unbinder(std::move(other.unbinder)) {}
EventGuard(EventGuard &&other) : event_storage(std::move(other.event_storage)) {}
~EventGuard() {
if (unbinder) {
unbinder(false);
}
}
template<class EvTag, class Fun>
EventGuard(wxEvtHandler *emitter, const EvTag &tag, Fun fun)
: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)
{
// This is a way to type-erase both the event type as well as the handler:
unbinder = std::move([=](bool bind) {
if (bind) {
emitter->Bind(type, fun);
} else {
emitter->Unbind(type, fun);
}
});
unbinder(true);
}
template<typename EvTag, typename Class, typename EvArg, typename EvHandler>
EventGuard(wxEvtHandler *emitter, const EvTag &tag, void(Class::* method)(EvArg &), EvHandler *handler)
:event_storage(new EventStorageMethod<EvTag, Class, EvArg, EvHandler>(emitter, tag, method, handler))
{}
EventGuard& operator=(const EventGuard&) = delete;
EventGuard& operator=(EventGuard &&other)
{
unbinder.swap(other.unbinder);
event_storage = std::move(other.event_storage);
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
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;
#if !ENABLE_IMGUI
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"
}))
, 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))
#if ENABLE_IMGUI
, canvas3Dwidget(GLCanvas3DManager::create_wxglcanvas(notebook))
@ -1124,9 +1129,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
// Events:
// Notebook page change event
notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &priv::on_notebook_changed, this);
// Preset change event
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();
object_list_changed();
update();
auto& config = wxGetApp().preset_bundle->project_config;
config.option<ConfigOptionFloats>("colorprint_heights")->values.clear();
}
void Plater::priv::mirror(Axis axis)
@ -1740,6 +1746,9 @@ void Plater::priv::sla_optimize_rotation() {
if(rotoptimizing.load()) // wasn't canceled
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."));
statusbar()->set_range(prev_range);
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&)
{
wxCHECK_RET(canvas3D != nullptr, "on_notebook_changed on freed Plater");
const auto current_id = notebook->GetCurrentPage()->GetId();
#if ENABLE_IMGUI
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)
{
if (m_values.empty())
if (m_values.empty() || m_lower_value<0)
return 0.0;
if (m_values.size() <= m_higher_value) {
correct_higher_value();
@ -1569,7 +1569,8 @@ void PrusaDoubleSlider::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, c
dc.DrawLine(pt_beg, pt_end);
//draw action icon
draw_action_icon(dc, pt_beg, pt_end);
if (m_is_enabled_tick_manipulation)
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)
{
dc.SetPen(DARK_GREY_PEN);
dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
int height, width;
get_size(&width, &height);
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
@ -1794,7 +1795,7 @@ void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
this->CaptureMouse();
wxClientDC dc(this);
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);
return;
}
@ -1812,7 +1813,7 @@ void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
else
detect_selected_slider(pos);
if (!m_selection) {
if (!m_selection && m_is_enabled_tick_manipulation) {
const auto tick = is_point_near_tick(pos);
if (tick >= 0)
{

View File

@ -683,6 +683,12 @@ public:
void ChangeOneLayerLock();
std::vector<double> GetTicksValues() const;
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 OnLeftDown(wxMouseEvent& event);
@ -753,6 +759,7 @@ private:
bool m_is_focused = false;
bool m_is_action_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_higher_thumb;