mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_3dconnexion
This commit is contained in:
		
						commit
						068b7e86a9
					
				
					 8 changed files with 296 additions and 203 deletions
				
			
		|  | @ -194,6 +194,8 @@ add_library(libslic3r STATIC | |||
|     SLA/SLARaster.cpp | ||||
|     SLA/SLARasterWriter.hpp | ||||
|     SLA/SLARasterWriter.cpp | ||||
|     SLA/ConcaveHull.hpp | ||||
|     SLA/ConcaveHull.cpp | ||||
| ) | ||||
| 
 | ||||
| encoding_check(libslic3r) | ||||
|  |  | |||
|  | @ -507,7 +507,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen) | |||
| std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer) | ||||
| { | ||||
|     std::string gcode; | ||||
| 	assert(m_layer_idx >= 0 && size_t(m_layer_idx) <= m_tool_changes.size()); | ||||
|     assert(m_layer_idx >= 0); | ||||
|     if (! m_brim_done || gcodegen.writer().need_toolchange(extruder_id) || finish_layer) { | ||||
| 		if (m_layer_idx < (int)m_tool_changes.size()) { | ||||
| 			if (! (size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size())) | ||||
|  |  | |||
							
								
								
									
										171
									
								
								src/libslic3r/SLA/ConcaveHull.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/libslic3r/SLA/ConcaveHull.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,171 @@ | |||
| #include "ConcaveHull.hpp" | ||||
| #include <libslic3r/MTUtils.hpp> | ||||
| #include <libslic3r/ClipperUtils.hpp> | ||||
| #include "SLASpatIndex.hpp" | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace sla { | ||||
| 
 | ||||
| inline Vec3d to_vec3(const Vec2crd &v2) { return {double(v2(X)), double(v2(Y)), 0.}; } | ||||
| inline Vec3d to_vec3(const Vec2d &v2) { return {v2(X), v2(Y), 0.}; } | ||||
| inline Vec2crd to_vec2(const Vec3d &v3) { return {coord_t(v3(X)), coord_t(v3(Y))}; } | ||||
| 
 | ||||
| Point ConcaveHull::centroid(const Points &pp) | ||||
| { | ||||
|     Point c; | ||||
|     switch(pp.size()) { | ||||
|     case 0: break; | ||||
|     case 1: c = pp.front(); break; | ||||
|     case 2: c = (pp[0] + pp[1]) / 2; break; | ||||
|     default: { | ||||
|         auto MAX = std::numeric_limits<Point::coord_type>::max(); | ||||
|         auto MIN = std::numeric_limits<Point::coord_type>::min(); | ||||
|         Point min = {MAX, MAX}, max = {MIN, MIN}; | ||||
| 
 | ||||
|         for(auto& p : pp) { | ||||
|             if(p(0) < min(0)) min(0) = p(0); | ||||
|             if(p(1) < min(1)) min(1) = p(1); | ||||
|             if(p(0) > max(0)) max(0) = p(0); | ||||
|             if(p(1) > max(1)) max(1) = p(1); | ||||
|         } | ||||
|         c(0) = min(0) + (max(0) - min(0)) / 2; | ||||
|         c(1) = min(1) + (max(1) - min(1)) / 2; | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     return c; | ||||
| } | ||||
| 
 | ||||
| // As it shows, the current offset_ex in ClipperUtils hangs if used in jtRound
 | ||||
| // mode
 | ||||
| ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, | ||||
|                               coord_t                  delta, | ||||
|                               ClipperLib::JoinType     jointype) | ||||
| { | ||||
|     using ClipperLib::ClipperOffset; | ||||
|     using ClipperLib::etClosedPolygon; | ||||
|     using ClipperLib::Paths; | ||||
|     using ClipperLib::Path; | ||||
| 
 | ||||
|     ClipperOffset offs; | ||||
|     offs.ArcTolerance = scaled<double>(0.01); | ||||
| 
 | ||||
|     for (auto &p : paths) | ||||
|         // If the input is not at least a triangle, we can not do this algorithm
 | ||||
|         if(p.size() < 3) { | ||||
|             BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; | ||||
|             return {}; | ||||
|         } | ||||
| 
 | ||||
|     offs.AddPaths(paths, jointype, etClosedPolygon); | ||||
| 
 | ||||
|     Paths result; | ||||
|     offs.Execute(result, static_cast<double>(delta)); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| Points ConcaveHull::calculate_centroids() const | ||||
| { | ||||
|     // We get the centroids of all the islands in the 2D slice
 | ||||
|     Points centroids = reserve_vector<Point>(m_polys.size()); | ||||
|     std::transform(m_polys.begin(), m_polys.end(), | ||||
|                    std::back_inserter(centroids), | ||||
|                    [this](const Polygon &poly) { return centroid(poly); }); | ||||
| 
 | ||||
|     return centroids; | ||||
| } | ||||
| 
 | ||||
| void ConcaveHull::merge_polygons() { m_polys = get_contours(union_ex(m_polys)); } | ||||
| 
 | ||||
| void ConcaveHull::add_connector_rectangles(const Points ¢roids, | ||||
|                                            coord_t       max_dist, | ||||
|                                            ThrowOnCancel thr) | ||||
| { | ||||
|     // Centroid of the centroids of islands. This is where the additional
 | ||||
|     // connector sticks are routed.
 | ||||
|     Point cc = centroid(centroids); | ||||
| 
 | ||||
|     PointIndex ctrindex; | ||||
|     unsigned  idx = 0; | ||||
|     for(const Point &ct : centroids) ctrindex.insert(to_vec3(ct), idx++); | ||||
| 
 | ||||
|     m_polys.reserve(m_polys.size() + centroids.size()); | ||||
| 
 | ||||
|     idx = 0; | ||||
|     for (const Point &c : centroids) { | ||||
|         thr(); | ||||
| 
 | ||||
|         double dx = c.x() - cc.x(), dy = c.y() - cc.y(); | ||||
|         double l  = std::sqrt(dx * dx + dy * dy); | ||||
|         double nx = dx / l, ny = dy / l; | ||||
| 
 | ||||
|         const Point &ct = centroids[idx]; | ||||
| 
 | ||||
|         std::vector<PointIndexEl> result = ctrindex.nearest(to_vec3(ct), 2); | ||||
| 
 | ||||
|         double dist = max_dist; | ||||
|         for (const PointIndexEl &el : result) | ||||
|             if (el.second != idx) { | ||||
|                 dist = Line(to_vec2(el.first), ct).length(); | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|         idx++; | ||||
| 
 | ||||
|         if (dist >= max_dist) return; | ||||
| 
 | ||||
|         Polygon r; | ||||
|         r.points.reserve(3); | ||||
|         r.points.emplace_back(cc); | ||||
| 
 | ||||
|         Point n(scaled(nx), scaled(ny)); | ||||
|         r.points.emplace_back(c + Point(n.y(), -n.x())); | ||||
|         r.points.emplace_back(c + Point(-n.y(), n.x())); | ||||
|         offset(r, scaled<float>(1.)); | ||||
| 
 | ||||
|         m_polys.emplace_back(r); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ConcaveHull::ConcaveHull(const Polygons &polys, double mergedist, ThrowOnCancel thr) | ||||
| { | ||||
|     if(polys.empty()) return; | ||||
| 
 | ||||
|     m_polys = polys; | ||||
|     merge_polygons(); | ||||
| 
 | ||||
|     if(m_polys.size() == 1) return; | ||||
| 
 | ||||
|     Points centroids = calculate_centroids(); | ||||
| 
 | ||||
|     add_connector_rectangles(centroids, scaled(mergedist), thr); | ||||
| 
 | ||||
|     merge_polygons(); | ||||
| } | ||||
| 
 | ||||
| ExPolygons ConcaveHull::to_expolygons() const | ||||
| { | ||||
|     auto ret = reserve_vector<ExPolygon>(m_polys.size()); | ||||
|     for (const Polygon &p : m_polys) ret.emplace_back(ExPolygon(p)); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| ExPolygons offset_waffle_style_ex(const ConcaveHull &hull, coord_t delta) | ||||
| { | ||||
|     ClipperLib::Paths paths = Slic3rMultiPoints_to_ClipperPaths(hull.polygons()); | ||||
|     paths = fast_offset(paths, 2 * delta, ClipperLib::jtRound); | ||||
|     paths = fast_offset(paths, -delta, ClipperLib::jtRound); | ||||
|     ExPolygons ret = ClipperPaths_to_Slic3rExPolygons(paths); | ||||
|     for (ExPolygon &p : ret) p.holes = {}; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta) | ||||
| { | ||||
|     return to_polygons(offset_waffle_style_ex(hull, delta)); | ||||
| } | ||||
| 
 | ||||
| }} // namespace Slic3r::sla
 | ||||
							
								
								
									
										53
									
								
								src/libslic3r/SLA/ConcaveHull.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/libslic3r/SLA/ConcaveHull.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| #ifndef CONCAVEHULL_HPP | ||||
| #define CONCAVEHULL_HPP | ||||
| 
 | ||||
| #include <libslic3r/ExPolygon.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace sla { | ||||
| 
 | ||||
| inline Polygons get_contours(const ExPolygons &poly) | ||||
| { | ||||
|     Polygons ret; ret.reserve(poly.size()); | ||||
|     for (const ExPolygon &p : poly) ret.emplace_back(p.contour); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| using ThrowOnCancel = std::function<void()>; | ||||
| 
 | ||||
| /// A fake concave hull that is constructed by connecting separate shapes
 | ||||
| /// with explicit bridges. Bridges are generated from each shape's centroid
 | ||||
| /// to the center of the "scene" which is the centroid calculated from the shape
 | ||||
| /// centroids (a star is created...)
 | ||||
| class ConcaveHull { | ||||
|     Polygons m_polys; | ||||
| 
 | ||||
|     static Point centroid(const Points& pp); | ||||
| 
 | ||||
|     static inline Point centroid(const Polygon &poly) { return poly.centroid(); } | ||||
| 
 | ||||
|     Points calculate_centroids() const; | ||||
| 
 | ||||
|     void merge_polygons(); | ||||
| 
 | ||||
|     void add_connector_rectangles(const Points ¢roids, | ||||
|                                   coord_t       max_dist, | ||||
|                                   ThrowOnCancel thr); | ||||
| public: | ||||
| 
 | ||||
|     ConcaveHull(const ExPolygons& polys, double merge_dist, ThrowOnCancel thr) | ||||
|         : ConcaveHull{to_polygons(polys), merge_dist, thr} {} | ||||
| 
 | ||||
|     ConcaveHull(const Polygons& polys, double mergedist, ThrowOnCancel thr); | ||||
| 
 | ||||
|     const Polygons & polygons() const { return m_polys; } | ||||
| 
 | ||||
|     ExPolygons to_expolygons() const; | ||||
| }; | ||||
| 
 | ||||
| ExPolygons offset_waffle_style_ex(const ConcaveHull &ccvhull, coord_t delta); | ||||
| Polygons   offset_waffle_style(const ConcaveHull &polys, coord_t delta); | ||||
| 
 | ||||
| }}     // namespace Slic3r::sla
 | ||||
| #endif // CONCAVEHULL_HPP
 | ||||
|  | @ -1,6 +1,7 @@ | |||
| #include "SLAPad.hpp" | ||||
| #include "SLABoilerPlate.hpp" | ||||
| #include "SLASpatIndex.hpp" | ||||
| #include "ConcaveHull.hpp" | ||||
| 
 | ||||
| #include "boost/log/trivial.hpp" | ||||
| #include "SLABoostAdapter.hpp" | ||||
|  | @ -206,36 +207,6 @@ Contour3D inline straight_walls(const Polygon &plate, | |||
|     return walls(plate, plate, lo_z, hi_z, .0 /*offset_diff*/, thr); | ||||
| } | ||||
| 
 | ||||
| // As it shows, the current offset_ex in ClipperUtils hangs if used in jtRound
 | ||||
| // mode
 | ||||
| ClipperLib::Paths fast_offset(const ClipperLib::Paths &paths, | ||||
|                               coord_t                  delta, | ||||
|                               ClipperLib::JoinType     jointype) | ||||
| { | ||||
|     using ClipperLib::ClipperOffset; | ||||
|     using ClipperLib::etClosedPolygon; | ||||
|     using ClipperLib::Paths; | ||||
|     using ClipperLib::Path; | ||||
| 
 | ||||
|     ClipperOffset offs; | ||||
|     offs.ArcTolerance = scaled<double>(0.01); | ||||
| 
 | ||||
|     for (auto &p : paths) | ||||
|         // If the input is not at least a triangle, we can not do this algorithm
 | ||||
|         if(p.size() < 3) { | ||||
|             BOOST_LOG_TRIVIAL(error) << "Invalid geometry for offsetting!"; | ||||
|             return {}; | ||||
|         } | ||||
| 
 | ||||
|     offs.AddPaths(paths, jointype, etClosedPolygon); | ||||
| 
 | ||||
|     Paths result; | ||||
|     offs.Execute(result, static_cast<double>(delta)); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Function to cut tiny connector cavities for a given polygon. The input poly
 | ||||
| // will be offsetted by "padding" and small rectangle shaped cavities will be
 | ||||
| // inserted along the perimeter in every "stride" distance. The stick rectangles
 | ||||
|  | @ -322,158 +293,15 @@ ExPolygons breakstick_holes(const ExPolygons &input, Args...args) | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /// A fake concave hull that is constructed by connecting separate shapes
 | ||||
| /// with explicit bridges. Bridges are generated from each shape's centroid
 | ||||
| /// to the center of the "scene" which is the centroid calculated from the shape
 | ||||
| /// centroids (a star is created...)
 | ||||
| class ConcaveHull { | ||||
|     Polygons m_polys; | ||||
| static inline coord_t get_waffle_offset(const PadConfig &c) | ||||
| { | ||||
|     return scaled(c.brim_size_mm + c.wing_distance()); | ||||
| } | ||||
| 
 | ||||
|     Point centroid(const Points& pp) const | ||||
|     { | ||||
|         Point c; | ||||
|         switch(pp.size()) { | ||||
|         case 0: break; | ||||
|         case 1: c = pp.front(); break; | ||||
|         case 2: c = (pp[0] + pp[1]) / 2; break; | ||||
|         default: { | ||||
|             auto MAX = std::numeric_limits<Point::coord_type>::max(); | ||||
|             auto MIN = std::numeric_limits<Point::coord_type>::min(); | ||||
|             Point min = {MAX, MAX}, max = {MIN, MIN}; | ||||
| 
 | ||||
|             for(auto& p : pp) { | ||||
|                 if(p(0) < min(0)) min(0) = p(0); | ||||
|                 if(p(1) < min(1)) min(1) = p(1); | ||||
|                 if(p(0) > max(0)) max(0) = p(0); | ||||
|                 if(p(1) > max(1)) max(1) = p(1); | ||||
|             } | ||||
|             c(0) = min(0) + (max(0) - min(0)) / 2; | ||||
|             c(1) = min(1) + (max(1) - min(1)) / 2; | ||||
|             break; | ||||
|         } | ||||
|         } | ||||
| 
 | ||||
|         return c; | ||||
|     } | ||||
| 
 | ||||
|     inline Point centroid(const Polygon &poly) const { return poly.centroid(); } | ||||
| 
 | ||||
|     Points calculate_centroids() const | ||||
|     { | ||||
|         // We get the centroids of all the islands in the 2D slice
 | ||||
|         Points centroids = reserve_vector<Point>(m_polys.size()); | ||||
|         std::transform(m_polys.begin(), m_polys.end(), | ||||
|                        std::back_inserter(centroids), | ||||
|                        [this](const Polygon &poly) { return centroid(poly); }); | ||||
| 
 | ||||
|         return centroids; | ||||
|     } | ||||
| 
 | ||||
|     void merge_polygons() { m_polys = union_(m_polys); } | ||||
| 
 | ||||
|     void add_connector_rectangles(const Points ¢roids, | ||||
|                                   coord_t       max_dist, | ||||
|                                   ThrowOnCancel thr) | ||||
|     { | ||||
|         namespace bgi = boost::geometry::index; | ||||
|         using PointIndexElement = std::pair<Point, unsigned>; | ||||
|         using PointIndex = bgi::rtree<PointIndexElement, bgi::rstar<16, 4>>; | ||||
| 
 | ||||
|         // Centroid of the centroids of islands. This is where the additional
 | ||||
|         // connector sticks are routed.
 | ||||
|         Point cc = centroid(centroids); | ||||
| 
 | ||||
|         PointIndex ctrindex; | ||||
|         unsigned  idx = 0; | ||||
|         for(const Point &ct : centroids) | ||||
|             ctrindex.insert(std::make_pair(ct, idx++)); | ||||
| 
 | ||||
|         m_polys.reserve(m_polys.size() + centroids.size()); | ||||
| 
 | ||||
|         idx = 0; | ||||
|         for (const Point &c : centroids) { | ||||
|             thr(); | ||||
| 
 | ||||
|             double dx = c.x() - cc.x(), dy = c.y() - cc.y(); | ||||
|             double l  = std::sqrt(dx * dx + dy * dy); | ||||
|             double nx = dx / l, ny = dy / l; | ||||
| 
 | ||||
|             const Point &ct = centroids[idx]; | ||||
| 
 | ||||
|             std::vector<PointIndexElement> result; | ||||
|             ctrindex.query(bgi::nearest(ct, 2), std::back_inserter(result)); | ||||
| 
 | ||||
|             double dist = max_dist; | ||||
|             for (const PointIndexElement &el : result) | ||||
|                 if (el.second != idx) { | ||||
|                     dist = Line(el.first, ct).length(); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|             idx++; | ||||
| 
 | ||||
|             if (dist >= max_dist) return; | ||||
| 
 | ||||
|             Polygon r; | ||||
|             r.points.reserve(3); | ||||
|             r.points.emplace_back(cc); | ||||
| 
 | ||||
|             Point d(scaled(nx), scaled(ny)); | ||||
|             r.points.emplace_back(c + Point(-d.y(), d.x())); | ||||
|             r.points.emplace_back(c + Point(d.y(), -d.x())); | ||||
|             offset(r, scaled<float>(1.)); | ||||
| 
 | ||||
|             m_polys.emplace_back(r); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     ConcaveHull(const ExPolygons& polys, double merge_dist, ThrowOnCancel thr) | ||||
|         : ConcaveHull{to_polygons(polys), merge_dist, thr} {} | ||||
| 
 | ||||
|     ConcaveHull(const Polygons& polys, double mergedist, ThrowOnCancel thr) | ||||
|     { | ||||
|         if(polys.empty()) return; | ||||
| 
 | ||||
|         m_polys = polys; | ||||
|         merge_polygons(); | ||||
| 
 | ||||
|         if(m_polys.size() == 1) return; | ||||
| 
 | ||||
|         Points centroids = calculate_centroids(); | ||||
| 
 | ||||
|         add_connector_rectangles(centroids, scaled(mergedist), thr); | ||||
| 
 | ||||
|         merge_polygons(); | ||||
|     } | ||||
| 
 | ||||
|     // const Polygons & polygons() const { return m_polys; }
 | ||||
| 
 | ||||
|     ExPolygons to_expolygons() const | ||||
|     { | ||||
|         auto ret = reserve_vector<ExPolygon>(m_polys.size()); | ||||
|         for (const Polygon &p : m_polys) ret.emplace_back(ExPolygon(p)); | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     void offset_waffle_style(coord_t delta) { | ||||
|         ClipperLib::Paths paths = Slic3rMultiPoints_to_ClipperPaths(m_polys); | ||||
|         paths = fast_offset(paths, 2 * delta, ClipperLib::jtRound); | ||||
|         paths = fast_offset(paths, -delta, ClipperLib::jtRound); | ||||
|         m_polys = ClipperPaths_to_Slic3rPolygons(paths); | ||||
|     } | ||||
| 
 | ||||
|     static inline coord_t get_waffle_offset(const PadConfig &c) | ||||
|     { | ||||
|         return scaled(c.brim_size_mm + c.wing_distance()); | ||||
|     } | ||||
| 
 | ||||
|     static inline double get_merge_distance(const PadConfig &c) | ||||
|     { | ||||
|         return 2. * (1.8 * c.wall_thickness_mm) + c.max_merge_dist_mm; | ||||
|     } | ||||
| }; | ||||
| static inline double get_merge_distance(const PadConfig &c) | ||||
| { | ||||
|     return 2. * (1.8 * c.wall_thickness_mm) + c.max_merge_dist_mm; | ||||
| } | ||||
| 
 | ||||
| // Part of the pad configuration that is used for 3D geometry generation
 | ||||
| struct PadConfig3D { | ||||
|  | @ -591,7 +419,7 @@ public: | |||
|                       scaled<float>(cfg.embed_object.object_gap_mm), | ||||
|                       ClipperLib::jtMiter, 1); | ||||
| 
 | ||||
|         ConcaveHull fullcvh = | ||||
|         ExPolygons fullcvh = | ||||
|             wafflized_concave_hull(support_blueprint, model_bp_offs, cfg, thr); | ||||
| 
 | ||||
|         auto model_bp_sticks = | ||||
|  | @ -600,7 +428,7 @@ public: | |||
|                              cfg.embed_object.stick_width_mm, | ||||
|                              cfg.embed_object.stick_penetration_mm); | ||||
| 
 | ||||
|         ExPolygons fullpad = diff_ex(fullcvh.to_expolygons(), model_bp_sticks); | ||||
|         ExPolygons fullpad = diff_ex(fullcvh, model_bp_sticks); | ||||
| 
 | ||||
|         remove_redundant_parts(fullpad); | ||||
| 
 | ||||
|  | @ -619,7 +447,7 @@ private: | |||
| 
 | ||||
|     // Create the wafflized pad around all object in the scene. This pad doesnt
 | ||||
|     // have any holes yet.
 | ||||
|     ConcaveHull wafflized_concave_hull(const ExPolygons &supp_bp, | ||||
|     ExPolygons wafflized_concave_hull(const ExPolygons &supp_bp, | ||||
|                                        const ExPolygons &model_bp, | ||||
|                                        const PadConfig  &cfg, | ||||
|                                        ThrowOnCancel     thr) | ||||
|  | @ -629,10 +457,8 @@ private: | |||
|         for (auto &ep : supp_bp) allin.emplace_back(ep.contour); | ||||
|         for (auto &ep : model_bp) allin.emplace_back(ep.contour); | ||||
| 
 | ||||
|         ConcaveHull ret{allin, ConcaveHull::get_merge_distance(cfg), thr}; | ||||
|         ret.offset_waffle_style(ConcaveHull::get_waffle_offset(cfg)); | ||||
| 
 | ||||
|         return ret; | ||||
|         ConcaveHull cchull{allin, get_merge_distance(cfg), thr}; | ||||
|         return offset_waffle_style_ex(cchull, get_waffle_offset(cfg)); | ||||
|     } | ||||
| 
 | ||||
|     // To remove parts of the pad skeleton which do not host any supports
 | ||||
|  | @ -663,10 +489,9 @@ public: | |||
|         for (auto &ep : support_blueprint) outer.emplace_back(ep.contour); | ||||
|         for (auto &ep : model_blueprint) outer.emplace_back(ep.contour); | ||||
| 
 | ||||
|         ConcaveHull ochull{outer, ConcaveHull::get_merge_distance(cfg), thr}; | ||||
|         ConcaveHull ochull{outer, get_merge_distance(cfg), thr}; | ||||
| 
 | ||||
|         ochull.offset_waffle_style(ConcaveHull::get_waffle_offset(cfg)); | ||||
|         outer = ochull.to_expolygons(); | ||||
|         outer = offset_waffle_style_ex(ochull, get_waffle_offset(cfg)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -861,7 +686,7 @@ std::string PadConfig::validate() const | |||
| 
 | ||||
|     if (brim_size_mm < MIN_BRIM_SIZE_MM || | ||||
|         bottom_offset() > brim_size_mm + wing_distance() || | ||||
|         ConcaveHull::get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) | ||||
|         get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) | ||||
|         return L("Pad brim size is too small for the current configuration."); | ||||
| 
 | ||||
|     return ""; | ||||
|  |  | |||
|  | @ -175,7 +175,7 @@ class SupportTreeBuildsteps { | |||
| 
 | ||||
|     // A spatial index to easily find strong pillars to connect to.
 | ||||
|     PillarIndex m_pillar_index; | ||||
|      | ||||
| 
 | ||||
|     // When bridging heads to pillars... TODO: find a cleaner solution
 | ||||
|     ccr::BlockingMutex m_bridge_mutex; | ||||
| 
 | ||||
|  |  | |||
|  | @ -107,7 +107,9 @@ void GLCanvas3DManager::GLInfo::detect() const | |||
|         m_renderer = data; | ||||
| 
 | ||||
|     glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_tex_size)); | ||||
|      | ||||
| 
 | ||||
|     m_max_tex_size /= 2; | ||||
| 
 | ||||
|     if (GLEW_EXT_texture_filter_anisotropic) | ||||
|         glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| #include "libslic3r/SLA/SLASupportTreeBuildsteps.hpp" | ||||
| #include "libslic3r/SLA/SLAAutoSupports.hpp" | ||||
| #include "libslic3r/SLA/SLARaster.hpp" | ||||
| #include "libslic3r/SLA/ConcaveHull.hpp" | ||||
| #include "libslic3r/MTUtils.hpp" | ||||
| 
 | ||||
| #include "libslic3r/SVG.hpp" | ||||
|  | @ -79,6 +80,43 @@ struct PadByproducts | |||
|     TriangleMesh mesh; | ||||
| }; | ||||
| 
 | ||||
| void _test_concave_hull(const Polygons &hull, const ExPolygons &polys) | ||||
| { | ||||
|     REQUIRE(polys.size() >=hull.size()); | ||||
| 
 | ||||
|     double polys_area = 0; | ||||
|     for (const ExPolygon &p : polys) polys_area += p.area(); | ||||
| 
 | ||||
|     double cchull_area = 0; | ||||
|     for (const Slic3r::Polygon &p : hull) cchull_area += p.area(); | ||||
| 
 | ||||
|     REQUIRE(cchull_area >= Approx(polys_area)); | ||||
| 
 | ||||
|     size_t cchull_holes = 0; | ||||
|     for (const Slic3r::Polygon &p : hull) | ||||
|         cchull_holes += p.is_clockwise() ? 1 : 0; | ||||
| 
 | ||||
|     REQUIRE(cchull_holes == 0); | ||||
| 
 | ||||
|     Polygons intr = diff(to_polygons(polys), hull); | ||||
|     REQUIRE(intr.empty()); | ||||
| } | ||||
| 
 | ||||
| void test_concave_hull(const ExPolygons &polys) { | ||||
|     sla::PadConfig pcfg; | ||||
| 
 | ||||
|     Slic3r::sla::ConcaveHull cchull{polys, pcfg.max_merge_dist_mm, []{}}; | ||||
| 
 | ||||
|     _test_concave_hull(cchull.polygons(), polys); | ||||
| 
 | ||||
|     coord_t delta = scaled(pcfg.brim_size_mm + pcfg.wing_distance()); | ||||
|     ExPolygons wafflex = sla::offset_waffle_style_ex(cchull, delta); | ||||
|     Polygons waffl = sla::offset_waffle_style(cchull, delta); | ||||
| 
 | ||||
|     _test_concave_hull(to_polygons(wafflex), polys); | ||||
|     _test_concave_hull(waffl, polys); | ||||
| } | ||||
| 
 | ||||
| void test_pad(const std::string &   obj_filename, | ||||
|               const sla::PadConfig &padcfg, | ||||
|               PadByproducts &       out) | ||||
|  | @ -92,6 +130,8 @@ void test_pad(const std::string &   obj_filename, | |||
|     // Create pad skeleton only from the model
 | ||||
|     Slic3r::sla::pad_blueprint(mesh, out.model_contours); | ||||
| 
 | ||||
|     test_concave_hull(out.model_contours); | ||||
| 
 | ||||
|     REQUIRE_FALSE(out.model_contours.empty()); | ||||
| 
 | ||||
|     // Create the pad geometry for the model contours only
 | ||||
|  | @ -257,7 +297,7 @@ void export_failed_case(const std::vector<ExPolygons> &support_slices, | |||
|         const ExPolygons &sup_slice = support_slices[n]; | ||||
|         const ExPolygons &mod_slice = byproducts.model_slices[n]; | ||||
|         Polygons intersections = intersection(sup_slice, mod_slice); | ||||
|          | ||||
| 
 | ||||
|         std::stringstream ss; | ||||
|         if (!intersections.empty()) { | ||||
|             ss << byproducts.obj_fname << std::setprecision(4) << n << ".svg"; | ||||
|  | @ -268,7 +308,7 @@ void export_failed_case(const std::vector<ExPolygons> &support_slices, | |||
|             svg.Close(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     TriangleMesh m; | ||||
|     byproducts.supporttree.retrieve_full_mesh(m); | ||||
|     m.merge(byproducts.input_mesh); | ||||
|  | @ -288,7 +328,7 @@ void test_support_model_collision( | |||
|     // Set head penetration to a small negative value which should ensure that
 | ||||
|     // the supports will not touch the model body.
 | ||||
|     supportcfg.head_penetration_mm = -0.15; | ||||
|      | ||||
| 
 | ||||
|     // TODO: currently, the tailheads penetrating into the model body do not
 | ||||
|     // respect the penetration parameter properly. No issues were reported so
 | ||||
|     // far but we should definitely fix this.
 | ||||
|  | @ -305,7 +345,7 @@ void test_support_model_collision( | |||
|     bool support_mesh_is_empty = | ||||
|         byproducts.supporttree.retrieve_mesh(sla::MeshType::Pad).empty() && | ||||
|         byproducts.supporttree.retrieve_mesh(sla::MeshType::Support).empty(); | ||||
|      | ||||
| 
 | ||||
|     if (support_mesh_is_empty) | ||||
|         REQUIRE(support_slices.empty()); | ||||
|     else | ||||
|  | @ -320,7 +360,7 @@ void test_support_model_collision( | |||
| 
 | ||||
|         notouch = notouch && intersections.empty(); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     if (!notouch) export_failed_case(support_slices, byproducts); | ||||
| 
 | ||||
|     REQUIRE(notouch); | ||||
|  | @ -359,12 +399,12 @@ template <class I, class II> void test_pairhash() | |||
| 
 | ||||
|     const I Ibits = int(sizeof(I) * CHAR_BIT); | ||||
|     const II IIbits = int(sizeof(II) * CHAR_BIT); | ||||
|      | ||||
| 
 | ||||
|     int bits = IIbits / 2 < Ibits ? Ibits / 2 : Ibits; | ||||
|     if (std::is_signed<I>::value) bits -= 1; | ||||
|     const I Imin = std::is_signed<I>::value ? -I(std::pow(2., bits)) : 0; | ||||
|     const I Imin = 0; | ||||
|     const I Imax = I(std::pow(2., bits) - 1); | ||||
|      | ||||
| 
 | ||||
|     std::uniform_int_distribution<I> dis(Imin, Imax); | ||||
| 
 | ||||
|     for (size_t i = 0; i < nums;) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri