mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	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
					
				
					 13 changed files with 304 additions and 174 deletions
				
			
		|  | @ -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()); | ||||
| 
 | ||||
|     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 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(); | ||||
|     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,14 +5959,25 @@ void GLCanvas3D::_render_sla_slices() const | |||
| 
 | ||||
|             double min_z = clip_min_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_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 (it_min_z != index.end()) | ||||
|                 if (bottom_triangles.empty() && (it_min_z != index.end())) | ||||
|                 { | ||||
|                 // render model bottom slices
 | ||||
|                     // calculate model bottom cap
 | ||||
|                     if (it_min_z->second.model_slices_idx < model_slices.size()) | ||||
|                     { | ||||
|                         const ExPolygons& polys = model_slices[it_min_z->second.model_slices_idx]; | ||||
|  | @ -5943,31 +5985,17 @@ void GLCanvas3D::_render_sla_slices() const | |||
|                         { | ||||
|                             Polygons 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(); | ||||
|                                 ::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(); | ||||
|                                     bottom_triangles.emplace_back(to_3d(unscale(t.points[v]), min_z)); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                 // render support bottom slices
 | ||||
|                     // 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]; | ||||
|  | @ -5975,34 +6003,22 @@ void GLCanvas3D::_render_sla_slices() const | |||
|                         { | ||||
|                             Polygons 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(); | ||||
|                                 ::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(); | ||||
|                                     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; | ||||
|                 } | ||||
| 
 | ||||
|             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()) | ||||
|                     { | ||||
|                         const ExPolygons& polys = model_slices[it_max_z->second.model_slices_idx]; | ||||
|  | @ -6010,31 +6026,17 @@ void GLCanvas3D::_render_sla_slices() const | |||
|                         { | ||||
|                             Polygons 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(); | ||||
|                                 ::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(); | ||||
|                                     top_triangles.emplace_back(to_3d(unscale(t.points[v]), max_z)); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                 // render support top slices
 | ||||
|                     // 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]; | ||||
|  | @ -6042,22 +6044,48 @@ void GLCanvas3D::_render_sla_slices() const | |||
|                         { | ||||
|                             Polygons 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(); | ||||
|                                 ::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); | ||||
|                     ::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2)); | ||||
|                     ::glRotatef(inst.rotation, 0.0, 0.0, 1.0); | ||||
| 
 | ||||
|                     ::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()); | ||||
|                                     ::glVertex3dv((GLdouble*)to_3d(unscale(p.points[1]), max_z).data()); | ||||
|                                     ::glVertex3dv((GLdouble*)to_3d(unscale(p.points[2]), max_z).data()); | ||||
|                         for (const Vec3d& v : bottom_triangles) | ||||
|                         { | ||||
|                             ::glVertex3dv((GLdouble*)v.data()); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (!top_triangles.empty()) | ||||
|                     { | ||||
|                         for (const Vec3d& v : top_triangles) | ||||
|                         { | ||||
|                             ::glVertex3dv((GLdouble*)v.data()); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     ::glEnd(); | ||||
| 
 | ||||
|                     ::glPopMatrix(); | ||||
|  | @ -6066,9 +6094,6 @@ void GLCanvas3D::_render_sla_slices() const | |||
|         } | ||||
|     } | ||||
| } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GLCanvas3D::_update_volumes_hover_state() const | ||||
| { | ||||
|  | @ -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,6 +1569,7 @@ void PrusaDoubleSlider::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, c | |||
|         dc.DrawLine(pt_beg, pt_end); | ||||
| 
 | ||||
|         //draw action icon
 | ||||
|         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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tamasmeszaros
						tamasmeszaros