mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'master' into fix-assertions
This commit is contained in:
		
						commit
						1ed7895f61
					
				
					 21 changed files with 562 additions and 256 deletions
				
			
		|  | @ -34,6 +34,8 @@ option(SLIC3R_PERL_XS           "Compile XS Perl module and enable Perl unit and | ||||||
| option(SLIC3R_ASAN              "Enable ASan on Clang and GCC" 0) | option(SLIC3R_ASAN              "Enable ASan on Clang and GCC" 0) | ||||||
| option(SLIC3R_SYNTAXONLY        "Only perform source code correctness checking, no binary output (UNIX only)" 0) | option(SLIC3R_SYNTAXONLY        "Only perform source code correctness checking, no binary output (UNIX only)" 0) | ||||||
| 
 | 
 | ||||||
|  | set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux") | ||||||
|  | 
 | ||||||
| # Proposal for C++ unit tests and sandboxes | # Proposal for C++ unit tests and sandboxes | ||||||
| option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" OFF) | option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" OFF) | ||||||
| option(SLIC3R_BUILD_TESTS       "Build unit tests" OFF) | option(SLIC3R_BUILD_TESTS       "Build unit tests" OFF) | ||||||
|  |  | ||||||
|  | @ -91,6 +91,10 @@ You can also use the Visual Studio GUI or other generators as mentioned above. | ||||||
| The `DESTDIR` option is the location where the bundle will be installed. | The `DESTDIR` option is the location where the bundle will be installed. | ||||||
| This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory. | This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory. | ||||||
| 
 | 
 | ||||||
|  | Warning: If the `build` directory is nested too deep inside other folders, various file paths during the build | ||||||
|  | become too long and the build might fail due to file writing errors. For this reason, it is recommended to | ||||||
|  | place the `build` directory relatively close to the drive root. | ||||||
|  | 
 | ||||||
| Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**. | Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**. | ||||||
| The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio. | The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio. | ||||||
| You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build. | You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build. | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ if (SLIC3R_GUI) | ||||||
|     endif() |     endif() | ||||||
| 
 | 
 | ||||||
|     if (CMAKE_SYSTEM_NAME STREQUAL "Linux") |     if (CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||||||
|  |         set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}") | ||||||
|         if (SLIC3R_WX_STABLE) |         if (SLIC3R_WX_STABLE) | ||||||
|             find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl) |             find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl) | ||||||
|         else () |         else () | ||||||
|  |  | ||||||
|  | @ -175,6 +175,11 @@ struct AMFParserContext | ||||||
|         bool  mirrory_set; |         bool  mirrory_set; | ||||||
|         float mirrorz; |         float mirrorz; | ||||||
|         bool  mirrorz_set; |         bool  mirrorz_set; | ||||||
|  | 
 | ||||||
