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_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 | ||||
| option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" 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. | ||||
| 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**. | ||||
| 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. | ||||
|  |  | |||
|  | @ -60,6 +60,7 @@ if (SLIC3R_GUI) | |||
|     endif() | ||||
| 
 | ||||
|     if (CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||||
|         set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}") | ||||
|         if (SLIC3R_WX_STABLE) | ||||
|             find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl) | ||||
|         else () | ||||
|  |  | |||
|  | @ -175,6 +175,11 @@ struct AMFParserContext | |||
|         bool  mirrory_set; | ||||
|         float mirrorz; | ||||
|         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 { | ||||
|  | @ -644,11 +649,7 @@ void AMFParserContext::endDocument() | |||
|             continue; | ||||
|         } | ||||
|         for (const Instance &instance : object.second.instances) | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|         { | ||||
| #else | ||||
|             if (instance.deltax_set && instance.deltay_set) { | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
|             if (instance.anything_set()) { | ||||
|                 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_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
 | ||||
|  |  | |||
|  | @ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | |||
|     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 PoolConfig& pcfg) const | ||||
| { | ||||
|  |  | |||
|  | @ -181,6 +181,8 @@ public: | |||
|     /// Get the sliced 2d layers of the support geometry.
 | ||||
|     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
 | ||||
|     const TriangleMesh& add_pad(const SliceLayer& baseplate, | ||||
|                                 const PoolConfig& pcfg) const; | ||||
|  |  | |||
|  | @ -30,7 +30,6 @@ public: | |||
|     std::vector<sla::SupportPoint> support_points;     // all the support points (manual/auto)
 | ||||
|     SupportTreePtr   support_tree_ptr;   // the supports
 | ||||
|     SlicedSupports   support_slices;     // sliced supports
 | ||||
|     std::vector<LevelID>    level_ids; | ||||
| 
 | ||||
|     inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {} | ||||
| }; | ||||
|  | @ -567,6 +566,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) { | |||
|     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) { | ||||
|     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)); | ||||
|  | @ -591,25 +602,9 @@ std::string SLAPrint::validate() const | |||
|     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> | ||||
| 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; | ||||
|     p.set_status(st, msg, std::forward<Args>(args)...); | ||||
| } | ||||
|  | @ -620,12 +615,19 @@ void SLAPrint::process() | |||
|     using namespace sla; | ||||
|     using ExPolygon = Slic3r::ExPolygon; | ||||
| 
 | ||||
|     if(m_objects.empty()) return; | ||||
| 
 | ||||
|     // 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
 | ||||
| 
 | ||||
|     // shortcut to initial layer height
 | ||||
|     double ilhd = m_material_config.initial_layer_height.getFloat(); | ||||
|     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 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
 | ||||
|     // be compared with the fff slicing algorithm for verification
 | ||||
|     auto slice_model = [this, ilh](SLAPrintObject& po) { | ||||
|         double lh = po.m_config.layer_height.getFloat(); | ||||
| 
 | ||||
|     auto slice_model = [this, ilhs, lhs, ilh, lh](SLAPrintObject& po) { | ||||
|         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); | ||||
| 
 | ||||
|         // The 1D grid heights
 | ||||
|         std::vector<float> heights = calculate_heights(mesh.bounding_box(), | ||||
|                                                        float(po.get_elevation()), | ||||
|                                                        ilh, float(lh)); | ||||
|         po.m_model_slices.clear(); | ||||
|         slicer.slice(po.m_model_height_levels, | ||||
|                      float(po.config().slice_closing_radius.value), | ||||
|                      &po.m_model_slices, | ||||
|                      [this](){ throw_if_canceled(); }); | ||||
| 
 | ||||
|         auto& layers = po.m_model_slices; layers.clear(); | ||||
| 		slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); }); | ||||
|         auto mit = slindex_it; | ||||
|         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
 | ||||
