mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r
This commit is contained in:
		
						commit
						f65eb9afdb
					
				
					 13 changed files with 304 additions and 303 deletions
				
			
		|  | @ -28,8 +28,8 @@ namespace Slic3r { | |||
| 
 | ||||
| //-----------------------------------------------------------
 | ||||
| // legacy code from Clipper documentation
 | ||||
| void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons); | ||||
| void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons); | ||||
| void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons *expolygons); | ||||
| Slic3r::ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree); | ||||
| //-----------------------------------------------------------
 | ||||
| 
 | ||||
| ClipperLib::Path   Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input); | ||||
|  | @ -228,4 +228,4 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons); | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  |  | |||
|  | @ -56,8 +56,18 @@ public: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<class Vector, | ||||
|          class Value = typename Vector::value_type> | ||||
| /// An std compatible random access iterator which uses indices to the source
 | ||||
| /// vector thus resistant to invalidation caused by relocations. It also "knows"
 | ||||
| /// its container. No comparison is neccesary to the container "end()" iterator.
 | ||||
| /// The template can be instantiated with a different value type than that of
 | ||||
| /// the container's but the types must be compatible. E.g. a base class of the
 | ||||
| /// contained objects is compatible.
 | ||||
| ///
 | ||||
| /// For a constant iterator, one can instantiate this template with a value
 | ||||
| /// type preceded with 'const'.
 | ||||
| template<class Vector,  // The container type, must be random access...
 | ||||
|          class Value = typename Vector::value_type // The value type
 | ||||
|          > | ||||
| class IndexBasedIterator { | ||||
|     static const size_t NONE = size_t(-1); | ||||
| 
 | ||||
|  | @ -110,6 +120,8 @@ public: | |||
| 
 | ||||
|     operator difference_type() { return difference_type(m_idx); } | ||||
| 
 | ||||
|     /// Tesing the end of the container... this is not possible with std
 | ||||
|     /// iterators.
 | ||||
|     inline bool is_end() const { return m_idx >= m_index_ref.get().size();} | ||||
| 
 | ||||
|     inline Value & operator*() const { | ||||
|  | @ -122,6 +134,7 @@ public: | |||
|         return &m_index_ref.get().operator[](m_idx); | ||||
|     } | ||||
| 
 | ||||
|     /// If both iterators point past the container, they are equal...
 | ||||
|     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); | ||||
|  | @ -148,17 +161,23 @@ public: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// A very simple range concept implementation with iterator-like objects.
 | ||||
| template<class It> class Range { | ||||
|     It from, to; | ||||
| public: | ||||
| 
 | ||||
|     // The class is ready for range based for loops.
 | ||||
|     It begin() const { return from; } | ||||
|     It end() const { return to; } | ||||
| 
 | ||||
|     // The iterator type can be obtained this way.
 | ||||
|     using Type = It; | ||||
| 
 | ||||
|     Range() = default; | ||||
|     Range(It &&b, It &&e): | ||||
|         from(std::forward<It>(b)), to(std::forward<It>(e)) {} | ||||
| 
 | ||||
|     // Some useful container-like methods...
 | ||||
|     inline size_t size() const { return end() - begin(); } | ||||
|     inline bool empty() const { return size() == 0; } | ||||
| }; | ||||
|  |  | |||
|  | @ -587,6 +587,15 @@ void swapXY(ExPolygon& expoly) { | |||
| std::string SLAPrint::validate() const | ||||
| { | ||||
|     for(SLAPrintObject * po : m_objects) { | ||||
| 
 | ||||
|         const ModelObject *mo = po->model_object(); | ||||
| 
 | ||||
|         if(po->config().supports_enable.getBool() && | ||||
|            mo->sla_points_status == sla::PointsStatus::UserModified && | ||||
|            mo->sla_support_points.empty()) | ||||
|             return L("Cannot proceed without support points! " | ||||
|                      "Add support points or disable support generation."); | ||||
| 
 | ||||
|         sla::SupportConfig cfg = make_support_cfg(po->config()); | ||||
| 
 | ||||
|         double pinhead_width = | ||||
|  | @ -596,7 +605,7 @@ std::string SLAPrint::validate() const | |||
|                 cfg.head_penetration_mm; | ||||
| 
 | ||||
|         if(pinhead_width > cfg.object_elevation_mm) | ||||
|             return L("Elevetion is too low for object."); | ||||
|             return L("Elevation is too low for object."); | ||||
|     } | ||||
| 
 | ||||
|     return ""; | ||||
|  | @ -623,11 +632,8 @@ void SLAPrint::process() | |||
|     // 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); | ||||
|     auto ilhs = coord_t(ilhd / SCALING_FACTOR); | ||||
|     const size_t objcount = m_objects.size(); | ||||
| 
 | ||||
|     const unsigned min_objstatus = 0;   // where the per object operations start
 | ||||
|  | @ -648,27 +654,33 @@ 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, ilhs, lhs, ilh, lh](SLAPrintObject& po) { | ||||
|     auto slice_model = [this, ilhs, ilh](SLAPrintObject& po) { | ||||
|         TriangleMesh mesh = po.transformed_mesh(); | ||||
| 
 | ||||
|         // We need to prepare the slice index...
 | ||||
| 
 | ||||
|         double lhd  = m_objects.front()->m_config.layer_height.getFloat(); | ||||
|         float  lh   = float(lhd); | ||||
|         auto   lhs  = coord_t(lhd  / SCALING_FACTOR); | ||||
| 
 | ||||
|         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); | ||||
|         auto minZs = coord_t(minZ / SCALING_FACTOR); | ||||
|         auto maxZs = coord_t(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) { | ||||
|         for(coord_t 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))); | ||||
|         // Just get the first record that is form the model:
 | ||||
|         auto slindex_it = | ||||
|                 po.closest_slice_record(po.m_slice_index, float(bb3d.min(Z))); | ||||
| 
 | ||||
|         if(slindex_it == po.m_slice_index.end()) | ||||
|             throw std::runtime_error(L("Slicing had to be stopped " | ||||
|  | @ -694,7 +706,7 @@ void SLAPrint::process() | |||
|             id < po.m_model_slices.size() && mit != po.m_slice_index.end(); | ||||
|             id++) | ||||
|         { | ||||
|             mit->set_model_slice_idx(id); ++mit; | ||||
|             mit->set_model_slice_idx(po, id); ++mit; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -716,6 +728,12 @@ void SLAPrint::process() | |||
|         // into the backend cache.
 | ||||
|         if (mo.sla_points_status != sla::PointsStatus::UserModified) { | ||||
| 
 | ||||
|             // Hypotetical use of the slice index:
 | ||||
|             // auto bb = po.transformed_mesh().bounding_box();
 | ||||
|             // auto range = po.get_slice_records(bb.min(Z));
 | ||||
|             // std::vector<float> heights; heights.reserve(range.size());
 | ||||
|             // for(auto& record : range) heights.emplace_back(record.slice_level());
 | ||||
| 
 | ||||
|             // calculate heights of slices (slices are calculated already)
 | ||||
|             const std::vector<float>& heights = po.m_model_height_levels; | ||||
| 
 | ||||
|  | @ -884,7 +902,7 @@ void SLAPrint::process() | |||
|             i < sd->support_slices.size() && i < po.m_slice_index.size(); | ||||
|             ++i) | ||||
|         { | ||||
|             po.m_slice_index[i].set_support_slice_idx(i); | ||||
|             po.m_slice_index[i].set_support_slice_idx(po, i); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -896,31 +914,43 @@ void SLAPrint::process() | |||
|     }; | ||||
| 
 | ||||
|     // Rasterizing the model objects, and their supports
 | ||||
|     auto rasterize = [this, max_objstatus]() { | ||||
|     auto rasterize = [this, max_objstatus, ilhs]() { | ||||
|         if(canceled()) return; | ||||
| 
 | ||||
|         // clear the rasterizer input
 | ||||
|         m_printer_input.clear(); | ||||
| 
 | ||||
|         size_t mx = 0; | ||||
|         for(SLAPrintObject * o : m_objects) { | ||||
|             LevelID gndlvl = o->get_slice_index().front().key(); | ||||
|             for(auto& slicerecord : o->get_slice_index()) { | ||||
|                 auto& lyrs = m_printer_input[slicerecord.key() - gndlvl]; | ||||
|             if(auto m = o->get_slice_index().size() > mx) mx = m; | ||||
|         } | ||||
| 
 | ||||
|                 const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel); | ||||
|                 const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport); | ||||
|         m_printer_input.reserve(mx); | ||||
| 
 | ||||
|                 if(!objslices.empty()) | ||||
|                     lyrs.emplace_back(objslices, o->instances()); | ||||
|         auto eps = coord_t(SCALED_EPSILON); | ||||
| 
 | ||||
|                 if(!supslices.empty()) | ||||
|                     lyrs.emplace_back(supslices, o->instances()); | ||||
|         for(SLAPrintObject * o : m_objects) { | ||||
|             coord_t gndlvl = o->get_slice_index().front().print_level() - ilhs; | ||||
| 
 | ||||
|             for(const SliceRecord& slicerecord : o->get_slice_index()) { | ||||
|                 coord_t lvlid = slicerecord.print_level() - gndlvl; | ||||
| 
 | ||||
|                 // Neat trick to round the layer levels to the grid.
 | ||||
|                 lvlid = eps * (lvlid / eps); | ||||
| 
 | ||||
|                 auto it = std::lower_bound(m_printer_input.begin(), | ||||
|                                            m_printer_input.end(), | ||||
|                                            PrintLayer(lvlid)); | ||||
| 
 | ||||
|                 if(it == m_printer_input.end() || it->level() != lvlid) | ||||
|                     it = m_printer_input.insert(it, PrintLayer(lvlid)); | ||||
| 
 | ||||
| 
 | ||||
|                 it->add(slicerecord); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // collect all the keys
 | ||||
|         std::vector<long long> keys; keys.reserve(m_printer_input.size()); | ||||
|         for(auto& e : m_printer_input) keys.emplace_back(e.first); | ||||
| 
 | ||||
|         // If the raster has vertical orientation, we will flip the coordinates
 | ||||
|         bool flpXY = m_printer_config.display_orientation.getInt() == | ||||
|  | @ -963,31 +993,36 @@ void SLAPrint::process() | |||
| 
 | ||||
|         // procedure to process one height level. This will run in parallel
 | ||||
|         auto lvlfn = | ||||
|         [this, &slck, &keys, &printer, slot, sd, ist, &pst, flpXY] | ||||
|         [this, &slck, &printer, slot, sd, ist, &pst, flpXY] | ||||
|             (unsigned level_id) | ||||
|         { | ||||
|             if(canceled()) return; | ||||
| 
 | ||||
|             LayerRefs& lrange = m_printer_input[keys[level_id]]; | ||||
|             PrintLayer& printlayer = m_printer_input[level_id]; | ||||
| 
 | ||||
|             // Switch to the appropriate layer in the printer
 | ||||
|             printer.begin_layer(level_id); | ||||
| 
 | ||||
|             for(auto& lyrref : lrange) { // for all layers in the current level
 | ||||
|                 if(canceled()) break; | ||||
|                 const Layer& sl = lyrref.lref;   // get the layer reference
 | ||||
|                 const LayerCopies& copies = lyrref.copies; | ||||
|             using Instance = SLAPrintObject::Instance; | ||||
| 
 | ||||
|                 // Draw all the polygons in the slice to the actual layer.
 | ||||
|                 for(auto& cp : copies) { | ||||
|                     for(ExPolygon slice : sl) { | ||||
|                         // The order is important here:
 | ||||
|                         // apply rotation before translation...
 | ||||
|                         slice.rotate(double(cp.rotation)); | ||||
|                         slice.translate(cp.shift(X), cp.shift(Y)); | ||||
|                         if(flpXY) swapXY(slice); | ||||
|                         printer.draw_polygon(slice, level_id); | ||||
|                     } | ||||
|             auto draw = | ||||
|                 [&printer, flpXY, level_id](ExPolygon& poly, const Instance& tr) | ||||
|             { | ||||
|                 poly.rotate(double(tr.rotation)); | ||||
|                 poly.translate(tr.shift(X), tr.shift(Y)); | ||||
|                 if(flpXY) swapXY(poly); | ||||
|                 printer.draw_polygon(poly, level_id); | ||||
|             }; | ||||
| 
 | ||||
|             for(const SliceRecord& sr : printlayer.slices()) { | ||||
|                 if(! sr.print_obj()) continue; | ||||
| 
 | ||||
|                 for(const Instance& inst : sr.print_obj()->instances()) { | ||||
|                     ExPolygons objsl = sr.get_slice(soModel); | ||||
|                     for(ExPolygon& poly : objsl) draw(poly, inst); | ||||
| 
 | ||||
|                     ExPolygons supsl = sr.get_slice(soSupport); | ||||
|                     for(ExPolygon& poly : supsl) draw(poly, inst); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  | @ -996,11 +1031,13 @@ void SLAPrint::process() | |||
| 
 | ||||
|             // Status indication guarded with the spinlock
 | ||||
|             auto st = ist + unsigned(sd*level_id*slot/m_printer_input.size()); | ||||
|             { std::lock_guard<SpinMutex> lck(slck); | ||||
|             if( st > pst) { | ||||
|                 report_status(*this, int(st), PRINT_STEP_LABELS[slapsRasterize]); | ||||
|                 pst = st; | ||||
|             } | ||||
|             { | ||||
|                 std::lock_guard<SpinMutex> lck(slck); | ||||
|                 if( st > pst) { | ||||
|                     report_status(*this, int(st), | ||||
|                                   PRINT_STEP_LABELS[slapsRasterize]); | ||||
|                     pst = st; | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|  | @ -1199,7 +1236,7 @@ void SLAPrint::fill_statistics() | |||
|             for (size_t i = 0; i < inst_cnt; ++i) | ||||
|             { | ||||
|                 ExPolygon tmp = polygon; | ||||
|                 tmp.rotate(Geometry::rad2deg(instances[i].rotation)); | ||||
|                 tmp.rotate(double(instances[i].rotation)); | ||||
|                 tmp.translate(instances[i].shift.x(), instances[i].shift.y()); | ||||
|                 polygons_append(polygons, to_polygons(std::move(tmp))); | ||||
|             } | ||||
|  | @ -1217,33 +1254,33 @@ 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?
 | ||||
|     float 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(); | ||||
|         auto& slice_index = po->get_slice_index(); | ||||
|         if (! slice_index.empty()) { | ||||
|             float z = (-- slice_index.end())->slice_level(); | ||||
|             // float z = (-- slice_index.end())->slice_level();
 | ||||
|             size_t cnt = slice_index.size(); | ||||
|             //if (z > max_z) {
 | ||||
|             if (cnt > max_layers_cnt) { | ||||
|                 max_layers_cnt = cnt; | ||||
|                 max_z = z; | ||||
|                 // max_z = z;
 | ||||
|                 highest_obj_idx = &po - &m_objects.front(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const SLAPrintObject * highest_obj = m_objects[highest_obj_idx]; | ||||
|     const SLAPrintObject::SliceIndex& highest_obj_slice_index = highest_obj->get_slice_index(); | ||||
|     auto& highest_obj_slice_index = highest_obj->get_slice_index(); | ||||
| 
 | ||||
|     const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1); | ||||
|     double fade_layer_time = init_exp_time; | ||||
| 
 | ||||
|     int sliced_layer_cnt = 0; | ||||
|     for (const auto& layer : highest_obj_slice_index) | ||||
|     for (const SliceRecord& layer : highest_obj_slice_index) | ||||
|     { | ||||
|         const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height; | ||||
|         const auto l_height = double(layer.layer_height()); | ||||
| 
 | ||||
|         // Calculation of the consumed material 
 | ||||
| 
 | ||||
|  | @ -1252,20 +1289,18 @@ void SLAPrint::fill_statistics() | |||
| 
 | ||||
|         for (SLAPrintObject * po : m_objects) | ||||
|         { | ||||
|             const SLAPrintObject::_SliceRecord *record = nullptr; | ||||
|             const SliceRecord *record = nullptr; | ||||
|             { | ||||
|                 const SLAPrintObject::SliceIndex& index = po->get_slice_index(); | ||||
|                 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); | ||||
|                 const SliceRecord& slr = po->closest_slice_to_slice_level(layer.slice_level(), float(EPSILON)); | ||||
|                 if (!slr.is_valid()) continue; | ||||
|                 record = &slr; | ||||
|             } | ||||
| 
 | ||||
|             const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel); | ||||
|             const ExPolygons &modelslices = record->get_slice(soModel); | ||||
|             if (!modelslices.empty()) | ||||
|                 append(model_polygons, get_all_polygons(modelslices, po->instances())); | ||||
| 
 | ||||
|             const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport); | ||||
|             const ExPolygons &supportslices = record->get_slice(soSupport); | ||||
|             if (!supportslices.empty()) | ||||
|                 append(supports_polygons, get_all_polygons(supportslices, po->instances())); | ||||
|         } | ||||
|  | @ -1472,77 +1507,13 @@ const TriangleMesh EMPTY_MESH; | |||
| const ExPolygons EMPTY_SLICE; | ||||
| } | ||||
| 
 | ||||
| const SliceRecord SliceRecord::EMPTY(0, std::nanf(""), 0.f); | ||||
| 
 | ||||
| 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));
 | ||||
|  | @ -1550,30 +1521,22 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const | |||
|     return m_supportdata->support_slices; | ||||
| } | ||||
| 
 | ||||
| const ExPolygons &SLAPrintObject::get_slices_from_record( | ||||
|         const _SliceRecord &rec, | ||||
|         SliceOrigin o) const | ||||
| const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const | ||||
| { | ||||
|     size_t idx = o == soModel ? rec.get_model_slice_idx() : | ||||
|                                 rec.get_support_slice_idx(); | ||||
|     size_t idx = o == soModel ? m_model_slices_idx : | ||||
|                                 m_support_slices_idx; | ||||
| 
 | ||||
|     const std::vector<ExPolygons>& v = o == soModel? get_model_slices() : | ||||
|                                                      get_support_slices(); | ||||
|     if(m_po == nullptr) return EMPTY_SLICE; | ||||
| 
 | ||||
|     const std::vector<ExPolygons>& v = o == soModel? m_po->get_model_slices() : | ||||
|                                                      m_po->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 | ||||
| const std::vector<SliceRecord> & SLAPrintObject::get_slice_index() const | ||||
| { | ||||
|     // assert(is_step_done(slaposIndexSlices));
 | ||||
|     return m_slice_index; | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ using _SLAPrintObjectBase = | |||
| 
 | ||||
| // Layers according to quantized height levels. This will be consumed by
 | ||||
| // the printer (rasterizer) in the SLAPrint class.
 | ||||
| using LevelID = long long; | ||||
| // using coord_t = long long;
 | ||||
| 
 | ||||
| enum SliceOrigin { soSupport, soModel }; | ||||
| 
 | ||||
|  | @ -94,142 +94,140 @@ public: | |||
|     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; | ||||
|         // this will be the max limit of size_t
 | ||||
|         static const size_t NONE = size_t(-1); | ||||
| 
 | ||||
|         static const SliceRecord EMPTY; | ||||
| 
 | ||||
|     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
 | ||||
|         coord_t   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) {} | ||||
|         size_t m_model_slices_idx = NONE; | ||||
|         size_t m_support_slices_idx = NONE; | ||||
|         const SLAPrintObject *m_po = nullptr; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         SliceRecord(coord_t key, float slicez, float height): | ||||
|             m_print_z(key), m_slice_z(slicez), m_height(height) {} | ||||
| 
 | ||||
|         // The key will be the integer height level of the top of the layer.
 | ||||
|         inline Key key() const { return m_print_z; } | ||||
|         coord_t print_level() const { return m_print_z; } | ||||
| 
 | ||||
|         // Returns the exact floating point Z coordinate of the slice
 | ||||
|         inline float slice_level() const { return m_slice_z; } | ||||
|         float slice_level() const { return m_slice_z; } | ||||
| 
 | ||||
|         // Returns the current layer height
 | ||||
|         inline float layer_height() const { return m_height; } | ||||
|         float layer_height() const { return m_height; } | ||||
| 
 | ||||
|         bool is_valid() const { return ! std::isnan(m_slice_z); } | ||||
| 
 | ||||
|         const SLAPrintObject* print_obj() const { return m_po; } | ||||
| 
 | ||||
|         // Methods for setting the indices into the slice vectors.
 | ||||
|         void set_model_slice_idx(const SLAPrintObject &po, size_t id) { | ||||
|             m_po = &po; m_model_slices_idx = id; | ||||
|         } | ||||
| 
 | ||||
|         void set_support_slice_idx(const SLAPrintObject& po, size_t id) { | ||||
|             m_po = &po; m_support_slices_idx = id; | ||||
|         } | ||||
| 
 | ||||
|         const ExPolygons& get_slice(SliceOrigin o) const; | ||||
|     }; | ||||
| 
 | ||||
| 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.
 | ||||
|     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; | ||||
|     template <class T> inline static T level(const SliceRecord& sr) { | ||||
|         static_assert(std::is_arithmetic<T>::value, "Arithmetic only!"); | ||||
|         return std::is_integral<T>::value ? T(sr.print_level()) : T(sr.slice_level()); | ||||
|     } | ||||
| 
 | ||||
|     public: | ||||
|         _SliceRecord(Key key, float slicez, float height): | ||||
|             SliceRecord(key, slicez, height) {} | ||||
|     template <class T> inline static SliceRecord create_slice_record(T val) { | ||||
|         static_assert(std::is_arithmetic<T>::value, "Arithmetic only!"); | ||||
|         return std::is_integral<T>::value ? SliceRecord{ coord_t(val), 0.f, 0.f } : SliceRecord{ 0, float(val), 0.f }; | ||||
|     } | ||||
| 
 | ||||
|         // 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; } | ||||
|     // This is a template method for searching the slice index either by
 | ||||
|     // an integer key: print_level or a floating point key: slice_level.
 | ||||
|     // The eps parameter gives the max deviation in + or - direction.
 | ||||
|     //
 | ||||
|     // This method can be used in const or non-const contexts as well.
 | ||||
|     template<class Container, class T> | ||||
|     static auto closest_slice_record( | ||||
|             Container& cont, | ||||
|             T lvl, | ||||
|             T eps = std::numeric_limits<T>::max()) -> decltype (cont.begin()) | ||||
|     { | ||||
|         if(cont.empty()) return cont.end(); | ||||
|         if(cont.size() == 1 && std::abs(level<T>(cont.front()) - lvl) > eps) | ||||
|             return cont.end(); | ||||
| 
 | ||||
|         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; } | ||||
|     }; | ||||
|         SliceRecord query = create_slice_record(lvl); | ||||
| 
 | ||||
|     // Slice index will be a plain vector sorted by the integer height levels
 | ||||
|     using SliceIndex = std::vector<_SliceRecord>; | ||||
|         auto it = std::lower_bound(cont.begin(), cont.end(), query, | ||||
|                                    [](const SliceRecord& r1, | ||||
|                                       const SliceRecord& r2) | ||||
|         { | ||||
|             return level<T>(r1) < level<T>(r2); | ||||
|         }); | ||||
| 
 | ||||
|     // Retrieve the slice index which is readable only after slaposIndexSlices
 | ||||
|     // is done.
 | ||||
|     const SliceIndex& get_slice_index() const; | ||||
|         T diff = std::abs(level<T>(*it) - lvl); | ||||
| 
 | ||||
|     // 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; | ||||
|         if(it != cont.begin()) { | ||||
|             auto it_prev = std::prev(it); | ||||
|             T diff_prev = std::abs(level<T>(*it_prev) - lvl); | ||||
|             if(diff_prev < diff) { diff = diff_prev; it = it_prev; } | ||||
|         } | ||||
| 
 | ||||
|     // 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; | ||||
|         if(diff > eps) it = cont.end(); | ||||
| 
 | ||||
|         return it; | ||||
|     } | ||||
| 
 | ||||
|     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)
 | ||||
|     // These 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 | ||||
|     // Retrieve the slice index.
 | ||||
|     const std::vector<SliceRecord>& get_slice_index() const; | ||||
| 
 | ||||
|     // Search slice index for the closest slice to given print_level.
 | ||||
|     // max_epsilon gives the allowable deviation of the returned slice record's
 | ||||
|     // level.
 | ||||
|     const SliceRecord& closest_slice_to_print_level( | ||||
|             coord_t print_level, | ||||
|             coord_t max_epsilon = std::numeric_limits<coord_t>::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), | ||||
|         }; | ||||
|         auto it = closest_slice_record(m_slice_index, print_level, max_epsilon); | ||||
|         return it == m_slice_index.end() ? SliceRecord::EMPTY : *it; | ||||
|     } | ||||
| 
 | ||||
|     // 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()) | ||||
|         }; | ||||
|     // Search slice index for the closest slice to given slice_level.
 | ||||
|     // max_epsilon gives the allowable deviation of the returned slice record's
 | ||||
|     // level. Use SliceRecord::is_valid() to check the result.
 | ||||
|     const SliceRecord& closest_slice_to_slice_level( | ||||
|             float slice_level, | ||||
|             float max_epsilon = std::numeric_limits<float>::max()) const | ||||
|     { | ||||
|         auto it = closest_slice_record(m_slice_index, slice_level, max_epsilon); | ||||
|         return it == m_slice_index.end() ? SliceRecord::EMPTY : *it; | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|  | @ -270,7 +268,7 @@ private: | |||
| 
 | ||||
|     // Exact (float) height levels mapped to the slices. Each record contains
 | ||||
|     // the index to the model and the support slice vectors.
 | ||||
|     std::vector<_SliceRecord>               m_slice_index; | ||||
|     std::vector<SliceRecord>                m_slice_index; | ||||
| 
 | ||||
|     std::vector<float>                      m_model_height_levels; | ||||
| 
 | ||||
|  | @ -283,6 +281,8 @@ private: | |||
| 
 | ||||
| using PrintObjects = std::vector<SLAPrintObject*>; | ||||
| 
 | ||||
| using SliceRecord  = SLAPrintObject::SliceRecord; | ||||
| 
 | ||||
| class TriangleMesh; | ||||
| 
 | ||||
| struct SLAPrintStatistics | ||||
|  | @ -328,6 +328,32 @@ private: // Prevents erroneous use by other classes. | |||
|     typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     // An aggregation of SliceRecord-s from all the print objects for each
 | ||||
|     // occupied layer. Slice record levels dont have to match exactly.
 | ||||
|     // They are unified if the level difference is within +/- SCALED_EPSILON
 | ||||
|     class PrintLayer { | ||||
|         coord_t m_level; | ||||
| 
 | ||||
|         // The collection of slice records for the current level.
 | ||||
|         std::vector<std::reference_wrapper<const SliceRecord>> m_slices; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         explicit PrintLayer(coord_t lvl) : m_level(lvl) {} | ||||
| 
 | ||||
|         // for being sorted in their container (see m_printer_input)
 | ||||
|         bool operator<(const PrintLayer& other) const { | ||||
|             return m_level < other.m_level; | ||||
|         } | ||||
| 
 | ||||
|         void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } | ||||
| 
 | ||||
|         coord_t level() const { return m_level; } | ||||
| 
 | ||||
|         auto slices() const -> const decltype (m_slices)& { return m_slices; } | ||||
|     }; | ||||
| 
 | ||||
|     SLAPrint(): m_stepmask(slapsCount, true) {} | ||||
| 
 | ||||
|     virtual ~SLAPrint() override { this->clear(); } | ||||
|  | @ -361,6 +387,10 @@ public: | |||
| 
 | ||||
|     std::string validate() const override; | ||||
| 
 | ||||
|     // The aggregated and leveled print records from various objects.
 | ||||
|     // TODO: use this structure for the preview in the future.
 | ||||
|     const std::vector<PrintLayer>& print_layers() const { return m_printer_input; } | ||||
| 
 | ||||
| private: | ||||
|     using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; | ||||
|     using SLAPrinterPtr = std::unique_ptr<SLAPrinter>; | ||||
|  | @ -378,23 +408,8 @@ private: | |||
|     PrintObjects                    m_objects; | ||||
|     std::vector<bool>               m_stepmask; | ||||
| 
 | ||||
|     // Definition of the print input map. It consists of the slices indexed
 | ||||
|     // with scaled (clipper) Z coordinates. Also contains the instance
 | ||||
|     // transformations in scaled and filtered version. This is enough for the
 | ||||
|     // rasterizer to be able to draw every layer in the right position
 | ||||
|     using Layer = ExPolygons; | ||||
|     using LayerCopies = std::vector<SLAPrintObject::Instance>; | ||||
|     struct LayerRef { | ||||
|         std::reference_wrapper<const Layer> lref; | ||||
|         std::reference_wrapper<const LayerCopies> copies; | ||||
|         LayerRef(const Layer& lyr, const LayerCopies& cp) : | ||||
|             lref(std::cref(lyr)), copies(std::cref(cp)) {} | ||||
|     }; | ||||
| 
 | ||||
|     // One level may contain multiple slices from multiple objects and their
 | ||||
|     // supports
 | ||||
|     using LayerRefs = std::vector<LayerRef>; | ||||
|     std::map<LevelID, LayerRefs>            m_printer_input; | ||||
|     // Ready-made data for rasterization.
 | ||||
|     std::vector<PrintLayer>                 m_printer_input; | ||||
| 
 | ||||
|     // The printer itself
 | ||||
|     SLAPrinterPtr                           m_printer; | ||||
|  |  | |||
|  | @ -5009,24 +5009,27 @@ void GLCanvas3D::_render_sla_slices() const | |||
| 			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) && !obj->get_slice_index().empty()) | ||||
|         { | ||||
|             double layer_height         = print->default_object_config().layer_height.value; | ||||
|             double initial_layer_height = print->material_config().initial_layer_height.value; | ||||
|             LevelID key_zero = obj->get_slice_records().begin()->key(); | ||||
|             // Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane.
 | ||||
| 			LevelID key_low  = LevelID((clip_min_z - initial_layer_height + layer_height) / SCALING_FACTOR) + key_zero; | ||||
|             // Slice at the center of the slab ending at clip_max_z will be rendered for the upper plane.
 | ||||
| 			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()); | ||||
|             // Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts.
 | ||||
|             double plane_shift_z = 0.002f;  | ||||
| 
 | ||||
|             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); | ||||
|             coord_t key_zero = obj->get_slice_index().front().print_level(); | ||||
|             // Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane.
 | ||||
|             coord_t key_low  = coord_t((clip_min_z - initial_layer_height + layer_height) / SCALING_FACTOR) + key_zero; | ||||
|             // Slice at the center of the slab ending at clip_max_z will be rendered for the upper plane.
 | ||||
|             coord_t key_high = coord_t((clip_max_z - initial_layer_height) / SCALING_FACTOR) + key_zero; | ||||
| 
 | ||||
|             const SliceRecord& slice_low  = obj->closest_slice_to_print_level(key_low, coord_t(SCALED_EPSILON)); | ||||
|             const SliceRecord& slice_high = obj->closest_slice_to_print_level(key_high, coord_t(SCALED_EPSILON)); | ||||
| 
 | ||||
|             // Offset to avoid OpenGL Z fighting between the object's horizontal surfaces and the triangluated surfaces of the cuts.
 | ||||
|             double plane_shift_z = 0.002; | ||||
| 
 | ||||
|             if (slice_low.is_valid()) { | ||||
|                 const ExPolygons& obj_bottom = slice_low.get_slice(soModel); | ||||
|                 const ExPolygons& sup_bottom = slice_low.get_slice(soSupport); | ||||
|                 // calculate model bottom cap
 | ||||
|                 if (bottom_obj_triangles.empty() && !obj_bottom.empty()) | ||||
|                     bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, true); | ||||
|  | @ -5035,9 +5038,9 @@ void GLCanvas3D::_render_sla_slices() const | |||
|                     bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, true); | ||||
|             } | ||||
| 
 | ||||
