merge tm_sla_supports_backend with master, reapply fix for index slice invalidation, fix for autorotation z offset
This commit is contained in:
commit
980c53970b
@ -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";
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user