|  |         bool anything_set() const { return deltax_set || deltay_set || deltaz_set || | ||||||
|  |                                            rx_set || ry_set || rz_set || | ||||||
|  |                                            scalex_set || scaley_set || scalez_set || | ||||||
|  |                                            mirrorx_set || mirrory_set || mirrorz_set; } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct Object { |     struct Object { | ||||||
|  | @ -644,11 +649,7 @@ void AMFParserContext::endDocument() | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         for (const Instance &instance : object.second.instances) |         for (const Instance &instance : object.second.instances) | ||||||
| #if ENABLE_VOLUMES_CENTERING_FIXES |             if (instance.anything_set()) { | ||||||
|         { |  | ||||||
| #else |  | ||||||
|             if (instance.deltax_set && instance.deltay_set) { |  | ||||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 |  | ||||||
|                 ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); |                 ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); | ||||||
|                 mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); |                 mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); | ||||||
|                 mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); |                 mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); | ||||||
|  |  | ||||||
|  | @ -56,6 +56,113 @@ public: | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | template<class Vector, | ||||||
|  |          class Value = typename Vector::value_type> | ||||||
|  | class IndexBasedIterator { | ||||||
|  |     static const size_t NONE = size_t(-1); | ||||||
|  | 
 | ||||||
|  |     std::reference_wrapper<Vector> m_index_ref; | ||||||
|  |     size_t m_idx = NONE; | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     using value_type = Value; | ||||||
|  |     using pointer = Value *; | ||||||
|  |     using reference = Value &; | ||||||
|  |     using difference_type = long; | ||||||
|  |     using iterator_category = std::random_access_iterator_tag; | ||||||
|  | 
 | ||||||
|  |     inline explicit | ||||||
|  |     IndexBasedIterator(Vector& index, size_t idx): | ||||||
|  |         m_index_ref(index), m_idx(idx) {} | ||||||
|  | 
 | ||||||
|  |     // Post increment
 | ||||||
|  |     inline IndexBasedIterator operator++(int) { | ||||||
|  |         IndexBasedIterator cpy(*this); ++m_idx; return cpy; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator operator--(int) { | ||||||
|  |         IndexBasedIterator cpy(*this); --m_idx; return cpy; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator& operator++() { | ||||||
|  |         ++m_idx; return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator& operator--() { | ||||||
|  |         --m_idx; return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator& operator+=(difference_type l) { | ||||||
|  |         m_idx += size_t(l); return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator operator+(difference_type l) { | ||||||
|  |         auto cpy = *this; cpy += l; return cpy; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator& operator-=(difference_type l) { | ||||||
|  |         m_idx -= size_t(l); return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline IndexBasedIterator operator-(difference_type l) { | ||||||
|  |         auto cpy = *this; cpy -= l; return cpy; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     operator difference_type() { return difference_type(m_idx); } | ||||||
|  | 
 | ||||||
|  |     inline bool is_end() const { return m_idx >= m_index_ref.get().size();} | ||||||
|  | 
 | ||||||
|  |     inline Value & operator*() const { | ||||||
|  |         assert(m_idx < m_index_ref.get().size()); | ||||||
|  |         return m_index_ref.get().operator[](m_idx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline Value * operator->() const { | ||||||
|  |         assert(m_idx < m_index_ref.get().size()); | ||||||
|  |         return &m_index_ref.get().operator[](m_idx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator ==(const IndexBasedIterator& other) { | ||||||
|  |         size_t e = m_index_ref.get().size(); | ||||||
|  |         return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator !=(const IndexBasedIterator& other) { | ||||||
|  |         return !(*this == other); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <=(const IndexBasedIterator& other) { | ||||||
|  |         return (m_idx < other.m_idx) || (*this == other); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator <(const IndexBasedIterator& other) { | ||||||
|  |         return m_idx < other.m_idx && (*this != other); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator >=(const IndexBasedIterator& other) { | ||||||
|  |         return m_idx > other.m_idx || *this == other; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator >(const IndexBasedIterator& other) { | ||||||
|  |         return m_idx > other.m_idx && *this != other; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template<class It> class Range { | ||||||
|  |     It from, to; | ||||||
|  | public: | ||||||
|  |     It begin() const { return from; } | ||||||
|  |     It end() const { return to; } | ||||||
|  |     using Type = It; | ||||||
|  | 
 | ||||||
|  |     Range() = default; | ||||||
|  |     Range(It &&b, It &&e): | ||||||
|  |         from(std::forward<It>(b)), to(std::forward<It>(e)) {} | ||||||
|  | 
 | ||||||
|  |     inline size_t size() const { return end() - begin(); } | ||||||
|  |     inline bool empty() const { return size() == 0; } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #endif // MTUTILS_HPP
 | #endif // MTUTILS_HPP
 | ||||||
|  |  | ||||||
|  | @ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | SlicedSupports SLASupportTree::slice(const std::vector<float> &heights, | ||||||
|  |                                      float cr) const | ||||||
|  | { | ||||||
|  |     TriangleMesh fullmesh = m_impl->merged_mesh(); | ||||||
|  |     fullmesh.merge(get_pad()); | ||||||
|  |     TriangleMeshSlicer slicer(&fullmesh); | ||||||
|  |     SlicedSupports ret; | ||||||
|  |     slicer.slice(heights, cr, &ret, get().ctl().cancelfn); | ||||||
|  | 
 | ||||||
|  |     return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate, | const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate, | ||||||
|                                             const PoolConfig& pcfg) const |                                             const PoolConfig& pcfg) const | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -181,6 +181,8 @@ public: | ||||||
|     /// Get the sliced 2d layers of the support geometry.
 |     /// Get the sliced 2d layers of the support geometry.
 | ||||||
|     SlicedSupports slice(float layerh, float init_layerh = -1.0) const; |     SlicedSupports slice(float layerh, float init_layerh = -1.0) const; | ||||||
| 
 | 
 | ||||||
|  |     SlicedSupports slice(const std::vector<float>&, float closing_radius) const; | ||||||
|  | 
 | ||||||
|     /// Adding the "pad" (base pool) under the supports
 |     /// Adding the "pad" (base pool) under the supports
 | ||||||
|     const TriangleMesh& add_pad(const SliceLayer& baseplate, |     const TriangleMesh& add_pad(const SliceLayer& baseplate, | ||||||
|                                 const PoolConfig& pcfg) const; |                                 const PoolConfig& pcfg) const; | ||||||
|  |  | ||||||
|  | @ -30,7 +30,6 @@ public: | ||||||
|     std::vector<sla::SupportPoint> support_points;     // all the support points (manual/auto)
 |     std::vector<sla::SupportPoint> support_points;     // all the support points (manual/auto)
 | ||||||
|     SupportTreePtr   support_tree_ptr;   // the supports
 |     SupportTreePtr   support_tree_ptr;   // the supports
 | ||||||
|     SlicedSupports   support_slices;     // sliced supports
 |     SlicedSupports   support_slices;     // sliced supports
 | ||||||
|     std::vector<LevelID>    level_ids; |  | ||||||
| 
 | 
 | ||||||
|     inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {} |     inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {} | ||||||
| }; | }; | ||||||
|  | @ -567,6 +566,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { | ||||||
|     return scfg; |     return scfg; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) { | ||||||
|  |     sla::PoolConfig pcfg; | ||||||
|  | 
 | ||||||
|  |     pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat(); | ||||||
|  |     pcfg.wall_slope = c.pad_wall_slope.getFloat(); | ||||||
|  |     pcfg.edge_radius_mm = c.pad_edge_radius.getFloat(); | ||||||
|  |     pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat(); | ||||||
|  |     pcfg.min_wall_height_mm = c.pad_wall_height.getFloat(); | ||||||
|  | 
 | ||||||
|  |     return pcfg; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void swapXY(ExPolygon& expoly) { | void swapXY(ExPolygon& expoly) { | ||||||
|     for(auto& p : expoly.contour.points) std::swap(p(X), p(Y)); |     for(auto& p : expoly.contour.points) std::swap(p(X), p(Y)); | ||||||
|     for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y)); |     for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y)); | ||||||
|  | @ -591,25 +602,9 @@ std::string SLAPrint::validate() const | ||||||
|     return ""; |     return ""; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d, |  | ||||||
|                                                float elevation, |  | ||||||
|                                                float initial_layer_height, |  | ||||||
|                                                float layer_height) const |  | ||||||
| { |  | ||||||
|     std::vector<float> heights; |  | ||||||
|     float minZ = float(bb3d.min(Z)) - float(elevation); |  | ||||||
|     float maxZ = float(bb3d.max(Z)); |  | ||||||
|     auto flh = float(layer_height); |  | ||||||
|     auto gnd = float(bb3d.min(Z)); |  | ||||||
| 
 |  | ||||||
|     for(float h = minZ + initial_layer_height; h < maxZ; h += flh) |  | ||||||
|         if(h >= gnd) heights.emplace_back(h); |  | ||||||
| 
 |  | ||||||
|     return heights; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| template<class...Args> | template<class...Args> | ||||||
| void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) { | void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) | ||||||
|  | { | ||||||
|     BOOST_LOG_TRIVIAL(info) << st << "% " << msg; |     BOOST_LOG_TRIVIAL(info) << st << "% " << msg; | ||||||
|     p.set_status(st, msg, std::forward<Args>(args)...); |     p.set_status(st, msg, std::forward<Args>(args)...); | ||||||
| } | } | ||||||
|  | @ -620,12 +615,19 @@ void SLAPrint::process() | ||||||
|     using namespace sla; |     using namespace sla; | ||||||
|     using ExPolygon = Slic3r::ExPolygon; |     using ExPolygon = Slic3r::ExPolygon; | ||||||
| 
 | 
 | ||||||
|  |     if(m_objects.empty()) return; | ||||||
|  | 
 | ||||||
|     // Assumption: at this point the print objects should be populated only with
 |     // Assumption: at this point the print objects should be populated only with
 | ||||||
|     // the model objects we have to process and the instances are also filtered
 |     // the model objects we have to process and the instances are also filtered
 | ||||||
| 
 | 
 | ||||||
|     // shortcut to initial layer height
 |     // shortcut to initial layer height
 | ||||||
|     double ilhd = m_material_config.initial_layer_height.getFloat(); |     double ilhd = m_material_config.initial_layer_height.getFloat(); | ||||||
|     auto   ilh  = float(ilhd); |     auto   ilh  = float(ilhd); | ||||||
|  |     double lhd  = m_objects.front()->m_config.layer_height.getFloat(); | ||||||
|  |     float  lh   = float(lhd); | ||||||
|  | 
 | ||||||
|  |     auto ilhs = LevelID(ilhd / SCALING_FACTOR); | ||||||
|  |     auto lhs  = LevelID(lhd  / SCALING_FACTOR); | ||||||
|     const size_t objcount = m_objects.size(); |     const size_t objcount = m_objects.size(); | ||||||
| 
 | 
 | ||||||
|     const unsigned min_objstatus = 0;   // where the per object operations start
 |     const unsigned min_objstatus = 0;   // where the per object operations start
 | ||||||
|  | @ -646,24 +648,59 @@ void SLAPrint::process() | ||||||
| 
 | 
 | ||||||
|     // Slicing the model object. This method is oversimplified and needs to
 |     // Slicing the model object. This method is oversimplified and needs to
 | ||||||
|     // be compared with the fff slicing algorithm for verification
 |     // be compared with the fff slicing algorithm for verification
 | ||||||
|     auto slice_model = [this, ilh](SLAPrintObject& po) { |     auto slice_model = [this, ilhs, lhs, ilh, lh](SLAPrintObject& po) { | ||||||
|         double lh = po.m_config.layer_height.getFloat(); |  | ||||||
| 
 |  | ||||||
|         TriangleMesh mesh = po.transformed_mesh(); |         TriangleMesh mesh = po.transformed_mesh(); | ||||||
|  | 
 | ||||||
|  |         // We need to prepare the slice index...
 | ||||||
|  | 
 | ||||||
|  |         auto&& bb3d = mesh.bounding_box(); | ||||||
|  |         double minZ = bb3d.min(Z) - po.get_elevation(); | ||||||
|  |         double maxZ = bb3d.max(Z); | ||||||
|  | 
 | ||||||
|  |         auto minZs = LevelID(minZ / SCALING_FACTOR); | ||||||
|  |         auto maxZs = LevelID(maxZ / SCALING_FACTOR); | ||||||
|  | 
 | ||||||
|  |         po.m_slice_index.clear(); | ||||||
|  |         po.m_slice_index.reserve(size_t(maxZs - (minZs + ilhs) / lhs) + 1); | ||||||
|  |         po.m_slice_index.emplace_back(minZs + ilhs, float(minZ) + ilh / 2.f, ilh); | ||||||
|  | 
 | ||||||
|  |         for(LevelID h = minZs + ilhs + lhs; h <= maxZs; h += lhs) { | ||||||
|  |             po.m_slice_index.emplace_back(h, float(h*SCALING_FACTOR) - lh / 2.f, lh); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         auto slindex_it = po.search_slice_index(float(bb3d.min(Z))); | ||||||
|  | 
 | ||||||
|  |         if(slindex_it == po.m_slice_index.end()) | ||||||
|  |             throw std::runtime_error(L("Slicing had to be stopped " | ||||||
|  |                                        "due to an internal error.")); | ||||||
|  | 
 | ||||||
|  |         po.m_model_height_levels.clear(); | ||||||
|  |         po.m_model_height_levels.reserve(po.m_slice_index.size()); | ||||||
|  |         for(auto it = slindex_it; it != po.m_slice_index.end(); ++it) | ||||||
|  |         { | ||||||
|  |             po.m_model_height_levels.emplace_back(it->slice_level()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         TriangleMeshSlicer slicer(&mesh); |         TriangleMeshSlicer slicer(&mesh); | ||||||
| 
 | 
 | ||||||
|         // The 1D grid heights
 |         po.m_model_slices.clear(); | ||||||
|         std::vector<float> heights = calculate_heights(mesh.bounding_box(), |         slicer.slice(po.m_model_height_levels, | ||||||
|                                                        float(po.get_elevation()), |                      float(po.config().slice_closing_radius.value), | ||||||
|                                                        ilh, float(lh)); |                      &po.m_model_slices, | ||||||
|  |                      [this](){ throw_if_canceled(); }); | ||||||
| 
 | 
 | ||||||
|         auto& layers = po.m_model_slices; layers.clear(); |         auto mit = slindex_it; | ||||||
| 		slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); }); |         for(size_t id = 0; | ||||||
|  |             id < po.m_model_slices.size() && mit != po.m_slice_index.end(); | ||||||
|  |             id++) | ||||||
|  |         { | ||||||
|  |             mit->set_model_slice_idx(id); ++mit; | ||||||
|  |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // In this step we check the slices, identify island and cover them with
 |     // In this step we check the slices, identify island and cover them with
 | ||||||
|     // support points. Then we sprinkle the rest of the mesh.
 |     // support points. Then we sprinkle the rest of the mesh.
 | ||||||
|     auto support_points = [this, ilh](SLAPrintObject& po) { |     auto support_points = [this](SLAPrintObject& po) { | ||||||
|         const ModelObject& mo = *po.m_model_object; |         const ModelObject& mo = *po.m_model_object; | ||||||
|         po.m_supportdata.reset( |         po.m_supportdata.reset( | ||||||
|                     new SLAPrintObject::SupportData(po.transformed_mesh()) ); |                     new SLAPrintObject::SupportData(po.transformed_mesh()) ); | ||||||
|  | @ -680,12 +717,7 @@ void SLAPrint::process() | ||||||
|         if (mo.sla_points_status != sla::PointsStatus::UserModified) { |         if (mo.sla_points_status != sla::PointsStatus::UserModified) { | ||||||
| 
 | 
 | ||||||
|             // calculate heights of slices (slices are calculated already)
 |             // calculate heights of slices (slices are calculated already)
 | ||||||
|             double lh = po.m_config.layer_height.getFloat(); |             const std::vector<float>& heights = po.m_model_height_levels; | ||||||
| 
 |  | ||||||
|             std::vector<float> heights = |  | ||||||
|                     calculate_heights(po.transformed_mesh().bounding_box(), |  | ||||||
|                                       float(po.get_elevation()), |  | ||||||
|                                       ilh, float(lh)); |  | ||||||
| 
 | 
 | ||||||
|             this->throw_if_canceled(); |             this->throw_if_canceled(); | ||||||
|             SLAAutoSupports::Config config; |             SLAAutoSupports::Config config; | ||||||
|  | @ -831,86 +863,34 @@ void SLAPrint::process() | ||||||
|     // Slicing the support geometries similarly to the model slicing procedure.
 |     // Slicing the support geometries similarly to the model slicing procedure.
 | ||||||
|     // If the pad had been added previously (see step "base_pool" than it will
 |     // If the pad had been added previously (see step "base_pool" than it will
 | ||||||
|     // be part of the slices)
 |     // be part of the slices)
 | ||||||
|     auto slice_supports = [ilh](SLAPrintObject& po) { |     auto slice_supports = [](SLAPrintObject& po) { | ||||||
|         auto& sd = po.m_supportdata; |         auto& sd = po.m_supportdata; | ||||||
|  | 
 | ||||||
|  |         if(sd) sd->support_slices.clear(); | ||||||
|  | 
 | ||||||
|         if(sd && sd->support_tree_ptr) { |         if(sd && sd->support_tree_ptr) { | ||||||
|             auto lh = float(po.m_config.layer_height.getFloat()); | 
 | ||||||
|             sd->support_slices = sd->support_tree_ptr->slice(lh, ilh); |             std::vector<float> heights; heights.reserve(po.m_slice_index.size()); | ||||||
|  | 
 | ||||||
|  |             for(auto& rec : po.m_slice_index) { | ||||||
|  |                 heights.emplace_back(rec.slice_level()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             sd->support_slices = sd->support_tree_ptr->slice( | ||||||
|  |                         heights, float(po.config().slice_closing_radius.value)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for(size_t i = 0; | ||||||
|  |             i < sd->support_slices.size() && i < po.m_slice_index.size(); | ||||||
|  |             ++i) | ||||||
|  |         { | ||||||
|  |             po.m_slice_index[i].set_support_slice_idx(i); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // We have the layer polygon collection but we need to unite them into
 |     // We have the layer polygon collection but we need to unite them into
 | ||||||
|     // an index where the key is the height level in discrete levels (clipper)
 |     // an index where the key is the height level in discrete levels (clipper)
 | ||||||
|     auto index_slices = [this, ilhd](SLAPrintObject& po) { |     auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) { | ||||||
|         po.m_slice_index.clear(); |  | ||||||
|         auto sih = LevelID(scale_(ilhd)); |  | ||||||
| 
 |  | ||||||
|         // Establish the slice grid boundaries
 |  | ||||||
|         auto bb = po.transformed_mesh().bounding_box(); |  | ||||||
|         double modelgnd = bb.min(Z); |  | ||||||
|         double elevation = po.get_elevation(); |  | ||||||
|         double lh = po.m_config.layer_height.getFloat(); |  | ||||||
|         double minZ = modelgnd - elevation; |  | ||||||
| 
 |  | ||||||
|         // scaled values:
 |  | ||||||
|         auto sminZ = LevelID(scale_(minZ)); |  | ||||||
|         auto smaxZ = LevelID(scale_(bb.max(Z))); |  | ||||||
|         auto smodelgnd = LevelID(scale_(modelgnd)); |  | ||||||
|         auto slh = LevelID(scale_(lh)); |  | ||||||
| 
 |  | ||||||
|         // It is important that the next levels match the levels in
 |  | ||||||
|         // model_slice method. Only difference is that here it works with
 |  | ||||||
|         // scaled coordinates
 |  | ||||||
|         po.m_level_ids.clear(); |  | ||||||
|         for(LevelID h = sminZ + sih; h < smaxZ; h += slh) |  | ||||||
|             if(h >= smodelgnd) po.m_level_ids.emplace_back(h); |  | ||||||
| 
 |  | ||||||
|         std::vector<ExPolygons>& oslices = po.m_model_slices; |  | ||||||
| 
 |  | ||||||
|         // If everything went well this code should not run at all, but
 |  | ||||||
|         // let's be robust...
 |  | ||||||
|         // assert(levelids.size() == oslices.size());
 |  | ||||||
|         if(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
 |  | ||||||
| 
 |  | ||||||
|             BOOST_LOG_TRIVIAL(warning) |  | ||||||
|                     << "Height level mismatch at rasterization!\n"; |  | ||||||
| 
 |  | ||||||
|             LevelID lastlvl = po.m_level_ids.back(); |  | ||||||
|             while(po.m_level_ids.size() < oslices.size()) { |  | ||||||
|                 lastlvl += slh; |  | ||||||
|                 po.m_level_ids.emplace_back(lastlvl); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         for(size_t i = 0; i < oslices.size(); ++i) { |  | ||||||
|             LevelID h = po.m_level_ids[i]; |  | ||||||
| 
 |  | ||||||
|             float fh = float(double(h) * SCALING_FACTOR); |  | ||||||
| 
 |  | ||||||
|             // now for the public slice index:
 |  | ||||||
|             SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh]; |  | ||||||
|             // There should be only one slice layer for each print object
 |  | ||||||
|             assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE); |  | ||||||
|             sr.model_slices_idx = i; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(po.m_supportdata) { // deal with the support slices if present
 |  | ||||||
|             std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices; |  | ||||||
|             po.m_supportdata->level_ids.clear(); |  | ||||||
|             po.m_supportdata->level_ids.reserve(sslices.size()); |  | ||||||
| 
 |  | ||||||
|             for(int i = 0; i < int(sslices.size()); ++i) { |  | ||||||
|                 LevelID h = sminZ + sih + i * slh; |  | ||||||
|                 po.m_supportdata->level_ids.emplace_back(h); |  | ||||||
| 
 |  | ||||||
|                 float fh = float(double(h) * SCALING_FACTOR); |  | ||||||
| 
 |  | ||||||
|                 SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh]; |  | ||||||
|                 assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE); |  | ||||||
|                 sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
 |         // Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
 | ||||||
|         report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); |         report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW); | ||||||
|     }; |     }; | ||||||
|  | @ -923,30 +903,18 @@ void SLAPrint::process() | ||||||
|         m_printer_input.clear(); |         m_printer_input.clear(); | ||||||
| 
 | 
 | ||||||
|         for(SLAPrintObject * o : m_objects) { |         for(SLAPrintObject * o : m_objects) { | ||||||
|             auto& po = *o; |             LevelID gndlvl = o->get_slice_index().front().key(); | ||||||
|             std::vector<ExPolygons>& oslices = po.m_model_slices; |             for(auto& slicerecord : o->get_slice_index()) { | ||||||
|  |                 auto& lyrs = m_printer_input[slicerecord.key() - gndlvl]; | ||||||
| 
 | 
 | ||||||
|             // We need to adjust the min Z level of the slices to be zero
 |                 const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel); | ||||||
|             LevelID smfirst = |                 const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport); | ||||||
|                     po.m_supportdata && !po.m_supportdata->level_ids.empty() ? |  | ||||||
|                         po.m_supportdata->level_ids.front() : 0; |  | ||||||
|             LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front(); |  | ||||||
|             LevelID gndlvl = -(std::min(smfirst, mfirst)); |  | ||||||
| 
 | 
 | ||||||
|             // now merge this object's support and object slices with the rest
 |                 if(!objslices.empty()) | ||||||
|             // of the print object slices
 |                     lyrs.emplace_back(objslices, o->instances()); | ||||||
| 
 | 
 | ||||||
|             for(size_t i = 0; i < oslices.size(); ++i) { |                 if(!supslices.empty()) | ||||||
|                 auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]]; |                     lyrs.emplace_back(supslices, o->instances()); | ||||||
|                 lyrs.emplace_back(oslices[i], po.m_instances); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if(!po.m_supportdata) continue; |  | ||||||
|             std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices; |  | ||||||
|             for(size_t i = 0; i < sslices.size(); ++i) { |  | ||||||
|                 LayerRefs& lyrs = |  | ||||||
|                        m_printer_input[gndlvl + po.m_supportdata->level_ids[i]]; |  | ||||||
|                 lyrs.emplace_back(sslices[i], po.m_instances); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics() | ||||||
| 
 | 
 | ||||||
|     // find highest object
 |     // find highest object
 | ||||||
|     // Which is a better bet? To compare by max_z or by number of layers in the index?
 |     // Which is a better bet? To compare by max_z or by number of layers in the index?
 | ||||||
|     double max_z = 0.; |     float max_z = 0.; | ||||||
| 	size_t max_layers_cnt = 0; | 	size_t max_layers_cnt = 0; | ||||||
|     size_t highest_obj_idx = 0; |     size_t highest_obj_idx = 0; | ||||||
| 	for (SLAPrintObject *&po : m_objects) { | 	for (SLAPrintObject *&po : m_objects) { | ||||||
|         const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index(); |         const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index(); | ||||||
|         if (! slice_index.empty()) { |         if (! slice_index.empty()) { | ||||||
|             double z = (-- slice_index.end())->first; |             float z = (-- slice_index.end())->slice_level(); | ||||||
|             size_t cnt = slice_index.size(); |             size_t cnt = slice_index.size(); | ||||||
|             //if (z > max_z) {
 |             //if (z > max_z) {
 | ||||||
|             if (cnt > max_layers_cnt) { |             if (cnt > max_layers_cnt) { | ||||||
|  | @ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics() | ||||||
|     int sliced_layer_cnt = 0; |     int sliced_layer_cnt = 0; | ||||||
|     for (const auto& layer : highest_obj_slice_index) |     for (const auto& layer : highest_obj_slice_index) | ||||||
|     { |     { | ||||||
|         const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height; |         const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height; | ||||||
| 
 | 
 | ||||||
|         // Calculation of the consumed material 
 |         // Calculation of the consumed material 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics() | ||||||
| 
 | 
 | ||||||
|         for (SLAPrintObject * po : m_objects) |         for (SLAPrintObject * po : m_objects) | ||||||
|         { |         { | ||||||
|             const SLAPrintObject::SliceRecord *record = nullptr; |             const SLAPrintObject::_SliceRecord *record = nullptr; | ||||||
|             { |             { | ||||||
|                 const SLAPrintObject::SliceIndex& index = po->get_slice_index(); |                 const SLAPrintObject::SliceIndex& index = po->get_slice_index(); | ||||||
|                 auto key = layer.first; |                 auto it = po->search_slice_index(layer.slice_level() - float(EPSILON)); | ||||||
| 				const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON)); |                 if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON)) | ||||||
|                 if (it_key == index.end() || it_key->first > key + EPSILON) |  | ||||||
|                     continue; |                     continue; | ||||||
|                 record = &it_key->second; |                 record = &(*it); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE) |             const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel); | ||||||
|                 append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances())); |             if (!modelslices.empty()) | ||||||
|  |                 append(model_polygons, get_all_polygons(modelslices, po->instances())); | ||||||
| 
 | 
 | ||||||
|             if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE) |             const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport); | ||||||
|                 append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances())); |             if (!supportslices.empty()) | ||||||
|  |                 append(supports_polygons, get_all_polygons(supportslices, po->instances())); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         model_polygons = union_(model_polygons); |         model_polygons = union_(model_polygons); | ||||||
|  | @ -1394,11 +1363,15 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf | ||||||
|     for (const t_config_option_key &opt_key : opt_keys) { |     for (const t_config_option_key &opt_key : opt_keys) { | ||||||
| 		if (   opt_key == "layer_height" | 		if (   opt_key == "layer_height" | ||||||
|             || opt_key == "faded_layers" |             || opt_key == "faded_layers" | ||||||
|  |             || opt_key == "pad_enable" | ||||||
|  |             || opt_key == "pad_wall_thickness" | ||||||
|  |             || opt_key == "supports_enable" | ||||||
|  |             || opt_key == "support_object_elevation" | ||||||
|             || opt_key == "slice_closing_radius") { |             || opt_key == "slice_closing_radius") { | ||||||
| 			steps.emplace_back(slaposObjectSlice); | 			steps.emplace_back(slaposObjectSlice); | ||||||
|         } else if ( |         } else if ( | ||||||
|                opt_key == "supports_enable" | 
 | ||||||
|             || opt_key == "support_points_density_relative" |                opt_key == "support_points_density_relative" | ||||||
|             || opt_key == "support_points_minimal_distance") { |             || opt_key == "support_points_minimal_distance") { | ||||||
|             steps.emplace_back(slaposSupportPoints); |             steps.emplace_back(slaposSupportPoints); | ||||||
| 		} else if ( | 		} else if ( | ||||||
|  | @ -1413,12 +1386,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf | ||||||
|             || opt_key == "support_critical_angle" |             || opt_key == "support_critical_angle" | ||||||
|             || opt_key == "support_max_bridge_length" |             || opt_key == "support_max_bridge_length" | ||||||
|             || opt_key == "support_max_pillar_link_distance" |             || opt_key == "support_max_pillar_link_distance" | ||||||
|             || opt_key == "support_object_elevation") { |             ) { | ||||||
|             steps.emplace_back(slaposSupportTree); |             steps.emplace_back(slaposSupportTree); | ||||||
|         } else if ( |         } else if ( | ||||||
|                opt_key == "pad_enable" |                opt_key == "pad_wall_height" | ||||||
|             || opt_key == "pad_wall_thickness" |  | ||||||
|             || opt_key == "pad_wall_height" |  | ||||||
|             || opt_key == "pad_max_merge_distance" |             || opt_key == "pad_max_merge_distance" | ||||||
|             || opt_key == "pad_wall_slope" |             || opt_key == "pad_wall_slope" | ||||||
|             || opt_key == "pad_edge_radius") { |             || opt_key == "pad_edge_radius") { | ||||||
|  | @ -1474,11 +1445,7 @@ double SLAPrintObject::get_elevation() const { | ||||||
|         // its walls but currently it is half of its thickness. Whatever it
 |         // its walls but currently it is half of its thickness. Whatever it
 | ||||||
|         // will be in the future, we provide the config to the get_pad_elevation
 |         // will be in the future, we provide the config to the get_pad_elevation
 | ||||||
|         // method and we will have the correct value
 |         // method and we will have the correct value
 | ||||||
|         sla::PoolConfig pcfg; |         sla::PoolConfig pcfg = make_pool_config(m_config); | ||||||
|         pcfg.min_wall_height_mm = m_config.pad_wall_height.getFloat(); |  | ||||||
|         pcfg.min_wall_thickness_mm = m_config.pad_wall_thickness.getFloat(); |  | ||||||
|         pcfg.edge_radius_mm = m_config.pad_edge_radius.getFloat(); |  | ||||||
|         pcfg.max_merge_distance_mm = m_config.pad_max_merge_distance.getFloat(); |  | ||||||
|         ret += sla::get_pad_elevation(pcfg); |         ret += sla::get_pad_elevation(pcfg); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1502,6 +1469,7 @@ double SLAPrintObject::get_current_elevation() const | ||||||
| namespace { // dummy empty static containers for return values in some methods
 | namespace { // dummy empty static containers for return values in some methods
 | ||||||
| const std::vector<ExPolygons> EMPTY_SLICES; | const std::vector<ExPolygons> EMPTY_SLICES; | ||||||
| const TriangleMesh EMPTY_MESH; | const TriangleMesh EMPTY_MESH; | ||||||
|  | const ExPolygons EMPTY_SLICE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const | const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const | ||||||
|  | @ -1509,6 +1477,72 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const | ||||||
|     return m_supportdata->support_points; |     return m_supportdata->support_points; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | SLAPrintObject::SliceIndex::iterator | ||||||
|  | SLAPrintObject::search_slice_index(float slice_level) | ||||||
|  | { | ||||||
|  |     _SliceRecord query(0, slice_level, 0); | ||||||
|  |     auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(), | ||||||
|  |                                query, | ||||||
|  |                                [](const _SliceRecord& r1, const _SliceRecord& r2) | ||||||
|  |     { | ||||||
|  |         return r1.slice_level() < r2.slice_level(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return it; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SLAPrintObject::SliceIndex::const_iterator | ||||||
|  | SLAPrintObject::search_slice_index(float slice_level) const | ||||||
|  | { | ||||||
|  |     _SliceRecord query(0, slice_level, 0); | ||||||
|  |     auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(), | ||||||
|  |                                query, | ||||||
|  |                                [](const _SliceRecord& r1, const _SliceRecord& r2) | ||||||
|  |     { | ||||||
|  |         return r1.slice_level() < r2.slice_level(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return it; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SLAPrintObject::SliceIndex::iterator | ||||||
|  | SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key, | ||||||
|  |                                    bool exact) | ||||||
|  | { | ||||||
|  |     _SliceRecord query(key, 0.f, 0.f); | ||||||
|  |     auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(), | ||||||
|  |                                query, | ||||||
|  |                                [](const _SliceRecord& r1, const _SliceRecord& r2) | ||||||
|  |     { | ||||||
|  |         return r1.key() < r2.key(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // Return valid iterator only if the keys really match
 | ||||||
|  |     if(exact && it != m_slice_index.end() && it->key() != key) | ||||||
|  |         it = m_slice_index.end(); | ||||||
|  | 
 | ||||||
|  |     return it; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | SLAPrintObject::SliceIndex::const_iterator | ||||||
|  | SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key, | ||||||
|  |                                    bool exact) const | ||||||
|  | { | ||||||
|  |     _SliceRecord query(key, 0.f, 0.f); | ||||||
|  |     auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(), | ||||||
|  |                                query, | ||||||
|  |                                [](const _SliceRecord& r1, const _SliceRecord& r2) | ||||||
|  |     { | ||||||
|  |         return r1.key() < r2.key(); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // Return valid iterator only if the keys really match
 | ||||||
|  |     if(exact && it != m_slice_index.end() && it->key() != key) | ||||||
|  |         it = m_slice_index.end(); | ||||||
|  | 
 | ||||||
|  |     return it; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const | const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const | ||||||
| { | { | ||||||
|     // assert(is_step_done(slaposSliceSupports));
 |     // assert(is_step_done(slaposSliceSupports));
 | ||||||
|  | @ -1516,7 +1550,30 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const | ||||||
|     return m_supportdata->support_slices; |     return m_supportdata->support_slices; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const SLAPrintObject::SliceIndex &SLAPrintObject::get_slice_index() const | const ExPolygons &SLAPrintObject::get_slices_from_record( | ||||||
|  |         const _SliceRecord &rec, | ||||||
|  |         SliceOrigin o) const | ||||||
|  | { | ||||||
|  |     size_t idx = o == soModel ? rec.get_model_slice_idx() : | ||||||
|  |                                 rec.get_support_slice_idx(); | ||||||
|  | 
 | ||||||
|  |     const std::vector<ExPolygons>& v = o == soModel? get_model_slices() : | ||||||
|  |                                                      get_support_slices(); | ||||||
|  | 
 | ||||||
|  |     if(idx >= v.size()) return EMPTY_SLICE; | ||||||
|  | 
 | ||||||
|  |     return idx >= v.size() ? EMPTY_SLICE : v[idx]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const ExPolygons &SLAPrintObject::get_slices_from_record( | ||||||
|  |         SLAPrintObject::SliceRecordConstIterator it, SliceOrigin o) const | ||||||
|  | { | ||||||
|  |     if(it.is_end()) return EMPTY_SLICE; | ||||||
|  |     return get_slices_from_record(*it, o); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const std::vector<SLAPrintObject::_SliceRecord>& | ||||||
|  | SLAPrintObject::get_slice_index() const | ||||||
| { | { | ||||||
|     // assert(is_step_done(slaposIndexSlices));
 |     // assert(is_step_done(slaposIndexSlices));
 | ||||||
|     return m_slice_index; |     return m_slice_index; | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include "PrintExport.hpp" | #include "PrintExport.hpp" | ||||||
| #include "Point.hpp" | #include "Point.hpp" | ||||||
| #include "MTUtils.hpp" | #include "MTUtils.hpp" | ||||||
|  | #include <iterator> | ||||||
| 
 | 
 | ||||||
| namespace Slic3r { | namespace Slic3r { | ||||||
| 
 | 
 | ||||||
|  | @ -35,12 +36,19 @@ using _SLAPrintObjectBase = | ||||||
| // the printer (rasterizer) in the SLAPrint class.
 | // the printer (rasterizer) in the SLAPrint class.
 | ||||||
| using LevelID = long long; | using LevelID = long long; | ||||||
| 
 | 
 | ||||||
|  | enum SliceOrigin { soSupport, soModel }; | ||||||
|  | 
 | ||||||
| class SLAPrintObject : public _SLAPrintObjectBase | class SLAPrintObject : public _SLAPrintObjectBase | ||||||
| { | { | ||||||
| private: // Prevents erroneous use by other classes.
 | private: // Prevents erroneous use by other classes.
 | ||||||
|     using Inherited = _SLAPrintObjectBase; |     using Inherited = _SLAPrintObjectBase; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|  | 
 | ||||||
|  |     // I refuse to grantee copying (Tamas)
 | ||||||
|  |     SLAPrintObject(const SLAPrintObject&) = delete; | ||||||
|  |     SLAPrintObject& operator=(const SLAPrintObject&) = delete; | ||||||
|  | 
 | ||||||
|     const SLAPrintObjectConfig& config() const { return m_config; } |     const SLAPrintObjectConfig& config() const { return m_config; } | ||||||
|     const Transform3d&          trafo()  const { return m_trafo; } |     const Transform3d&          trafo()  const { return m_trafo; } | ||||||
| 
 | 
 | ||||||
|  | @ -82,40 +90,146 @@ public: | ||||||
|     // pad is not, then without the pad, otherwise the full value is returned.
 |     // pad is not, then without the pad, otherwise the full value is returned.
 | ||||||
|     double get_current_elevation() const; |     double get_current_elevation() const; | ||||||
| 
 | 
 | ||||||
|     // These two methods should be callable on the client side (e.g. UI thread)
 |  | ||||||
|     // when the appropriate steps slaposObjectSlice and slaposSliceSupports
 |  | ||||||
|     // are ready. All the print objects are processed before slapsRasterize so
 |  | ||||||
|     // it is safe to call them during and/or after slapsRasterize.
 |  | ||||||
|     const std::vector<ExPolygons>& get_model_slices() const; |  | ||||||
|     const std::vector<ExPolygons>& get_support_slices() const; |  | ||||||
| 
 |  | ||||||
|     // This method returns the support points of this SLAPrintObject.
 |     // This method returns the support points of this SLAPrintObject.
 | ||||||
|     const std::vector<sla::SupportPoint>& get_support_points() const; |     const std::vector<sla::SupportPoint>& get_support_points() const; | ||||||
| 
 | 
 | ||||||
|  |     // The public Slice record structure. It corresponds to one printable layer.
 | ||||||
|  |     // To get the sliced polygons, use SLAPrintObject::get_slices_from_record
 | ||||||
|  |     class SliceRecord { | ||||||
|  |     public: | ||||||
|  |         using Key = LevelID; | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         Key   m_print_z = 0;      // Top of the layer
 | ||||||
|  |         float m_slice_z = 0.f;    // Exact level of the slice
 | ||||||
|  |         float m_height = 0.f;     // Height of the sliced layer
 | ||||||
|  | 
 | ||||||
|  |     protected: | ||||||
|  |         SliceRecord(Key key, float slicez, float height): | ||||||
|  |             m_print_z(key), m_slice_z(slicez), m_height(height) {} | ||||||
|  | 
 | ||||||
|  |     public: | ||||||
|  | 
 | ||||||
|  |         // The key will be the integer height level of the top of the layer.
 | ||||||
|  |         inline Key key() const { return m_print_z; } | ||||||
|  | 
 | ||||||
|  |         // Returns the exact floating point Z coordinate of the slice
 | ||||||
|  |         inline float slice_level() const { return m_slice_z; } | ||||||
|  | 
 | ||||||
|  |         // Returns the current layer height
 | ||||||
|  |         inline float layer_height() const { return m_height; } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 
 | ||||||
|     // An index record referencing the slices
 |     // An index record referencing the slices
 | ||||||
|     // (get_model_slices(), get_support_slices()) where the keys are the height
 |     // (get_model_slices(), get_support_slices()) where the keys are the height
 | ||||||
|     // levels of the model in scaled-clipper coordinates. The levels correspond
 |     // levels of the model in scaled-clipper coordinates. The levels correspond
 | ||||||
|     // to the z coordinate of the object coordinate system.
 |     // to the z coordinate of the object coordinate system.
 | ||||||
|     struct SliceRecord { |     class _SliceRecord: public SliceRecord { | ||||||
|         using Key = float; |     public: | ||||||
|  |         static const size_t NONE = size_t(-1); // this will be the max limit of size_t
 | ||||||
|  |     private: | ||||||
|  |         size_t m_model_slices_idx = NONE; | ||||||
|  |         size_t m_support_slices_idx = NONE; | ||||||
| 
 | 
 | ||||||
|         using Idx = size_t; |     public: | ||||||
|         static const Idx NONE = Idx(-1); // this will be the max limit of size_t
 |         _SliceRecord(Key key, float slicez, float height): | ||||||
|  |             SliceRecord(key, slicez, height) {} | ||||||
| 
 | 
 | ||||||
|         Idx model_slices_idx = NONE; |         // Methods for setting the indices into the slice vectors.
 | ||||||
|         Idx support_slices_idx = NONE; |         void set_model_slice_idx(size_t id) { m_model_slices_idx = id; } | ||||||
|  |         void set_support_slice_idx(size_t id) { m_support_slices_idx = id; } | ||||||
|  | 
 | ||||||
|  |         inline size_t get_model_slice_idx() const { return m_model_slices_idx; } | ||||||
|  |         inline size_t get_support_slice_idx() const { return m_support_slices_idx; } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     using SliceIndex = std::map<SliceRecord::Key, SliceRecord>; |     // Slice index will be a plain vector sorted by the integer height levels
 | ||||||
|  |     using SliceIndex = std::vector<_SliceRecord>; | ||||||
| 
 | 
 | ||||||
|     // Retrieve the slice index which is readable only after slaposIndexSlices
 |     // Retrieve the slice index which is readable only after slaposIndexSlices
 | ||||||
|     // is done.
 |     // is done.
 | ||||||
|     const SliceIndex& get_slice_index() const; |     const SliceIndex& get_slice_index() const; | ||||||
| 
 | 
 | ||||||
|     // I refuse to grantee copying (Tamas)
 |     // Search slice index for the closest slice to the given level
 | ||||||
|     SLAPrintObject(const SLAPrintObject&) = delete; |     SliceIndex::iterator search_slice_index(float slice_level); | ||||||
|     SLAPrintObject& operator=(const SLAPrintObject&) = delete; |     SliceIndex::const_iterator search_slice_index(float slice_level) const; | ||||||
| 
 | 
 | ||||||
|  |     // Search the slice index for a particular level in integer coordinates.
 | ||||||
|  |     // If no such layer is present, it will return m_slice_index.end()
 | ||||||
|  |     // This behavior can be suppressed by the second parameter. If it is true
 | ||||||
|  |     // the method will return the closest (non-equal) record
 | ||||||
|  |     SliceIndex::iterator search_slice_index(_SliceRecord::Key key, bool exact = false); | ||||||
|  |     SliceIndex::const_iterator search_slice_index(_SliceRecord::Key key, bool = false) const; | ||||||
|  | 
 | ||||||
|  |     const std::vector<ExPolygons>& get_model_slices() const; | ||||||
|  |     const std::vector<ExPolygons>& get_support_slices() const; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 
 | ||||||
|  |     // Should work as a polymorphic bidirectional iterator to the slice records
 | ||||||
|  |     using SliceRecordConstIterator = | ||||||
|  |         IndexBasedIterator<const SliceIndex, const _SliceRecord>; | ||||||
|  | 
 | ||||||
|  |     // /////////////////////////////////////////////////////////////////////////
 | ||||||
|  |     //
 | ||||||
|  |     // These two methods should be callable on the client side (e.g. UI thread)
 | ||||||
|  |     // when the appropriate steps slaposObjectSlice and slaposSliceSupports
 | ||||||
|  |     // are ready. All the print objects are processed before slapsRasterize so
 | ||||||
|  |     // it is safe to call them during and/or after slapsRasterize.
 | ||||||
|  |     //
 | ||||||
|  |     // /////////////////////////////////////////////////////////////////////////
 | ||||||
|  | 
 | ||||||
|  |     // Get the slice records from a range of slice levels (inclusive). Floating
 | ||||||
|  |     // point keys are the levels where the model was sliced with the mesh
 | ||||||
|  |     // slicer. Integral keys are the keys of the slice records, which
 | ||||||
|  |     // correspond to the top of each layer.. The end() method of the returned
 | ||||||
|  |     // range points *after* the last valid element. This is for being
 | ||||||
|  |     // consistent with std and makeing range based for loops work. use
 | ||||||
|  |     // std::prev(range.end()) or --range.end() to get the last element.
 | ||||||
|  |     template<class Key> Range<SliceRecordConstIterator> | ||||||
|  |     get_slice_records(Key from, Key to = std::numeric_limits<Key>::max()) const | ||||||
|  |     { | ||||||
|  |         SliceIndex::const_iterator it_from, it_to; | ||||||
|  |         if(std::is_integral<Key>::value) { | ||||||
|  |             it_from = search_slice_index(SliceRecord::Key(from)); | ||||||
|  |             it_to   = search_slice_index(SliceRecord::Key(to)); | ||||||
|  |         } else if(std::is_floating_point<Key>::value) { | ||||||
|  |             it_from = search_slice_index(float(from)); | ||||||
|  |             it_to   = search_slice_index(float(to)); | ||||||
|  |         } else return { | ||||||
|  |             SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ), | ||||||
|  |             SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         auto start = m_slice_index.begin(); | ||||||
|  | 
 | ||||||
|  |         size_t bidx = it_from == m_slice_index.end() ? _SliceRecord::NONE : | ||||||
|  |                                                         size_t(it_from - start); | ||||||
|  | 
 | ||||||
|  |         size_t eidx = it_to   == m_slice_index.end() ? _SliceRecord::NONE : | ||||||
|  |                                                        size_t(it_to - start) + 1; | ||||||
|  | 
 | ||||||
|  |         return { | ||||||
|  |             SliceRecordConstIterator(m_slice_index, bidx), | ||||||
|  |             SliceRecordConstIterator(m_slice_index, eidx), | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Get all the slice records as a range.
 | ||||||
|  |     inline Range<SliceRecordConstIterator> get_slice_records() const { | ||||||
|  |         return { | ||||||
|  |             SliceRecordConstIterator(m_slice_index, 0), | ||||||
|  |             SliceRecordConstIterator(m_slice_index, m_slice_index.size()) | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const ExPolygons& get_slices_from_record(SliceRecordConstIterator it, | ||||||
|  |                                              SliceOrigin o) const; | ||||||
|  | 
 | ||||||
|  |     const ExPolygons& get_slices_from_record(const _SliceRecord& rec, | ||||||
|  |                                              SliceOrigin o) const; | ||||||
| protected: | protected: | ||||||
|     // to be called from SLAPrint only.
 |     // to be called from SLAPrint only.
 | ||||||
|     friend class SLAPrint; |     friend class SLAPrint; | ||||||
|  | @ -145,8 +259,10 @@ protected: | ||||||
| private: | private: | ||||||
|     // Object specific configuration, pulled from the configuration layer.
 |     // Object specific configuration, pulled from the configuration layer.
 | ||||||
|     SLAPrintObjectConfig                    m_config; |     SLAPrintObjectConfig                    m_config; | ||||||
|  | 
 | ||||||
|     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
 |     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
 | ||||||
|     Transform3d                             m_trafo = Transform3d::Identity(); |     Transform3d                             m_trafo = Transform3d::Identity(); | ||||||
|  | 
 | ||||||
|     std::vector<Instance> 					m_instances; |     std::vector<Instance> 					m_instances; | ||||||
| 
 | 
 | ||||||
|     // Individual 2d slice polygons from lower z to higher z levels
 |     // Individual 2d slice polygons from lower z to higher z levels
 | ||||||
|  | @ -154,11 +270,9 @@ private: | ||||||
| 
 | 
 | ||||||
|     // Exact (float) height levels mapped to the slices. Each record contains
 |     // Exact (float) height levels mapped to the slices. Each record contains
 | ||||||
|     // the index to the model and the support slice vectors.
 |     // the index to the model and the support slice vectors.
 | ||||||
|     SliceIndex                              m_slice_index; |     std::vector<_SliceRecord>               m_slice_index; | ||||||
| 
 | 
 | ||||||
|     // The height levels corrected and scaled up in integer values. This will
 |     std::vector<float>                      m_model_height_levels; | ||||||
|     // be used at rasterization.
 |  | ||||||
|     std::vector<LevelID>                    m_level_ids; |  | ||||||
| 
 | 
 | ||||||
|     // Caching the transformed (m_trafo) raw mesh of the object
 |     // Caching the transformed (m_trafo) raw mesh of the object
 | ||||||
|     mutable CachedObject<TriangleMesh>      m_transformed_rmesh; |     mutable CachedObject<TriangleMesh>      m_transformed_rmesh; | ||||||
|  | @ -236,6 +350,11 @@ public: | ||||||
|     } |     } | ||||||
|     const PrintObjects& objects() const { return m_objects; } |     const PrintObjects& objects() const { return m_objects; } | ||||||
| 
 | 
 | ||||||
|  |     const SLAPrintConfig&     print_config() const { return m_print_config; } | ||||||
|  |     const SLAPrinterConfig&   printer_config() const { return m_printer_config; } | ||||||
|  |     const SLAMaterialConfig&  material_config() const { return m_material_config; } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	std::string         output_filename() const override; | 	std::string         output_filename() const override; | ||||||
| 
 | 
 | ||||||
|     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; } |     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; } | ||||||
|  | @ -249,11 +368,6 @@ private: | ||||||
|     // Invalidate steps based on a set of parameters changed.
 |     // Invalidate steps based on a set of parameters changed.
 | ||||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); |     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||||
| 
 | 
 | ||||||
|     std::vector<float> calculate_heights(const BoundingBoxf3& bb, |  | ||||||
|                                          float elevation, |  | ||||||
|                                          float initial_layer_height, |  | ||||||
|                                          float layer_height) const; |  | ||||||
| 
 |  | ||||||
|     void fill_statistics(); |     void fill_statistics(); | ||||||
| 
 | 
 | ||||||
|     SLAPrintConfig                  m_print_config; |     SLAPrintConfig                  m_print_config; | ||||||
|  |  | ||||||
|  | @ -540,7 +540,10 @@ void Choice::BUILD() { | ||||||
| 	else{ | 	else{ | ||||||
| 		for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) { | 		for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) { | ||||||
| 			const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
 | 			const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
 | ||||||
|             temp->Append(str, create_scaled_bitmap("empty_icon.png")); | 			//FIXME Vojtech: Why is the single column empty icon necessary? It is a workaround of some kind, but what for?
 | ||||||
|  | 			// Please document such workarounds by comments!
 | ||||||
|  |             // temp->Append(str, create_scaled_bitmap("empty_icon.png"));
 | ||||||
|  |             temp->Append(str, wxNullBitmap); | ||||||
| 		} | 		} | ||||||
| 		set_selection(); | 		set_selection(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2293,11 +2293,13 @@ int GLCanvas3D::check_volumes_outside_state() const | ||||||
|     return (int)state; |     return (int)state; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible) | void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx) | ||||||
| { | { | ||||||
|     for (GLVolume* vol : m_volumes.volumes) { |     for (GLVolume* vol : m_volumes.volumes) { | ||||||
|         if (vol->composite_id.volume_id < 0) |         if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) | ||||||
|              vol->is_active = visible; |         && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx) | ||||||
|  |         && vol->composite_id.volume_id < 0) | ||||||
|  |             vol->is_active = visible; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     m_render_sla_auxiliaries = visible; |     m_render_sla_auxiliaries = visible; | ||||||
|  | @ -2313,7 +2315,7 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (visible && !mo) |     if (visible && !mo) | ||||||
|         toggle_sla_auxiliaries_visibility(true); |         toggle_sla_auxiliaries_visibility(true, mo, instance_idx); | ||||||
| 
 | 
 | ||||||
|     if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1)) |     if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1)) | ||||||
|         _set_warning_texture(WarningTexture::SomethingNotShown, true); |         _set_warning_texture(WarningTexture::SomethingNotShown, true); | ||||||
|  | @ -4971,24 +4973,20 @@ void GLCanvas3D::_render_sla_slices() const | ||||||
|     { |     { | ||||||
|         const SLAPrintObject* obj = print_objects[i]; |         const SLAPrintObject* obj = print_objects[i]; | ||||||
| 
 | 
 | ||||||
|         double shift_z = obj->get_current_elevation(); |  | ||||||
|         double min_z = clip_min_z - shift_z; |  | ||||||
|         double max_z = clip_max_z - shift_z; |  | ||||||
| 
 |  | ||||||
|         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); |         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i); | ||||||
|         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top    = m_sla_caps[1].triangles.find(i); |         SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top    = m_sla_caps[1].triangles.find(i); | ||||||
|         { |         { | ||||||
| 			if (it_caps_bottom == m_sla_caps[0].triangles.end()) | 			if (it_caps_bottom == m_sla_caps[0].triangles.end()) | ||||||
| 				it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; | 				it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; | ||||||
|             if (! m_sla_caps[0].matches(min_z)) { |             if (! m_sla_caps[0].matches(clip_min_z)) { | ||||||
| 				m_sla_caps[0].z = min_z; | 				m_sla_caps[0].z = clip_min_z; | ||||||
|                 it_caps_bottom->second.object.clear(); |                 it_caps_bottom->second.object.clear(); | ||||||
|                 it_caps_bottom->second.supports.clear(); |                 it_caps_bottom->second.supports.clear(); | ||||||
|             } |             } | ||||||
|             if (it_caps_top == m_sla_caps[1].triangles.end()) |             if (it_caps_top == m_sla_caps[1].triangles.end()) | ||||||
| 				it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; | 				it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; | ||||||
|             if (! m_sla_caps[1].matches(max_z)) { |             if (! m_sla_caps[1].matches(clip_max_z)) { | ||||||
| 				m_sla_caps[1].z = max_z; | 				m_sla_caps[1].z = clip_max_z; | ||||||
|                 it_caps_top->second.object.clear(); |                 it_caps_top->second.object.clear(); | ||||||
|                 it_caps_top->second.supports.clear(); |                 it_caps_top->second.supports.clear(); | ||||||
|             } |             } | ||||||
|  | @ -5008,36 +5006,39 @@ void GLCanvas3D::_render_sla_slices() const | ||||||
|         std::vector<InstanceTransform> instance_transforms; |         std::vector<InstanceTransform> instance_transforms; | ||||||
|         for (const SLAPrintObject::Instance& inst : instances) |         for (const SLAPrintObject::Instance& inst : instances) | ||||||
|         { |         { | ||||||
|             instance_transforms.push_back({ to_3d(unscale(inst.shift), shift_z), Geometry::rad2deg(inst.rotation) }); | 			instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices)) |         if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices)) | ||||||
|         { |         { | ||||||
|             const std::vector<ExPolygons>& model_slices = obj->get_model_slices(); |             double initial_layer_height = print->material_config().initial_layer_height.value; | ||||||
|             const std::vector<ExPolygons>& support_slices = obj->get_support_slices(); |             LevelID key_zero = obj->get_slice_records().begin()->key(); | ||||||
|  | 			LevelID key_low  = LevelID((clip_min_z - initial_layer_height) / SCALING_FACTOR) + key_zero; | ||||||
|  | 			LevelID key_high = LevelID((clip_max_z - initial_layer_height) / SCALING_FACTOR) + key_zero; | ||||||
|  | 			auto slice_range = obj->get_slice_records(key_low - LevelID(SCALED_EPSILON), key_high - LevelID(SCALED_EPSILON)); | ||||||
|  |             auto it_low  = slice_range.begin(); | ||||||
|  |             auto it_high = std::prev(slice_range.end()); | ||||||
|      |      | ||||||
|             const SLAPrintObject::SliceIndex& index = obj->get_slice_index(); |             if (! it_low.is_end() && it_low->key() < key_low + LevelID(SCALED_EPSILON)) { | ||||||
|             SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; }); |                 const ExPolygons& obj_bottom = obj->get_slices_from_record(it_low, soModel); | ||||||
|             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; }); |                 const ExPolygons& sup_bottom = obj->get_slices_from_record(it_low, soSupport); | ||||||
| 
 |  | ||||||
|             if (it_min_z != index.end()) |  | ||||||
|             { |  | ||||||
|                 // calculate model bottom cap
 |                 // calculate model bottom cap
 | ||||||
|                 if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size())) |                 if (bottom_obj_triangles.empty() && !obj_bottom.empty()) | ||||||
|                     bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true); |                     bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true); | ||||||
|                 // calculate support bottom cap
 |                 // calculate support bottom cap
 | ||||||
|                 if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size())) |                 if (bottom_sup_triangles.empty() && !sup_bottom.empty()) | ||||||
|                     bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true); |                     bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z, true); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (it_max_z != index.end()) |             if (! it_high.is_end() && it_high->key() < key_high + LevelID(SCALED_EPSILON)) { | ||||||
|             { |                 const ExPolygons& obj_top = obj->get_slices_from_record(it_high, soModel); | ||||||
|  |                 const ExPolygons& sup_top = obj->get_slices_from_record(it_high, soSupport); | ||||||
|                 // calculate model top cap
 |                 // calculate model top cap
 | ||||||
|                 if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size())) |                 if (top_obj_triangles.empty() && !obj_top.empty()) | ||||||
|                     top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false); |                     top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false); | ||||||
|                 // calculate support top cap
 |                 // calculate support top cap
 | ||||||
|                 if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size())) |                 if (top_sup_triangles.empty() && !sup_top.empty()) | ||||||
| 					top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false); |                     top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z, false); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -584,6 +584,9 @@ private: | ||||||
|     bool m_regenerate_volumes; |     bool m_regenerate_volumes; | ||||||
|     bool m_moving; |     bool m_moving; | ||||||
|     bool m_tab_down; |     bool m_tab_down; | ||||||
|  | 
 | ||||||
|  |     // Following variable is obsolete and it should be safe to remove it.
 | ||||||
|  |     // I just don't want to do it now before a release (Lukas Matena 24.3.2019)
 | ||||||
|     bool m_render_sla_auxiliaries; |     bool m_render_sla_auxiliaries; | ||||||
| 
 | 
 | ||||||
|     std::string m_color_by; |     std::string m_color_by; | ||||||
|  | @ -610,7 +613,7 @@ public: | ||||||
|     void reset_volumes(); |     void reset_volumes(); | ||||||
|     int check_volumes_outside_state() const; |     int check_volumes_outside_state() const; | ||||||
| 
 | 
 | ||||||
|     void toggle_sla_auxiliaries_visibility(bool visible); |     void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); | ||||||
|     void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); |     void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); | ||||||
| 
 | 
 | ||||||
|     void set_config(const DynamicPrintConfig* config); |     void set_config(const DynamicPrintConfig* config); | ||||||
|  |  | ||||||
|  | @ -157,7 +157,6 @@ GLToolbar::GLToolbar(GLToolbar::EType type) | ||||||
| #if ENABLE_SVG_ICONS | #if ENABLE_SVG_ICONS | ||||||
|     , m_icons_texture_dirty(true) |     , m_icons_texture_dirty(true) | ||||||
| #endif // ENABLE_SVG_ICONS
 | #endif // ENABLE_SVG_ICONS
 | ||||||
|     , m_mouse_capture({ false, false, false, nullptr }) |  | ||||||
|     , m_tooltip("") |     , m_tooltip("") | ||||||
| { | { | ||||||
| } | } | ||||||
|  | @ -410,6 +409,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | ||||||
|     bool processed = false; |     bool processed = false; | ||||||
| 
 | 
 | ||||||
|     // mouse anywhere
 |     // mouse anywhere
 | ||||||
|  |     if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr)) | ||||||
|  |     { | ||||||
|  |         if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())) | ||||||
|  |             // prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
 | ||||||
|  |             // as when switching between views
 | ||||||
|  |             processed = true; | ||||||
|  | 
 | ||||||
|  |         m_mouse_capture.reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (evt.Moving()) |     if (evt.Moving()) | ||||||
|         m_tooltip = update_hover_state(mouse_pos, parent); |         m_tooltip = update_hover_state(mouse_pos, parent); | ||||||
|     else if (evt.LeftUp()) |     else if (evt.LeftUp()) | ||||||
|  | @ -418,17 +427,9 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | ||||||
|         m_mouse_capture.middle = false; |         m_mouse_capture.middle = false; | ||||||
|     else if (evt.RightUp()) |     else if (evt.RightUp()) | ||||||
|         m_mouse_capture.right = false; |         m_mouse_capture.right = false; | ||||||
|     else if (m_mouse_capture.any()) |     else if (evt.Dragging() && m_mouse_capture.any()) | ||||||
|     { |         // if the button down was done on this toolbar, prevent from dragging into the scene
 | ||||||
|         if (evt.Dragging()) |         processed = true; | ||||||
|             processed = true; |  | ||||||
|         else if (evt.Entering() && (m_mouse_capture.parent == &parent)) |  | ||||||
|             // Resets the mouse capture state to avoid setting the dragging event as processed when, for example,
 |  | ||||||
|             // the item action opens a modal dialog
 |  | ||||||
|             // Keeps the mouse capture state if the entering event happens on different parent from the one
 |  | ||||||
|             // who received the button down event, to prevent, for example, dragging when switching between scene views 
 |  | ||||||
|             m_mouse_capture.reset(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     int item_id = contains_mouse(mouse_pos, parent); |     int item_id = contains_mouse(mouse_pos, parent); | ||||||
|     if (item_id == -1) |     if (item_id == -1) | ||||||
|  |  | ||||||
|  | @ -238,6 +238,8 @@ private: | ||||||
|         bool right; |         bool right; | ||||||
|         GLCanvas3D* parent; |         GLCanvas3D* parent; | ||||||
| 
 | 
 | ||||||
|  |         MouseCapture() { reset(); } | ||||||
|  | 
 | ||||||
|         bool any() const { return left || middle || right; } |         bool any() const { return left || middle || right; } | ||||||
|         void reset() { left = middle = right = false; parent = nullptr; } |         void reset() { left = middle = right = false; parent = nullptr; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ | ||||||
| 
 | 
 | ||||||
| #include "I18N.hpp" | #include "I18N.hpp" | ||||||
| 
 | 
 | ||||||
|  | #include <wx/wupdlock.h> | ||||||
|  | 
 | ||||||
| namespace Slic3r | namespace Slic3r | ||||||
| { | { | ||||||
| namespace GUI | namespace GUI | ||||||
|  | @ -40,7 +42,7 @@ void OG_Settings::Hide() | ||||||
| void OG_Settings::UpdateAndShow(const bool show) | void OG_Settings::UpdateAndShow(const bool show) | ||||||
| { | { | ||||||
|     Show(show); |     Show(show); | ||||||
| //     m_parent->Layout();
 | //    m_parent->Layout();
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| wxSizer* OG_Settings::get_sizer() | wxSizer* OG_Settings::get_sizer() | ||||||
|  | @ -84,6 +86,7 @@ void ObjectSettings::update_settings_list() | ||||||
| 			btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { | 			btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { | ||||||
| 				config->erase(opt_key); | 				config->erase(opt_key); | ||||||
|                 wxTheApp->CallAfter([this]() {  |                 wxTheApp->CallAfter([this]() {  | ||||||
|  |                     wxWindowUpdateLocker noUpdates(m_parent); | ||||||
|                     update_settings_list();  |                     update_settings_list();  | ||||||
|                     m_parent->Layout();  |                     m_parent->Layout();  | ||||||
|                 }); |                 }); | ||||||
|  | @ -119,7 +122,7 @@ void ObjectSettings::update_settings_list() | ||||||
|                 if (cat.second.size() == 1 && cat.second[0] == "extruder") |                 if (cat.second.size() == 1 && cat.second[0] == "extruder") | ||||||
|                     continue; |                     continue; | ||||||
| 
 | 
 | ||||||
|                 auto optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, cat.first, config, false, extra_column); |                 auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), cat.first, config, false, extra_column); | ||||||
|                 optgroup->label_width = 15 * wxGetApp().em_unit();//150;
 |                 optgroup->label_width = 15 * wxGetApp().em_unit();//150;
 | ||||||
|                 optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
 |                 optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -769,19 +769,17 @@ void Preview::load_print_as_sla() | ||||||
|     unsigned int n_layers = 0; |     unsigned int n_layers = 0; | ||||||
|     const SLAPrint* print = m_process->sla_print(); |     const SLAPrint* print = m_process->sla_print(); | ||||||
| 
 | 
 | ||||||
|     std::set<double> zs; |     std::vector<double> zs; | ||||||
|  |     double initial_layer_height = print->material_config().initial_layer_height.value; | ||||||
|     for (const SLAPrintObject* obj : print->objects()) |     for (const SLAPrintObject* obj : print->objects()) | ||||||
|     { |  | ||||||
|         double shift_z = obj->get_current_elevation(); |  | ||||||
|         if (obj->is_step_done(slaposIndexSlices)) |         if (obj->is_step_done(slaposIndexSlices)) | ||||||
|         { |         { | ||||||
|             const SLAPrintObject::SliceIndex& index = obj->get_slice_index(); |             auto slicerecords = obj->get_slice_records(); | ||||||
|             for (const SLAPrintObject::SliceIndex::value_type& id : index) |             auto low_coord = slicerecords.begin()->key(); | ||||||
|             { |             for (auto& rec : slicerecords) | ||||||
|                 zs.insert(shift_z + id.first); |                 zs.emplace_back(initial_layer_height + (rec.key() - low_coord) * SCALING_FACTOR); | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     sort_remove_duplicates(zs); | ||||||
| 
 | 
 | ||||||
|     n_layers = (unsigned int)zs.size(); |     n_layers = (unsigned int)zs.size(); | ||||||
|     if (n_layers == 0) |     if (n_layers == 0) | ||||||
|  | @ -796,11 +794,7 @@ void Preview::load_print_as_sla() | ||||||
|         show_hide_ui_elements("none"); |         show_hide_ui_elements("none"); | ||||||
| 
 | 
 | ||||||
|         if (n_layers > 0) |         if (n_layers > 0) | ||||||
|         { |             update_sliders(zs); | ||||||
|             std::vector<double> layer_zs; |  | ||||||
|             std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs)); |  | ||||||
|             update_sliders(layer_zs); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         m_loaded = true; |         m_loaded = true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -666,7 +666,7 @@ RENDER_AGAIN: | ||||||
|     m_imgui->end(); |     m_imgui->end(); | ||||||
| 
 | 
 | ||||||
|     if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
 |     if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
 | ||||||
|         m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode); |         m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode, m_model_object, m_active_instance); | ||||||
|         force_refresh = true; |         force_refresh = true; | ||||||
|     } |     } | ||||||
|     m_old_editing_state = m_editing_mode; |     m_old_editing_state = m_editing_mode; | ||||||
|  |  | ||||||
|  | @ -327,8 +327,7 @@ void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type) | ||||||
| 
 | 
 | ||||||
| void PresetComboBox::check_selection() | void PresetComboBox::check_selection() | ||||||
| { | { | ||||||
|     if (this->last_selected != GetSelection()) |     this->last_selected = GetSelection(); | ||||||
|         this->last_selected = GetSelection(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Frequently changed parameters
 | // Frequently changed parameters
 | ||||||
|  | @ -829,10 +828,7 @@ void Sidebar::update_presets(Preset::Type preset_type) | ||||||
|             preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); |             preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material); | ||||||
|         } |         } | ||||||
| 		// Update the printer choosers, update the dirty flags.
 | 		// Update the printer choosers, update the dirty flags.
 | ||||||
|         auto prev_selection = p->combo_printer->GetSelection(); |  | ||||||
| 		preset_bundle.printers.update_platter_ui(p->combo_printer); | 		preset_bundle.printers.update_platter_ui(p->combo_printer); | ||||||
|         if (prev_selection != p->combo_printer->GetSelection()) |  | ||||||
|             p->combo_printer->check_selection(); |  | ||||||
| 		// Update the filament choosers to only contain the compatible presets, update the color preview,
 | 		// Update the filament choosers to only contain the compatible presets, update the color preview,
 | ||||||
| 		// update the dirty flags.
 | 		// update the dirty flags.
 | ||||||
|         if (print_tech == ptFFF) { |         if (print_tech == ptFFF) { | ||||||
|  | @ -1717,7 +1713,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | ||||||
|             object->center_around_origin(); |             object->center_around_origin(); | ||||||
|             new_instances.emplace_back(object->add_instance()); |             new_instances.emplace_back(object->add_instance()); | ||||||
| #else /* AUTOPLACEMENT_ON_LOAD */ | #else /* AUTOPLACEMENT_ON_LOAD */ | ||||||
|             // if object has no defined position(s) we need to rearrange everything after loading               object->center_around_origin();
 |             // if object has no defined position(s) we need to rearrange everything after loading
 | ||||||
|             need_arrange = true; |             need_arrange = true; | ||||||
|              // add a default instance and center object around origin  
 |              // add a default instance and center object around origin  
 | ||||||
|             object->center_around_origin();  // also aligns object to Z = 0 
 |             object->center_around_origin();  // also aligns object to Z = 0 
 | ||||||
|  |  | ||||||
|  | @ -988,6 +988,7 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui) | ||||||
| 
 | 
 | ||||||
| 	ui->SetSelection(selected_preset_item); | 	ui->SetSelection(selected_preset_item); | ||||||
| 	ui->SetToolTip(ui->GetString(selected_preset_item)); | 	ui->SetToolTip(ui->GetString(selected_preset_item)); | ||||||
|  |     ui->check_selection(); | ||||||
| 	ui->Thaw(); | 	ui->Thaw(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,9 +11,10 @@ | ||||||
| #include "slic3r/Utils/Semver.hpp" | #include "slic3r/Utils/Semver.hpp" | ||||||
| 
 | 
 | ||||||
| class wxBitmap; | class wxBitmap; | ||||||
| class wxChoice; |  | ||||||
| class wxBitmapComboBox; | class wxBitmapComboBox; | ||||||
|  | class wxChoice; | ||||||
| class wxItemContainer; | class wxItemContainer; | ||||||
|  | class wxString; | ||||||
| 
 | 
 | ||||||
| namespace Slic3r { | namespace Slic3r { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1529,6 +1529,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr | ||||||
| 	} | 	} | ||||||
| 	ui->SetSelection(selected_preset_item); | 	ui->SetSelection(selected_preset_item); | ||||||
| 	ui->SetToolTip(ui->GetString(selected_preset_item)); | 	ui->SetToolTip(ui->GetString(selected_preset_item)); | ||||||
|  |     ui->check_selection(); | ||||||
|     ui->Thaw(); |     ui->Thaw(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sijmen Schoon
						Sijmen Schoon