|             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); | ||||
|             if (slice_high.is_valid()) { | ||||
|                 const ExPolygons& obj_top = slice_high.get_slice(soModel); | ||||
|                 const ExPolygons& sup_top = slice_high.get_slice(soSupport); | ||||
|                 // calculate model top cap
 | ||||
|                 if (top_obj_triangles.empty() && !obj_top.empty()) | ||||
|                     top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, false); | ||||
|  |  | |||
|  | @ -772,12 +772,11 @@ void Preview::load_print_as_sla() | |||
|     std::vector<double> zs; | ||||
|     double initial_layer_height = print->material_config().initial_layer_height.value; | ||||
|     for (const SLAPrintObject* obj : print->objects()) | ||||
|         if (obj->is_step_done(slaposIndexSlices)) | ||||
|         if (obj->is_step_done(slaposIndexSlices) && !obj->get_slice_index().empty()) | ||||
|         { | ||||
|             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); | ||||
|             auto low_coord = obj->get_slice_index().front().print_level(); | ||||
|             for (auto& rec : obj->get_slice_index()) | ||||
|                 zs.emplace_back(initial_layer_height + (rec.print_level() - low_coord) * SCALING_FACTOR); | ||||
|         } | ||||
|     sort_remove_duplicates(zs); | ||||
| 
 | ||||