|     // 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; | ||||
|         po.m_supportdata.reset( | ||||
|                     new SLAPrintObject::SupportData(po.transformed_mesh()) ); | ||||
|  | @ -680,12 +717,7 @@ void SLAPrint::process() | |||
|         if (mo.sla_points_status != sla::PointsStatus::UserModified) { | ||||
| 
 | ||||
|             // calculate heights of slices (slices are calculated already)
 | ||||
|             double lh = po.m_config.layer_height.getFloat(); | ||||
| 
 | ||||
|             std::vector<float> heights = | ||||
|                     calculate_heights(po.transformed_mesh().bounding_box(), | ||||
|                                       float(po.get_elevation()), | ||||
|                                       ilh, float(lh)); | ||||
|             const std::vector<float>& heights = po.m_model_height_levels; | ||||
| 
 | ||||
|             this->throw_if_canceled(); | ||||
|             SLAAutoSupports::Config config; | ||||
|  | @ -831,86 +863,34 @@ void SLAPrint::process() | |||
|     // Slicing the support geometries similarly to the model slicing procedure.
 | ||||
|     // If the pad had been added previously (see step "base_pool" than it will
 | ||||
|     // be part of the slices)
 | ||||
|     auto slice_supports = [ilh](SLAPrintObject& po) { | ||||
|     auto slice_supports = [](SLAPrintObject& po) { | ||||
|         auto& sd = po.m_supportdata; | ||||
| 
 | ||||
|         if(sd) sd->support_slices.clear(); | ||||
| 
 | ||||
|         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
 | ||||
|     // an index where the key is the height level in discrete levels (clipper)
 | ||||
|     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); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) { | ||||
|         // 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); | ||||
|     }; | ||||
|  | @ -923,30 +903,18 @@ void SLAPrint::process() | |||
|         m_printer_input.clear(); | ||||
| 
 | ||||
|         for(SLAPrintObject * o : m_objects) { | ||||
|             auto& po = *o; | ||||
|             std::vector<ExPolygons>& oslices = po.m_model_slices; | ||||
|             LevelID gndlvl = o->get_slice_index().front().key(); | ||||
|             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
 | ||||
|             LevelID smfirst = | ||||
|                     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)); | ||||
|                 const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel); | ||||
|                 const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport); | ||||
| 
 | ||||
|             // now merge this object's support and object slices with the rest
 | ||||
|             // of the print object slices
 | ||||
|                 if(!objslices.empty()) | ||||
|                     lyrs.emplace_back(objslices, o->instances()); | ||||
| 
 | ||||
|             for(size_t i = 0; i < oslices.size(); ++i) { | ||||
|                 auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]]; | ||||
|                 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); | ||||
|                 if(!supslices.empty()) | ||||
|                     lyrs.emplace_back(supslices, o->instances()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics() | |||
| 
 | ||||
|     // find highest object
 | ||||
|     // 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 highest_obj_idx = 0; | ||||
| 	for (SLAPrintObject *&po : m_objects) { | ||||
|         const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index(); | ||||
|         if (! slice_index.empty()) { | ||||
|             double z = (-- slice_index.end())->first; | ||||
|             float z = (-- slice_index.end())->slice_level(); | ||||
|             size_t cnt = slice_index.size(); | ||||
|             //if (z > max_z) {
 | ||||
|             if (cnt > max_layers_cnt) { | ||||
|  | @ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics() | |||
|     int sliced_layer_cnt = 0; | ||||
|     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 
 | ||||
| 
 | ||||
|  | @ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics() | |||
| 
 | ||||
|         for (SLAPrintObject * po : m_objects) | ||||
|         { | ||||
|             const SLAPrintObject::SliceRecord *record = nullptr; | ||||
|             const SLAPrintObject::_SliceRecord *record = nullptr; | ||||
|             { | ||||
|                 const SLAPrintObject::SliceIndex& index = po->get_slice_index(); | ||||
|                 auto key = layer.first; | ||||
| 				const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON)); | ||||
|                 if (it_key == index.end() || it_key->first > key + EPSILON) | ||||
|                 auto it = po->search_slice_index(layer.slice_level() - float(EPSILON)); | ||||
|                 if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON)) | ||||
|                     continue; | ||||
|                 record = &it_key->second; | ||||
|                 record = &(*it); | ||||
|             } | ||||
| 
 | ||||
|             if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE) | ||||
|                 append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances())); | ||||
|              | ||||
|             if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE) | ||||
|                 append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances())); | ||||
|             const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel); | ||||
|             if (!modelslices.empty()) | ||||
|                 append(model_polygons, get_all_polygons(modelslices, po->instances())); | ||||
| 
 | ||||
