mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	WIP:
* slicing supports * adding the pad geometry * rasterizing the support and pad slices
This commit is contained in:
		
							parent
							
								
									3613a54e03
								
							
						
					
					
						commit
						e98c83a025
					
				
					 6 changed files with 268 additions and 144 deletions
				
			
		|  | @ -425,6 +425,8 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h) | |||
| 
 | ||||
|     TriangleMesh upper, lower; | ||||
|     slicer.cut(h, &upper, &lower); | ||||
| 
 | ||||
|     // TODO: this might be slow
 | ||||
|     output = lower.horizontal_projection(); | ||||
| 
 | ||||
|     for(auto& o : output) o = o.simplify(0.1/SCALING_FACTOR).front(); | ||||
|  |  | |||
|  | @ -168,9 +168,10 @@ Contour3D sphere(double rho, Portion portion = make_portion(0.0, 2.0*PI), | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| Contour3D cylinder(double r, double h, size_t steps) { | ||||
| Contour3D cylinder(double r, double h, size_t ssteps) { | ||||
|     Contour3D ret; | ||||
| 
 | ||||
|     auto steps = int(ssteps); | ||||
|     auto& points = ret.points; | ||||
|     auto& indices = ret.indices; | ||||
|     points.reserve(2*steps); | ||||
|  | @ -275,10 +276,10 @@ struct Head { | |||
|             mesh.indices.emplace_back(i1s1, i2s2, i1s2); | ||||
|         } | ||||
| 
 | ||||
|         auto i1s1 = coord_t(s1.points.size()) - steps; | ||||
|         auto i1s1 = coord_t(s1.points.size()) - coord_t(steps); | ||||
|         auto i2s1 = coord_t(s1.points.size()) - 1; | ||||
|         auto i1s2 = coord_t(s1.points.size()); | ||||
|         auto i2s2 = coord_t(s1.points.size()) + steps - 1; | ||||
|         auto i2s2 = coord_t(s1.points.size()) + coord_t(steps) - 1; | ||||
| 
 | ||||
|         mesh.indices.emplace_back(i2s2, i2s1, i1s1); | ||||
|         mesh.indices.emplace_back(i1s2, i2s2, i1s1); | ||||
|  | @ -368,13 +369,13 @@ struct Pillar { | |||
|         } | ||||
| 
 | ||||
|         indices.reserve(2*steps); | ||||
|         auto offs = steps; | ||||
|         int offs = int(steps); | ||||
|         for(int i = 0; i < steps - 1; ++i) { | ||||
|             indices.emplace_back(i, i + offs, offs + i + 1); | ||||
|             indices.emplace_back(i, offs + i + 1, i + 1); | ||||
|         } | ||||
| 
 | ||||
|         auto last = steps - 1; | ||||
|         int last = int(steps) - 1; | ||||
|         indices.emplace_back(0, last, offs); | ||||
|         indices.emplace_back(last, offs + last, offs); | ||||
|     } | ||||
|  | @ -499,6 +500,27 @@ struct CompactBridge { | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| // A wrapper struct around the base pool (pad)
 | ||||
| struct Pad { | ||||
| //    Contour3D mesh;
 | ||||
|     TriangleMesh tmesh; | ||||
|     PoolConfig cfg; | ||||
|     double zlevel; | ||||
| 
 | ||||
|     Pad() {} | ||||
| 
 | ||||
|     Pad(const TriangleMesh& object_support_mesh, | ||||
|         double ground_level, | ||||
|         const PoolConfig& cfg) : zlevel(ground_level) | ||||
|     { | ||||
|         ExPolygons basep; | ||||
|         base_plate(object_support_mesh, basep); | ||||
|         create_base_pool(basep, tmesh, cfg); | ||||
|         tmesh.translate(0, 0, float(zlevel)); | ||||
|         std::cout << "pad ground level " << zlevel << std::endl; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| EigenMesh3D to_eigenmesh(const Contour3D& cntr) { | ||||
|     EigenMesh3D emesh; | ||||
| 
 | ||||
|  | @ -564,7 +586,11 @@ EigenMesh3D to_eigenmesh(const TriangleMesh& tmesh) { | |||
| } | ||||
| 
 | ||||
| EigenMesh3D to_eigenmesh(const ModelObject& modelobj) { | ||||
|     return to_eigenmesh(modelobj.raw_mesh()); | ||||
|     auto&& rmesh = modelobj.raw_mesh(); | ||||
|     auto&& ret = to_eigenmesh(rmesh); | ||||
|     auto&& bb = rmesh.bounding_box(); | ||||
|     ret.ground_level = bb.min(Z); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| EigenMesh3D to_eigenmesh(const Model& model) { | ||||
|  | @ -606,13 +632,12 @@ PointSet support_points(const Model& model) { | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| PointSet support_points(const ModelObject& modelobject, std::size_t instance_id) | ||||
| PointSet support_points(const ModelObject& modelobject) | ||||
| { | ||||
|     PointSet ret(modelobject.sla_support_points.size(), 3); | ||||
|     long i = 0; | ||||
|     ModelInstance *inst = modelobject.instances[instance_id]; | ||||
|     for(const Vec3f& msource : modelobject.sla_support_points) { | ||||
|         ret.row(i++) = model_coord(*inst, msource); | ||||
|         ret.row(i++) = msource.cast<double>(); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
|  | @ -643,12 +668,16 @@ class SLASupportTree::Impl { | |||
|     std::vector<Junction> m_junctions; | ||||
|     std::vector<Bridge> m_bridges; | ||||
|     std::vector<CompactBridge> m_compact_bridges; | ||||
|     Pad m_pad; | ||||
|     mutable TriangleMesh meshcache; mutable bool meshcache_valid; | ||||
|     mutable double model_height = 0; // the full height of the model
 | ||||
| public: | ||||
|     float model_height = 0; // the full height of the model
 | ||||
|     double ground_level = 0; | ||||
| 
 | ||||
|     template<class...Args> Head& add_head(Args&&... args) { | ||||
|         m_heads.emplace_back(std::forward<Args>(args)...); | ||||
|         m_heads.back().id = long(m_heads.size() - 1); | ||||
|         meshcache_valid = false; | ||||
|         return m_heads.back(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -661,6 +690,7 @@ public: | |||
|         head.pillar_id = pillar.id; | ||||
|         pillar.start_junction_id = head.id; | ||||
|         pillar.starts_from_head = true; | ||||
|         meshcache_valid = false; | ||||
|         return m_pillars.back(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -669,6 +699,7 @@ public: | |||
|         Pillar& p = m_pillars[pillar_id]; | ||||
|         assert(p.starts_from_head && p.start_junction_id > 0 && | ||||
|                p.start_junction_id < m_heads.size() ); | ||||
|         meshcache_valid = false; | ||||
|         return m_heads[p.start_junction_id]; | ||||
|     } | ||||
| 
 | ||||
|  | @ -676,18 +707,21 @@ public: | |||
|         assert(headid >= 0 && headid < m_heads.size()); | ||||
|         Head& h = m_heads[headid]; | ||||
|         assert(h.pillar_id > 0 && h.pillar_id < m_pillars.size()); | ||||
|         meshcache_valid = false; | ||||
|         return m_pillars[h.pillar_id]; | ||||
|     } | ||||
| 
 | ||||
|     template<class...Args> const Junction& add_junction(Args&&... args) { | ||||
|         m_junctions.emplace_back(std::forward<Args>(args)...); | ||||
|         m_junctions.back().id = long(m_junctions.size() - 1); | ||||
|         meshcache_valid = false; | ||||
|         return m_junctions.back(); | ||||
|     } | ||||
| 
 | ||||
|     template<class...Args> const Bridge& add_bridge(Args&&... args) { | ||||
|         m_bridges.emplace_back(std::forward<Args>(args)...); | ||||
|         m_bridges.back().id = long(m_bridges.size() - 1); | ||||
|         meshcache_valid = false; | ||||
|         return m_bridges.back(); | ||||
|     } | ||||
| 
 | ||||
|  | @ -695,17 +729,64 @@ public: | |||
|     const CompactBridge& add_compact_bridge(Args&&...args) { | ||||
|         m_compact_bridges.emplace_back(std::forward<Args>(args)...); | ||||
|         m_compact_bridges.back().id = long(m_compact_bridges.size() - 1); | ||||
|         meshcache_valid = false; | ||||
|         return m_compact_bridges.back(); | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<Head>& heads() const { return m_heads; } | ||||
|     Head& head(size_t idx) { return m_heads[idx]; } | ||||
|     Head& head(size_t idx) { meshcache_valid = false; return m_heads[idx]; } | ||||
|     const std::vector<Pillar>& pillars() const { return m_pillars; } | ||||
|     const std::vector<Bridge>& bridges() const { return m_bridges; } | ||||
|     const std::vector<Junction>& junctions() const { return m_junctions; } | ||||
|     const std::vector<CompactBridge>& compact_bridges() const { | ||||
|         return m_compact_bridges; | ||||
|     } | ||||
| 
 | ||||
|     const Pad& create_pad(const TriangleMesh& object_supports, | ||||
|                           const PoolConfig& cfg) { | ||||
|         m_pad = Pad(object_supports, ground_level, cfg); | ||||
|         return m_pad; | ||||
|     } | ||||
| 
 | ||||
|     const Pad& pad() const { return m_pad; } | ||||
| 
 | ||||
|     // WITHOUT THE PAD!!!
 | ||||
|     const TriangleMesh& merged_mesh() const { | ||||
|         if(meshcache_valid) return meshcache; | ||||
| 
 | ||||
|         meshcache = TriangleMesh(); | ||||
| 
 | ||||
|         for(auto& head : heads()) { | ||||
|             meshcache.merge(mesh(head.mesh)); | ||||
|         } | ||||
| 
 | ||||
|         for(auto& stick : pillars()) { | ||||
|             meshcache.merge(mesh(stick.mesh)); | ||||
|             meshcache.merge(mesh(stick.base)); | ||||
|         } | ||||
| 
 | ||||
|         for(auto& j : junctions()) { | ||||
|             meshcache.merge(mesh(j.mesh)); | ||||
|         } | ||||
| 
 | ||||
|         for(auto& cb : compact_bridges()) { | ||||
|             meshcache.merge(mesh(cb.mesh)); | ||||
|         } | ||||
| 
 | ||||
|         for(auto& bs : bridges()) { | ||||
|             meshcache.merge(mesh(bs.mesh)); | ||||
|         } | ||||
| 
 | ||||
|         BoundingBoxf3&& bb = meshcache.bounding_box(); | ||||
|         model_height = bb.max(Z); | ||||
| 
 | ||||
|         meshcache_valid = true; | ||||
|     } | ||||
| 
 | ||||
|     double full_height() const { | ||||
|         if(!meshcache_valid) merged_mesh(); | ||||
|         return model_height; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<class DistFn> | ||||
|  | @ -908,6 +989,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|     using Result = SLASupportTree::Impl; | ||||
| 
 | ||||
|     Result& result = *m_impl; | ||||
|     result.ground_level = mesh.ground_level; | ||||
| 
 | ||||
|     enum Steps { | ||||
|         BEGIN, | ||||
|  | @ -925,9 +1007,9 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|     }; | ||||
| 
 | ||||
|     // Debug:
 | ||||
|     for(int pn = 0; pn < points.rows(); ++pn) { | ||||
|         std::cout << "p " << pn << " " << points.row(pn) << std::endl; | ||||
|     } | ||||
|     // for(int pn = 0; pn < points.rows(); ++pn) {
 | ||||
|     //     std::cout << "p " << pn << " " << points.row(pn) << std::endl;
 | ||||
|     // }
 | ||||
| 
 | ||||
|     auto filterfn = [] ( | ||||
|             const SupportConfig& cfg, | ||||
|  | @ -1119,8 +1201,8 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|         const Head& phead = result.pillar_head(pillar.id); | ||||
|         const Head& nextphead = result.pillar_head(nextpillar.id); | ||||
| 
 | ||||
|         double d = 2*pillar.r; | ||||
|         const Vec3d& pp = pillar.endpoint.cwiseProduct(Vec3d{1, 1, 0}); | ||||
| //        double d = 2*pillar.r;
 | ||||
| //        const Vec3d& pp = pillar.endpoint.cwiseProduct(Vec3d{1, 1, 0});
 | ||||
| 
 | ||||
|         Vec3d sj = phead.junction_point(); | ||||
|         sj(Z) = std::min(sj(Z), nextphead.junction_point()(Z)); | ||||
|  | @ -1176,10 +1258,13 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|         const double hbr = cfg.head_back_radius_mm; | ||||
|         const double pradius = cfg.pillar_radius_mm; | ||||
|         const double maxbridgelen = cfg.max_bridge_length_mm; | ||||
|         const double gndlvl = emesh.ground_level - cfg.object_elevation_mm; | ||||
| 
 | ||||
|         ClusterEl cl_centroids; | ||||
|         cl_centroids.reserve(gnd_clusters.size()); | ||||
| 
 | ||||
|         std::cout << "gnd_clusters size: " << gnd_clusters.size() << std::endl; | ||||
| 
 | ||||
|         SpatIndex pheadindex; // spatial index for the junctions
 | ||||
|         for(auto cl : gnd_clusters) { | ||||
|             // place all the centroid head positions into the index. We will
 | ||||
|  | @ -1201,7 +1286,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|             unsigned hid = gndidx[cl[cid]]; // Head index
 | ||||
|             Head& h = result.head(hid); | ||||
|             h.transform(); | ||||
|             Vec3d p = h.junction_point(); p(Z) = 0; | ||||
|             Vec3d p = h.junction_point(); p(Z) = gndlvl; | ||||
| 
 | ||||
|             pheadindex.insert(p, hid); | ||||
|         } | ||||
|  | @ -1218,7 +1303,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|             auto& head = result.head(index_to_heads); | ||||
| 
 | ||||
|             Vec3d startpoint = head.junction_point(); | ||||
|             auto endpoint = startpoint; endpoint(Z) = 0; | ||||
|             auto endpoint = startpoint; endpoint(Z) = gndlvl; | ||||
| 
 | ||||
|             // Create the central pillar of the cluster with its base on the
 | ||||
|             // ground
 | ||||
|  | @ -1233,7 +1318,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|             // is distributed more effectively on the pillar.
 | ||||
| 
 | ||||
|             auto search_nearest = | ||||
|                     [&cfg, &result, &emesh, maxbridgelen] | ||||
|                     [&cfg, &result, &emesh, maxbridgelen, gndlvl] | ||||
|                     (SpatIndex& spindex, const Vec3d& jsh) | ||||
|             { | ||||
|                 long nearest_id = -1; | ||||
|  | @ -1244,7 +1329,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|                     // (this may happen as the clustering is not perfect)
 | ||||
|                     // than we will bridge to this closer pillar
 | ||||
| 
 | ||||
|                     Vec3d qp(jsh(X), jsh(Y), 0); | ||||
|                     Vec3d qp(jsh(X), jsh(Y), gndlvl); | ||||
|                     auto ne = spindex.nearest(qp, 1).front(); | ||||
|                     const Head& nearhead = result.heads()[ne.second]; | ||||
| 
 | ||||
|  | @ -1263,7 +1348,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|                     } | ||||
| 
 | ||||
|                     double d = distance(jp, jn); | ||||
|                     if(jn(Z) <= 0 || d > max_len) break; | ||||
|                     if(jn(Z) <= gndlvl || d > max_len) break; | ||||
| 
 | ||||
|                     double chkd = ray_mesh_intersect(jp, dirv(jp, jn), emesh); | ||||
|                     if(chkd >= d) nearest_id = ne.second; | ||||
|  | @ -1278,7 +1363,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|                 sidehead.transform(); | ||||
| 
 | ||||
|                 Vec3d jsh = sidehead.junction_point(); | ||||
|                 Vec3d jp2d = {jsh(X), jsh(Y), 0}; | ||||
| //                Vec3d jp2d = {jsh(X), jsh(Y), gndlvl};
 | ||||
|                 SpatIndex spindex = pheadindex; | ||||
|                 long nearest_id = search_nearest(spindex, jsh); | ||||
| 
 | ||||
|  | @ -1286,7 +1371,7 @@ bool SLASupportTree::generate(const PointSet &points, | |||
|                 // to connect the sidehead to the ground
 | ||||
|                 if(nearest_id < 0) { | ||||
|                     // Could not find a pillar, create one
 | ||||
|                     Vec3d jp = jsh; jp(Z) = 0; | ||||
|                     Vec3d jp = jsh; jp(Z) = gndlvl; | ||||
|                     result.add_pillar(sidehead.id, jp, pradius). | ||||
|                         add_base(cfg.base_height_mm, cfg.base_radius_mm); | ||||
| 
 | ||||
|  | @ -1571,28 +1656,12 @@ bool SLASupportTree::generate(const PointSet &points, | |||
| 
 | ||||
| void SLASupportTree::merged_mesh(TriangleMesh &outmesh) const | ||||
| { | ||||
|     const SLASupportTree::Impl& stree = get(); | ||||
|     outmesh.merge(get().merged_mesh()); | ||||
| } | ||||
| 
 | ||||
|     for(auto& head : stree.heads()) { | ||||
|         outmesh.merge(mesh(head.mesh)); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& stick : stree.pillars()) { | ||||
|         outmesh.merge(mesh(stick.mesh)); | ||||
|         outmesh.merge(mesh(stick.base)); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& j : stree.junctions()) { | ||||
|         outmesh.merge(mesh(j.mesh)); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& cb : stree.compact_bridges()) { | ||||
|         outmesh.merge(mesh(cb.mesh)); | ||||
|     } | ||||
| 
 | ||||
|     for(auto& bs : stree.bridges()) { | ||||
|         outmesh.merge(mesh(bs.mesh)); | ||||
|     } | ||||
| void SLASupportTree::merged_mesh_with_pad(TriangleMesh &outmesh) const { | ||||
|     merged_mesh(outmesh); | ||||
|     outmesh.merge(get_pad()); | ||||
| } | ||||
| 
 | ||||
| template<class T> void slice_part(const T& inp, | ||||
|  | @ -1616,7 +1685,7 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | |||
| { | ||||
|     if(init_layerh < 0) init_layerh = layerh; | ||||
|     auto& stree = get(); | ||||
|     const float modelh = stree.model_height; | ||||
|     const float modelh = stree.full_height(); | ||||
| 
 | ||||
|     std::vector<float> heights; heights.reserve(size_t(modelh/layerh) + 1); | ||||
|     for(float h = init_layerh; h <= modelh; h += layerh) { | ||||
|  | @ -1640,10 +1709,24 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | |||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| // Here we should implement the support editing
 | ||||
| void SLASupportTree::mouse_event(const MouseEvent &) | ||||
| const TriangleMesh &SLASupportTree::add_pad(double min_wall_thickness_mm, | ||||
|                                             double min_wall_height_mm, | ||||
|                                             double max_merge_distance_mm, | ||||
|                                             double edge_radius_mm) const | ||||
| { | ||||
|     TriangleMesh mm; | ||||
|     merged_mesh(mm); | ||||
|     PoolConfig pcfg; | ||||
| //    pcfg.min_wall_thickness_mm = min_wall_thickness_mm;
 | ||||
| //    pcfg.min_wall_height_mm    = min_wall_height_mm;
 | ||||
| //    pcfg.max_merge_distance_mm = max_merge_distance_mm;
 | ||||
| //    pcfg.edge_radius_mm        = edge_radius_mm;
 | ||||
|     return m_impl->create_pad(mm, pcfg).tmesh; | ||||
| } | ||||
| 
 | ||||
| const TriangleMesh &SLASupportTree::get_pad() const | ||||
| { | ||||
|     return m_impl->pad().tmesh; | ||||
| } | ||||
| 
 | ||||
| SLASupportTree::SLASupportTree(const Model& model, | ||||
|  |  | |||
|  | @ -60,6 +60,10 @@ struct SupportConfig { | |||
| 
 | ||||
|     // The max length of a bridge in mm
 | ||||
|     double max_bridge_length_mm = 15.0; | ||||
| 
 | ||||
|     // The elevation in Z direction upwards. This is the space between the pad
 | ||||
|     // and the model object's bounding box bottom.
 | ||||
|     double object_elevation_mm = 0; | ||||
| }; | ||||
| 
 | ||||
| /// A Control structure for the support calculation. Consists of the status
 | ||||
|  | @ -76,6 +80,7 @@ struct Controller { | |||
| struct EigenMesh3D { | ||||
|     Eigen::MatrixXd V; | ||||
|     Eigen::MatrixXi F; | ||||
|     double ground_level = 0; | ||||
| 
 | ||||
|     // igl crashes with the following data types:
 | ||||
| //    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::DontAlign> V;
 | ||||
|  | @ -100,7 +105,7 @@ EigenMesh3D to_eigenmesh(const Model& model); | |||
| EigenMesh3D to_eigenmesh(const ModelObject& model); | ||||
| 
 | ||||
| PointSet support_points(const Model& model); | ||||
| PointSet support_points(const ModelObject& modelobject, size_t instance_id = 0); | ||||
| PointSet support_points(const ModelObject& modelobject); | ||||
| 
 | ||||
| /* ************************************************************************** */ | ||||
| 
 | ||||
|  | @ -111,24 +116,10 @@ public: | |||
|     SLASupportsStoppedException(): std::runtime_error("") {} | ||||
| }; | ||||
| 
 | ||||
| /// A simple type carrying mouse event info. For support editing purposes
 | ||||
| struct MouseEvent { | ||||
|     enum Buttons { | ||||
|         M_RIGHT, M_LEFT, M_MIDDLE | ||||
|     } button; | ||||
| 
 | ||||
|     enum Type { | ||||
|         ENGAGE, RELEASE, MOVE | ||||
|     } type; | ||||
| 
 | ||||
|     Vec3d coords; | ||||
| }; | ||||
| 
 | ||||
| /// The class containing mesh data for the generated supports.
 | ||||
| class SLASupportTree { | ||||
|     class Impl; | ||||
|     std::unique_ptr<Impl> m_impl; | ||||
|     std::function<void()> m_vcallback; | ||||
| 
 | ||||
|     Impl& get() { return *m_impl; } | ||||
|     const Impl& get() const { return *m_impl; } | ||||
|  | @ -160,20 +151,23 @@ public: | |||
|     ~SLASupportTree(); | ||||
| 
 | ||||
|     /// Get the whole mesh united into the output TriangleMesh
 | ||||
|     /// WITHOUT THE PAD
 | ||||
|     void merged_mesh(TriangleMesh& outmesh) const; | ||||
| 
 | ||||
|     void merged_mesh_with_pad(TriangleMesh&) const; | ||||
| 
 | ||||
|     /// Get the sliced 2d layers of the support geometry.
 | ||||
|     SlicedSupports slice(float layerh, float init_layerh = -1.0) const; | ||||
| 
 | ||||
|     /// The function to call when mouse events should be propagated to the
 | ||||
|     /// supports for editing
 | ||||
|     void mouse_event(const MouseEvent&); | ||||
|     /// Adding the "pad" (base pool) under the supports
 | ||||
|     const TriangleMesh& add_pad(double min_wall_thickness_mm, | ||||
|                                 double min_wall_height_mm, | ||||
|                                 double max_merge_distance_mm, | ||||
|                                 double edge_radius_mm) const; | ||||
| 
 | ||||
|     /// Get the pad geometry
 | ||||
|     const TriangleMesh& get_pad() const; | ||||
| 
 | ||||
|     /// The provided callback will be called if the supports change their shape
 | ||||
|     /// or need to be repainted
 | ||||
|     inline void on_supports_changed(std::function<void()> callback) { | ||||
|         m_vcallback = callback; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -70,7 +70,7 @@ void SLAPrint::clear() | |||
| } | ||||
| 
 | ||||
| SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, | ||||
|                                       const DynamicPrintConfig &config) | ||||
|                                       const DynamicPrintConfig &config_in) | ||||
| { | ||||
| //	if (m_objects.empty())
 | ||||
| //		return APPLY_STATUS_UNCHANGED;
 | ||||
|  | @ -80,6 +80,11 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, | |||
|     if(m_objects.empty() && model.objects.empty()) | ||||
|         return APPLY_STATUS_UNCHANGED; | ||||
| 
 | ||||
|     // Temporary: just to have to correct layer height for the rasterization
 | ||||
|     DynamicPrintConfig config(config_in); | ||||
|     config.normalize(); | ||||
|     auto lh = config.opt<ConfigOptionFloat>("layer_height"); | ||||
| 
 | ||||
| 	// Temporary quick fix, just invalidate everything.
 | ||||
|     { | ||||
|         for (SLAPrintObject *print_object : m_objects) { | ||||
|  | @ -95,6 +100,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, | |||
|         // Generate new SLAPrintObjects.
 | ||||
|         for (ModelObject *model_object : m_model.objects) { | ||||
|             auto po = new SLAPrintObject(this, model_object); | ||||
|             po->m_config.layer_height.set(lh); | ||||
|             m_objects.emplace_back(po); | ||||
|             for (ModelInstance *oinst : model_object->instances) { | ||||
|                 Point tr = Point::new_scale(oinst->get_offset()(X), | ||||
|  | @ -138,7 +144,17 @@ void SLAPrint::process() | |||
|         slicer.slice(heights, &layers, [](){}); | ||||
|     }; | ||||
| 
 | ||||
|     auto support_points = [](SLAPrintObject&) { | ||||
|     auto support_points = [](SLAPrintObject& po) { | ||||
|         ModelObject& mo = *po.m_model_object; | ||||
|         if(!mo.sla_support_points.empty()) { | ||||
|             po.m_supportdata.reset(new SLAPrintObject::SupportData()); | ||||
|             po.m_supportdata->emesh = sla::to_eigenmesh(mo); | ||||
|             po.m_supportdata->support_points = sla::support_points(mo); | ||||
| 
 | ||||
|             std::cout << "support points copied " | ||||
|                       << po.m_supportdata->support_points.rows() << std::endl; | ||||
|         } | ||||
| 
 | ||||
|         // for(SLAPrintObject *po : pobjects) {
 | ||||
|             // TODO: calculate automatic support points
 | ||||
|             // po->m_supportdata->slice_cache contains the slices at this point
 | ||||
|  | @ -149,7 +165,6 @@ void SLAPrint::process() | |||
|     auto support_tree = [this](SLAPrintObject& po) { | ||||
|         auto& emesh = po.m_supportdata->emesh; | ||||
|         auto& pts = po.m_supportdata->support_points; // nowhere filled yet
 | ||||
|         auto& supportd = *po.m_supportdata; | ||||
|         try { | ||||
|             SupportConfig scfg;  //  TODO fill or replace with po.m_config
 | ||||
| 
 | ||||
|  | @ -161,7 +176,7 @@ void SLAPrint::process() | |||
|             }; | ||||
|             ctl.stopcondition = [this](){ return canceled(); }; | ||||
| 
 | ||||
|             supportd.support_tree_ptr.reset( | ||||
|              po.m_supportdata->support_tree_ptr.reset( | ||||
|                         new SLASupportTree(pts, emesh, scfg, ctl)); | ||||
| 
 | ||||
|         } catch(sla::SLASupportsStoppedException&) { | ||||
|  | @ -171,13 +186,32 @@ void SLAPrint::process() | |||
|     }; | ||||
| 
 | ||||
|     // This step generates the sla base pad
 | ||||
|     auto base_pool = [](SLAPrintObject&) { | ||||
|     auto base_pool = [](SLAPrintObject& po) { | ||||
|         // this step can only go after the support tree has been created
 | ||||
|         // and before the supports had been sliced. (or the slicing has to be
 | ||||
|         // repeated)
 | ||||
|         if(po.is_step_done(slaposSupportTree) && | ||||
|            po.m_supportdata && | ||||
|            po.m_supportdata->support_tree_ptr) | ||||
|         { | ||||
|             double wt = po.m_config.pad_wall_thickness.getFloat(); | ||||
|             double h =  po.m_config.pad_wall_height.getFloat(); | ||||
|             double md = po.m_config.pad_max_merge_distance.getFloat(); | ||||
|             double er = po.m_config.pad_edge_radius.getFloat(); | ||||
| 
 | ||||
|             po.m_supportdata->support_tree_ptr->add_pad(wt, h, md, er); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Slicing the support geometries similarly to the model slicing procedure
 | ||||
|     auto slice_supports = [](SLAPrintObject&) { | ||||
| 
 | ||||
|     // 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& sd = po.m_supportdata; | ||||
|         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); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // Rasterizing the model objects, and their supports
 | ||||
|  | @ -198,27 +232,47 @@ void SLAPrint::process() | |||
| 
 | ||||
|         // For all print objects, go through its initial layers and place them
 | ||||
|         // into the layers hash
 | ||||
|         long long initlyridx = static_cast<long long>(scale_(ilh)); | ||||
| //        long long initlyridx = static_cast<long long>(scale_(ilh));
 | ||||
|         for(SLAPrintObject *o : m_objects) { | ||||
|             auto& oslices = o->m_model_slices; | ||||
|             auto& firstlyr = oslices.front(); | ||||
|             auto& initlevel = levels[initlyridx]; | ||||
|             initlevel.emplace_back(firstlyr, o->m_instances); | ||||
| 
 | ||||
|             // now push the support slices as well
 | ||||
|             // TODO
 | ||||
| 
 | ||||
|             double lh = o->m_config.layer_height.getFloat(); | ||||
|             size_t li = 1; | ||||
|             for(auto lit = std::next(oslices.begin()); | ||||
|                 lit != oslices.end(); | ||||
|                 ++lit) | ||||
|             { | ||||
|                 double h = ilh + li++ * lh; | ||||
|             std::vector<ExPolygons> & oslices = o->m_model_slices; | ||||
|             for(int i = 0; i < oslices.size(); ++i) { | ||||
|                 double h = ilh + i * lh; | ||||
|                 long long lyridx = static_cast<long long>(scale_(h)); | ||||
|                 auto& lyrs = levels[lyridx]; | ||||
|                 lyrs.emplace_back(*lit, o->m_instances); | ||||
|                 auto& lyrs = levels[lyridx]; // this initializes a new record
 | ||||
|                 lyrs.emplace_back(oslices[i], o->m_instances); | ||||
|             } | ||||
| 
 | ||||
|             if(o->m_supportdata) { // deal with the support slices if present
 | ||||
|                 auto& sslices = o->m_supportdata->support_slices; | ||||
| 
 | ||||
|                 for(int i = 0; i < sslices.size(); ++i) { | ||||
|                     double h = ilh + i * lh; | ||||
|                     long long lyridx = static_cast<long long>(scale_(h)); | ||||
|                     auto& lyrs = levels[lyridx]; | ||||
|                     lyrs.emplace_back(sslices[i], o->m_instances); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| //            auto& oslices = o->m_model_slices;
 | ||||
| //            auto& firstlyr = oslices.front();
 | ||||
| //            auto& initlevel = levels[initlyridx];
 | ||||
| //            initlevel.emplace_back(firstlyr, o->m_instances);
 | ||||
| 
 | ||||
| //            // now push the support slices as well
 | ||||
| //            // TODO
 | ||||
| 
 | ||||
| //            double lh = o->m_config.layer_height.getFloat();
 | ||||
| //            size_t li = 1;
 | ||||
| //            for(auto lit = std::next(oslices.begin());
 | ||||
| //                lit != oslices.end();
 | ||||
| //                ++lit)
 | ||||
| //            {
 | ||||
| //                double h = ilh + li++ * lh;
 | ||||
| //                long long lyridx = static_cast<long long>(scale_(h));
 | ||||
| //                auto& lyrs = levels[lyridx];
 | ||||
| //                lyrs.emplace_back(*lit, o->m_instances);
 | ||||
| //            }
 | ||||
|         } | ||||
| 
 | ||||
|         // collect all the keys
 | ||||
|  | @ -244,10 +298,11 @@ void SLAPrint::process() | |||
| 
 | ||||
|         // Allocate space for all the layers
 | ||||
|         SLAPrinter& printer = *m_printer; | ||||
|         printer.layers(unsigned(levels.size())); | ||||
|         auto lvlcnt = unsigned(levels.size()); | ||||
|         printer.layers(lvlcnt); | ||||
| 
 | ||||
|         // procedure to process one height level. This will run in parallel
 | ||||
|         auto process_level = [&keys, &levels, &printer](unsigned level_id) { | ||||
|         auto lvlfn = [&keys, &levels, &printer](unsigned level_id) { | ||||
|             LayerRefs& lrange = levels[keys[level_id]]; | ||||
| 
 | ||||
|             for(auto& lyrref : lrange) { // for all layers in the current level
 | ||||
|  | @ -273,12 +328,10 @@ void SLAPrint::process() | |||
|         }; | ||||
| 
 | ||||
|         // Sequential version (for testing)
 | ||||
|         // for(unsigned l = 0; l < levels.size(); ++l) process_level(l);
 | ||||
|         // for(unsigned l = 0; l < lvlcnt; ++l) process_level(l);
 | ||||
| 
 | ||||
|         // Print all the layers in parallel
 | ||||
|         tbb::parallel_for<size_t, decltype(process_level)>(0, | ||||
|                                                            levels.size(), | ||||
|                                                            process_level); | ||||
|         tbb::parallel_for<unsigned, decltype(lvlfn)>(0, lvlcnt, lvlfn); | ||||
|     }; | ||||
| 
 | ||||
|     using slaposFn = std::function<void(SLAPrintObject&)>; | ||||
|  | @ -333,6 +386,9 @@ void SLAPrint::process() | |||
|         slapsRasterize, slapsValidate | ||||
|     }; | ||||
| 
 | ||||
|     // TODO: enable rasterizing
 | ||||
|      m_stepmask[slapsRasterize] = false; | ||||
| 
 | ||||
|     for(size_t s = 0; s < print_program.size(); ++s) { | ||||
|         auto currentstep = printsteps[s]; | ||||
| 
 | ||||
|  | @ -352,33 +408,39 @@ void SLAPrint::process() | |||
|     set_status(100, L("Slicing done")); | ||||
| } | ||||
| 
 | ||||
| void SLAPrint::render_supports(SLASupportRenderer &renderer) | ||||
| { | ||||
|     std::cout << "Would show the SLA supports" << std::endl; | ||||
| } | ||||
| 
 | ||||
| SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): | ||||
|     Inherited(print), | ||||
|     m_model_object(model_object), | ||||
|     m_supportdata(new SupportData()), | ||||
|     m_stepmask(slaposCount, true) | ||||
| { | ||||
|     m_supportdata->emesh = sla::to_eigenmesh(*m_model_object); | ||||
|     m_supportdata->support_points = sla::support_points(*m_model_object); | ||||
| 
 | ||||
|     std::cout << "support points copied " << m_supportdata->support_points.rows() << std::endl; | ||||
| } | ||||
| 
 | ||||
| SLAPrintObject::~SLAPrintObject() {} | ||||
| 
 | ||||
| TriangleMesh SLAPrintObject::support_mesh() const | ||||
| { | ||||
| 	return make_cube(10., 10., 10.); | ||||
|     TriangleMesh trm; | ||||
| 
 | ||||
|     if(m_supportdata && m_supportdata->support_tree_ptr) | ||||
|         m_supportdata->support_tree_ptr->merged_mesh(trm); | ||||
| 
 | ||||
|     trm.repair(); | ||||
| 
 | ||||
|     std::cout << "support mesh united and returned" << std::endl; | ||||
|     return trm; | ||||
| //    return make_cube(10., 10., 10.);
 | ||||
| } | ||||
| 
 | ||||
| TriangleMesh SLAPrintObject::pad_mesh() const | ||||
| { | ||||
| 	return make_cube(10., 10., 10.); | ||||
|     if(!m_supportdata || !m_supportdata->support_tree_ptr) { | ||||
|         std::cout << "Empty pad mesh returned.." << std::endl; | ||||
|         return TriangleMesh(); | ||||
|     } | ||||
| 
 | ||||
|     // FIXME: pad mesh is empty here for some reason.
 | ||||
|     return m_supportdata->support_tree_ptr->get_pad(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
|  |  | |||
|  | @ -98,33 +98,6 @@ using PrintObjects = std::vector<SLAPrintObject*>; | |||
| 
 | ||||
| class TriangleMesh; | ||||
| 
 | ||||
| class SLASupportRenderer { | ||||
| public: | ||||
| 
 | ||||
|     virtual ~SLASupportRenderer() {} | ||||
| 
 | ||||
|     enum Buttons { | ||||
|         LEFT, RIGHT, MIDDLE | ||||
|     }; | ||||
| 
 | ||||
|     enum MType { | ||||
|         ENGAGE, RELEASE, HOVER | ||||
|     }; | ||||
| 
 | ||||
|     struct MouseEvt { | ||||
|         Buttons button; MType type; | ||||
|     }; | ||||
| 
 | ||||
|     using ClickCb = std::function<void(MouseEvt)>; | ||||
|     using Mesh = TriangleMesh; | ||||
| 
 | ||||
|     virtual void add_pillar(const Mesh&, ClickCb on_mouse_evt) = 0; | ||||
|     virtual void add_head(const Mesh&, ClickCb on_mouse_evt) = 0; | ||||
|     virtual void add_bridge(const Mesh&, ClickCb on_mouse_evt) = 0; | ||||
|     virtual void add_junction(const Mesh&, ClickCb on_mouse_evt) = 0; | ||||
|     virtual void add_pad(const Mesh&, ClickCb on_mouse_evt) = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief This class is the high level FSM for the SLA printing process. | ||||
|  * | ||||
|  | @ -156,11 +129,8 @@ public: | |||
|     ApplyStatus         apply(const Model &model, const DynamicPrintConfig &config) override; | ||||
|     void                process() override; | ||||
| 
 | ||||
|     void                render_supports(SLASupportRenderer& renderer); | ||||
| 
 | ||||
|     template<class Fmt> void export_raster(const std::string& fname) { | ||||
|         if(m_printer) m_printer->save<Fmt>(fname); | ||||
|         std::cout << "Would export the SLA raster" << std::endl; | ||||
|     } | ||||
|     const PrintObjects& objects() const { return m_objects; } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1871,8 +1871,21 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) | |||
|     case ptSLA: | ||||
|         // Update the SLAPrint from the current Model, so that the reload_scene()
 | ||||
|         // pulls the correct data.
 | ||||
|         if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART) | ||||
|             this->schedule_background_process(); | ||||
| //        if (this->update_background_process() & UPDATE_BACKGROUND_PROCESS_RESTART)
 | ||||
| //            this->schedule_background_process();
 | ||||
| 
 | ||||
|         { | ||||
| //        for(SLAPrintObject * po: sla_print.objects()) {
 | ||||
| //            TriangleMesh&& suppmesh = po->support_mesh();
 | ||||
| //            if(suppmesh.facets_count() > 0) {
 | ||||
| //                ModelObject* mo = model.add_object();
 | ||||
| //                for(const SLAPrintObject::Instance& inst : po->instances() ) {
 | ||||
| //                    mo->add_instance(*(mo->instances[inst.instance_id.id]));
 | ||||
| //                    mo->add_volume(suppmesh);
 | ||||
| //                }
 | ||||
| //            }
 | ||||
| //        }
 | ||||
|         } | ||||
|         _3DScene::reload_scene(canvas3D, true); | ||||
|         break; | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tamasmeszaros
						tamasmeszaros