|  |  | |||
|  | @ -231,13 +231,7 @@ std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const | |||
| 
 | ||||
| void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const | ||||
| { | ||||
|     float size = (float)box.max_size(); | ||||
| 
 | ||||
|     for (int i = 0; i < (int)m_grabbers.size(); ++i) | ||||
|     { | ||||
|         if (m_grabbers[i].enabled) | ||||
|             m_grabbers[i].render((m_hover_id == i), size); | ||||
|     } | ||||
|     render_grabbers((float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoBase::render_grabbers(float size) const | ||||
|  | @ -251,7 +245,7 @@ void GLGizmoBase::render_grabbers(float size) const | |||
| 
 | ||||
| void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const | ||||
| { | ||||
|     float size = (float)box.max_size(); | ||||
|     float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_grabbers.size(); ++i) | ||||
|     { | ||||
|  | @ -261,7 +255,7 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const | |||
|             m_grabbers[i].color[0] = color[0]; | ||||
|             m_grabbers[i].color[1] = color[1]; | ||||
|             m_grabbers[i].color[2] = color[2]; | ||||
|             m_grabbers[i].render_for_picking(size); | ||||
|             m_grabbers[i].render_for_picking(mean_size); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -173,7 +173,7 @@ void GLGizmoCut::on_render(const Selection& selection) const | |||
|     ::glEnd(); | ||||
| 
 | ||||
|     std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_grabbers[0].color); | ||||
|     m_grabbers[0].render(m_hover_id == 0, box.max_size()); | ||||
|     m_grabbers[0].render(m_hover_id == 0, (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoCut::on_render_for_picking(const Selection& selection) const | ||||
|  |  | |||
|  | @ -216,7 +216,8 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box | |||
|     if (m_quadric == nullptr) | ||||
|         return; | ||||
| 
 | ||||
|     double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size((float)box.max_size()) : (double)m_grabbers[axis].get_half_size((float)box.max_size()); | ||||
|     float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); | ||||
|     double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size); | ||||
| 
 | ||||
|     float color[3]; | ||||
|     ::memcpy((void*)color, (const void*)m_grabbers[axis].color, 3 * sizeof(float)); | ||||
|  |  | |||
|  | @ -307,7 +307,8 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick | |||
|     if (m_quadric == nullptr) | ||||
|         return; | ||||
| 
 | ||||
|     double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size((float)box.max_size()) : (double)m_grabbers[0].get_half_size((float)box.max_size()); | ||||
|     float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); | ||||
|     double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); | ||||
| 
 | ||||
|     float color[3]; | ||||
|     ::memcpy((void*)color, (const void*)m_grabbers[0].color, 3 * sizeof(float)); | ||||
|  |  | |||
|  | @ -116,8 +116,6 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|     Vec3d angles = Vec3d::Zero(); | ||||
|     Transform3d offsets_transform = Transform3d::Identity(); | ||||
| 
 | ||||
|     Vec3d grabber_size = Vec3d::Zero(); | ||||
| 
 | ||||
|     if (single_instance) | ||||
|     { | ||||
|         // calculate bounding box in instance local reference system
 | ||||
|  | @ -135,7 +133,6 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|         angles = v->get_instance_rotation(); | ||||
|         // consider rotation+mirror only components of the transform for offsets
 | ||||
|         offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); | ||||
|         grabber_size = v->get_instance_transformation().get_matrix(true, true, false, true) * box.size(); | ||||
|     } | ||||
|     else if (single_volume) | ||||
|     { | ||||
|  | @ -145,13 +142,9 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|         angles = Geometry::extract_euler_angles(transform); | ||||
|         // consider rotation+mirror only components of the transform for offsets
 | ||||
|         offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror()); | ||||
|         grabber_size = v->get_volume_transformation().get_matrix(true, true, false, true) * box.size(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         box = selection.get_bounding_box(); | ||||
|         grabber_size = box.size(); | ||||
|     } | ||||
| 
 | ||||