|             const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport); | ||||
|             if (!supportslices.empty()) | ||||
|                 append(supports_polygons, get_all_polygons(supportslices, po->instances())); | ||||
|         } | ||||
|          | ||||
|         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) { | ||||
| 		if (   opt_key == "layer_height" | ||||
|             || 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") { | ||||
| 			steps.emplace_back(slaposObjectSlice); | ||||
|         } else if ( | ||||
|                opt_key == "supports_enable" | ||||
|             || opt_key == "support_points_density_relative" | ||||
| 
 | ||||
|                opt_key == "support_points_density_relative" | ||||
|             || opt_key == "support_points_minimal_distance") { | ||||
|             steps.emplace_back(slaposSupportPoints); | ||||
| 		} 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_max_bridge_length" | ||||
|             || opt_key == "support_max_pillar_link_distance" | ||||
|             || opt_key == "support_object_elevation") { | ||||
|             ) { | ||||
|             steps.emplace_back(slaposSupportTree); | ||||
|         } else if ( | ||||
|                opt_key == "pad_enable" | ||||
|             || opt_key == "pad_wall_thickness" | ||||
|             || opt_key == "pad_wall_height" | ||||
|                opt_key == "pad_wall_height" | ||||
|             || opt_key == "pad_max_merge_distance" | ||||
|             || opt_key == "pad_wall_slope" | ||||
|             || 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
 | ||||
|         // will be in the future, we provide the config to the get_pad_elevation
 | ||||
|         // method and we will have the correct value
 | ||||
|         sla::PoolConfig pcfg; | ||||
|         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(); | ||||
|         sla::PoolConfig pcfg = make_pool_config(m_config); | ||||
|         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
 | ||||
| const std::vector<ExPolygons> EMPTY_SLICES; | ||||
| const TriangleMesh EMPTY_MESH; | ||||
| const ExPolygons EMPTY_SLICE; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
|     // assert(is_step_done(slaposSliceSupports));
 | ||||
|  | @ -1516,7 +1550,30 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const | |||
|     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));
 | ||||
|     return m_slice_index; | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include "PrintExport.hpp" | ||||
| #include "Point.hpp" | ||||
| #include "MTUtils.hpp" | ||||
| #include <iterator> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -35,12 +36,19 @@ using _SLAPrintObjectBase = | |||
| // the printer (rasterizer) in the SLAPrint class.
 | ||||
| using LevelID = long long; | ||||
| 
 | ||||
| enum SliceOrigin { soSupport, soModel }; | ||||
| 
 | ||||
| class SLAPrintObject : public _SLAPrintObjectBase | ||||
| { | ||||
| private: // Prevents erroneous use by other classes.
 | ||||
|     using Inherited = _SLAPrintObjectBase; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     // I refuse to grantee copying (Tamas)
 | ||||
|     SLAPrintObject(const SLAPrintObject&) = delete; | ||||
|     SLAPrintObject& operator=(const SLAPrintObject&) = delete; | ||||
| 
 | ||||
|     const SLAPrintObjectConfig& config() const { return m_config; } | ||||
|     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.
 | ||||
|     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.
 | ||||
|     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
 | ||||
|     // (get_model_slices(), get_support_slices()) where the keys are the height
 | ||||
|     // levels of the model in scaled-clipper coordinates. The levels correspond
 | ||||
|     // to the z coordinate of the object coordinate system.
 | ||||
|     struct SliceRecord { | ||||
|         using Key = float; | ||||
|     class _SliceRecord: public SliceRecord { | ||||
|     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; | ||||
|         static const Idx NONE = Idx(-1); // this will be the max limit of size_t
 | ||||
|     public: | ||||
|         _SliceRecord(Key key, float slicez, float height): | ||||
|             SliceRecord(key, slicez, height) {} | ||||
| 
 | ||||
|         Idx model_slices_idx = NONE; | ||||
|         Idx support_slices_idx = NONE; | ||||
|         // Methods for setting the indices into the slice vectors.
 | ||||
|         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
 | ||||
|     // is done.
 | ||||
|     const SliceIndex& get_slice_index() const; | ||||
| 
 | ||||
|     // I refuse to grantee copying (Tamas)
 | ||||
|     SLAPrintObject(const SLAPrintObject&) = delete; | ||||
|     SLAPrintObject& operator=(const SLAPrintObject&) = delete; | ||||
|     // Search slice index for the closest slice to the given level
 | ||||
|     SliceIndex::iterator search_slice_index(float slice_level); | ||||
|     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: | ||||
|     // to be called from SLAPrint only.
 | ||||
|     friend class SLAPrint; | ||||
|  | @ -145,8 +259,10 @@ protected: | |||
| private: | ||||
|     // Object specific configuration, pulled from the configuration layer.
 | ||||
|     SLAPrintObjectConfig                    m_config; | ||||
| 
 | ||||
|     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
 | ||||
|     Transform3d                             m_trafo = Transform3d::Identity(); | ||||
| 
 | ||||
|     std::vector<Instance> 					m_instances; | ||||
| 
 | ||||
|     // 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
 | ||||
|     // 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
 | ||||
|     // be used at rasterization.
 | ||||
|     std::vector<LevelID>                    m_level_ids; | ||||
|     std::vector<float>                      m_model_height_levels; | ||||
| 
 | ||||
|     // Caching the transformed (m_trafo) raw mesh of the object
 | ||||
|     mutable CachedObject<TriangleMesh>      m_transformed_rmesh; | ||||
|  | @ -236,6 +350,11 @@ public: | |||
|     } | ||||
|     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; | ||||
| 
 | ||||
|     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; } | ||||
|  | @ -249,11 +368,6 @@ private: | |||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     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(); | ||||
| 
 | ||||
|     SLAPrintConfig                  m_print_config; | ||||
|  |  | |||
|  | @ -540,7 +540,10 @@ void Choice::BUILD() { | |||
| 	else{ | ||||
| 		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;
 | ||||
|             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(); | ||||
| 	} | ||||
|  |  | |||
|  | @ -2293,11 +2293,13 @@ int GLCanvas3D::check_volumes_outside_state() const | |||
|     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) { | ||||
|         if (vol->composite_id.volume_id < 0) | ||||
|              vol->is_active = visible; | ||||
|         if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo) | ||||
|         && (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; | ||||
|  | @ -2313,7 +2315,7 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject | |||
|         } | ||||
|     } | ||||
|     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)) | ||||
|         _set_warning_texture(WarningTexture::SomethingNotShown, true); | ||||
|  | @ -4971,24 +4973,20 @@ void GLCanvas3D::_render_sla_slices() const | |||
|     { | ||||
|         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_top    = m_sla_caps[1].triangles.find(i); | ||||
|         { | ||||
| 			if (it_caps_bottom == m_sla_caps[0].triangles.end()) | ||||
| 				it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first; | ||||
|             if (! m_sla_caps[0].matches(min_z)) { | ||||
| 				m_sla_caps[0].z = min_z; | ||||
|             if (! m_sla_caps[0].matches(clip_min_z)) { | ||||
| 				m_sla_caps[0].z = clip_min_z; | ||||
|                 it_caps_bottom->second.object.clear(); | ||||
|                 it_caps_bottom->second.supports.clear(); | ||||
|             } | ||||
|             if (it_caps_top == m_sla_caps[1].triangles.end()) | ||||
| 				it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first; | ||||
|             if (! m_sla_caps[1].matches(max_z)) { | ||||
| 				m_sla_caps[1].z = max_z; | ||||
|             if (! m_sla_caps[1].matches(clip_max_z)) { | ||||
| 				m_sla_caps[1].z = clip_max_z; | ||||
|                 it_caps_top->second.object.clear(); | ||||
|                 it_caps_top->second.supports.clear(); | ||||
|             } | ||||
|  | @ -5008,36 +5006,39 @@ void GLCanvas3D::_render_sla_slices() const | |||
|         std::vector<InstanceTransform> instance_transforms; | ||||
|         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)) | ||||
|         { | ||||
|             const std::vector<ExPolygons>& model_slices = obj->get_model_slices(); | ||||
|             const std::vector<ExPolygons>& support_slices = obj->get_support_slices(); | ||||
| 
 | ||||
|             const SLAPrintObject::SliceIndex& index = obj->get_slice_index(); | ||||
|             SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; }); | ||||
|             SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; }); | ||||
| 
 | ||||
|             if (it_min_z != index.end()) | ||||
|             { | ||||
|             double initial_layer_height = print->material_config().initial_layer_height.value; | ||||
|             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()); | ||||
|      | ||||
|             if (! it_low.is_end() && it_low->key() < key_low + LevelID(SCALED_EPSILON)) { | ||||
|                 const ExPolygons& obj_bottom = obj->get_slices_from_record(it_low, soModel); | ||||
|                 const ExPolygons& sup_bottom = obj->get_slices_from_record(it_low, soSupport); | ||||
|                 // calculate model bottom cap
 | ||||
|                 if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size())) | ||||
|                     bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true); | ||||
|                 if (bottom_obj_triangles.empty() && !obj_bottom.empty()) | ||||
|                     bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true); | ||||
|                 // calculate support bottom cap
 | ||||
|                 if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size())) | ||||
|                     bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true); | ||||
|                 if (bottom_sup_triangles.empty() && !sup_bottom.empty()) | ||||
|                     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
 | ||||
|                 if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size())) | ||||
|                     top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false); | ||||
|                 if (top_obj_triangles.empty() && !obj_top.empty()) | ||||
|                     top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false); | ||||
|                 // calculate support top cap
 | ||||
|                 if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size())) | ||||
| 					top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false); | ||||
|                 if (top_sup_triangles.empty() && !sup_top.empty()) | ||||
|                     top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z, false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -584,6 +584,9 @@ private: | |||
|     bool m_regenerate_volumes; | ||||
|     bool m_moving; | ||||
|     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; | ||||
| 
 | ||||
|     std::string m_color_by; | ||||
|  | @ -610,7 +613,7 @@ public: | |||
|     void reset_volumes(); | ||||
|     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 set_config(const DynamicPrintConfig* config); | ||||
|  |  | |||
|  | @ -157,7 +157,6 @@ GLToolbar::GLToolbar(GLToolbar::EType type) | |||
| #if ENABLE_SVG_ICONS | ||||
|     , m_icons_texture_dirty(true) | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     , m_mouse_capture({ false, false, false, nullptr }) | ||||
|     , m_tooltip("") | ||||
| { | ||||
| } | ||||
|  | @ -410,6 +409,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | |||
|     bool processed = false; | ||||
| 
 | ||||
|     // 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()) | ||||
|         m_tooltip = update_hover_state(mouse_pos, parent); | ||||
|     else if (evt.LeftUp()) | ||||
|  | @ -418,17 +427,9 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | |||
|         m_mouse_capture.middle = false; | ||||
|     else if (evt.RightUp()) | ||||
|         m_mouse_capture.right = false; | ||||
|     else if (m_mouse_capture.any()) | ||||
|     { | ||||
|         if (evt.Dragging()) | ||||
|             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(); | ||||
|     } | ||||
|     else if (evt.Dragging() && m_mouse_capture.any()) | ||||
|         // if the button down was done on this toolbar, prevent from dragging into the scene
 | ||||
|         processed = true; | ||||
| 
 | ||||
|     int item_id = contains_mouse(mouse_pos, parent); | ||||
|     if (item_id == -1) | ||||
|  |  | |||
|  | @ -238,6 +238,8 @@ private: | |||
|         bool right; | ||||
|         GLCanvas3D* parent; | ||||
| 
 | ||||
|         MouseCapture() { reset(); } | ||||
| 
 | ||||
|         bool any() const { return left || middle || right; } | ||||
|         void reset() { left = middle = right = false; parent = nullptr; } | ||||
|     }; | ||||
|  |  | |||
|  | @ -10,6 +10,8 @@ | |||
| 
 | ||||
| #include "I18N.hpp" | ||||
| 
 | ||||
| #include <wx/wupdlock.h> | ||||
| 
 | ||||
| namespace Slic3r | ||||
| { | ||||
| namespace GUI | ||||
|  | @ -40,7 +42,7 @@ void OG_Settings::Hide() | |||
| void OG_Settings::UpdateAndShow(const bool show) | ||||
| { | ||||
|     Show(show); | ||||
| //     m_parent->Layout();
 | ||||
| //    m_parent->Layout();
 | ||||
| } | ||||
| 
 | ||||
| wxSizer* OG_Settings::get_sizer() | ||||
|  | @ -84,6 +86,7 @@ void ObjectSettings::update_settings_list() | |||
| 			btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { | ||||
| 				config->erase(opt_key); | ||||
|                 wxTheApp->CallAfter([this]() {  | ||||
|                     wxWindowUpdateLocker noUpdates(m_parent); | ||||
|                     update_settings_list();  | ||||
|                     m_parent->Layout();  | ||||
|                 }); | ||||
|  | @ -119,7 +122,7 @@ void ObjectSettings::update_settings_list() | |||
|                 if (cat.second.size() == 1 && cat.second[0] == "extruder") | ||||
|                     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->sidetext_width = 7 * wxGetApp().em_unit();//70;
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -769,19 +769,17 @@ void Preview::load_print_as_sla() | |||
|     unsigned int n_layers = 0; | ||||
|     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()) | ||||
|     { | ||||
|         double shift_z = obj->get_current_elevation(); | ||||
|         if (obj->is_step_done(slaposIndexSlices)) | ||||
|         { | ||||
|             const SLAPrintObject::SliceIndex& index = obj->get_slice_index(); | ||||
|             for (const SLAPrintObject::SliceIndex::value_type& id : index) | ||||
|             { | ||||
|                 zs.insert(shift_z + id.first); | ||||
|             } | ||||
|             auto slicerecords = obj->get_slice_records(); | ||||
|             auto low_coord = slicerecords.begin()->key(); | ||||
|             for (auto& rec : slicerecords) | ||||
|                 zs.emplace_back(initial_layer_height + (rec.key() - low_coord) * SCALING_FACTOR); | ||||
|         } | ||||
|     } | ||||
|     sort_remove_duplicates(zs); | ||||
| 
 | ||||
|     n_layers = (unsigned int)zs.size(); | ||||
|     if (n_layers == 0) | ||||
|  | @ -796,11 +794,7 @@ void Preview::load_print_as_sla() | |||
|         show_hide_ui_elements("none"); | ||||
| 
 | ||||
|         if (n_layers > 0) | ||||
|         { | ||||
|             std::vector<double> layer_zs; | ||||
|             std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs)); | ||||
|             update_sliders(layer_zs); | ||||
|         } | ||||
|             update_sliders(zs); | ||||
| 
 | ||||
|         m_loaded = true; | ||||
|     } | ||||
|  |  | |||
|  | @ -666,7 +666,7 @@ RENDER_AGAIN: | |||
|     m_imgui->end(); | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
|     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() | ||||
| { | ||||
|     if (this->last_selected != GetSelection()) | ||||
|         this->last_selected = GetSelection(); | ||||
|     this->last_selected = GetSelection(); | ||||
| } | ||||
| 
 | ||||
| // 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); | ||||
|         } | ||||
| 		// Update the printer choosers, update the dirty flags.
 | ||||
|         auto prev_selection = p->combo_printer->GetSelection(); | ||||
| 		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 dirty flags.
 | ||||
|         if (print_tech == ptFFF) { | ||||
|  | @ -1717,8 +1713,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | |||
|             object->center_around_origin(); | ||||
|             new_instances.emplace_back(object->add_instance()); | ||||
| #else /* AUTOPLACEMENT_ON_LOAD */ | ||||
|             // if object has no defined position(s) we need to rearrange everything after loading               object->center_around_origin();
 | ||||
|             need_arrange = true;                 | ||||
|             // if object has no defined position(s) we need to rearrange everything after loading
 | ||||
|             need_arrange = true; | ||||
|              // add a default instance and center object around origin  
 | ||||
|             object->center_around_origin();  // also aligns object to Z = 0 
 | ||||
|             ModelInstance* instance = object->add_instance();    | ||||
|  |  | |||
|  | @ -988,6 +988,7 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui) | |||
| 
 | ||||
| 	ui->SetSelection(selected_preset_item); | ||||
| 	ui->SetToolTip(ui->GetString(selected_preset_item)); | ||||
|     ui->check_selection(); | ||||
| 	ui->Thaw(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,9 +11,10 @@ | |||
| #include "slic3r/Utils/Semver.hpp" | ||||
| 
 | ||||
| class wxBitmap; | ||||
| class wxChoice; | ||||
| class wxBitmapComboBox; | ||||
| class wxChoice; | ||||
| class wxItemContainer; | ||||
| class wxString; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  |  | |||
|  | @ -1529,6 +1529,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr | |||
| 	} | ||||
| 	ui->SetSelection(selected_preset_item); | ||||
| 	ui->SetToolTip(ui->GetString(selected_preset_item)); | ||||
|     ui->check_selection(); | ||||
|     ui->Thaw(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sijmen Schoon
						Sijmen Schoon