|     m_box = box; | ||||
| 
 | ||||
|  | @ -196,7 +189,9 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
| 
 | ||||
|     ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); | ||||
| 
 | ||||
|     float grabber_mean_size = (float)(grabber_size(0) + grabber_size(1) + grabber_size(2)) / 3.0f; | ||||
|     const BoundingBoxf3& selection_box = selection.get_bounding_box(); | ||||
| 
 | ||||
|     float grabber_mean_size = (float)((selection_box.size()(0) + selection_box.size()(1) + selection_box.size()(2)) / 3.0); | ||||
| 
 | ||||
|     if (m_hover_id == -1) | ||||
|     { | ||||
|  |  | |||
|  | @ -56,6 +56,14 @@ bool ImGuiWrapper::init() | |||
| 
 | ||||
| void ImGuiWrapper::set_language(const std::string &language) | ||||
| { | ||||
|     if (m_new_frame_open) { | ||||
|         // ImGUI internally locks the font between NewFrame() and EndFrame()
 | ||||
|         // NewFrame() might've been called here because of input from the 3D scene;
 | ||||
|         // call EndFrame()
 | ||||
|         ImGui::EndFrame(); | ||||
|         m_new_frame_open = false; | ||||
|     } | ||||
| 
 | ||||
|     const ImWchar *ranges = nullptr; | ||||
|     size_t idx = language.find('_'); | ||||
|     std::string lang = (idx == std::string::npos) ? language : language.substr(0, idx); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv