1 #define NOMINMAX
2 
3 #include <libslic3r/SLA/SupportTreeBuilder.hpp>
4 #include <libslic3r/SLA/SupportTreeBuildsteps.hpp>
5 #include <libslic3r/SLA/SupportTreeMesher.hpp>
6 #include <libslic3r/SLA/Contour3D.hpp>
7 
8 namespace Slic3r {
9 namespace sla {
10 
Head(double r_big_mm,double r_small_mm,double length_mm,double penetration,const Vec3d & direction,const Vec3d & offset)11 Head::Head(double       r_big_mm,
12            double       r_small_mm,
13            double       length_mm,
14            double       penetration,
15            const Vec3d &direction,
16            const Vec3d &offset)
17     : dir(direction)
18     , pos(offset)
19     , r_back_mm(r_big_mm)
20     , r_pin_mm(r_small_mm)
21     , width_mm(length_mm)
22     , penetration_mm(penetration)
23 {
24 }
25 
Pad(const TriangleMesh & support_mesh,const ExPolygons & model_contours,double ground_level,const PadConfig & pcfg,ThrowOnCancel thr)26 Pad::Pad(const TriangleMesh &support_mesh,
27          const ExPolygons &  model_contours,
28          double              ground_level,
29          const PadConfig &   pcfg,
30          ThrowOnCancel       thr)
31     : cfg(pcfg)
32     , zlevel(ground_level + pcfg.full_height() - pcfg.required_elevation())
33 {
34     thr();
35 
36     ExPolygons sup_contours;
37 
38     float zstart = float(zlevel);
39     float zend   = zstart + float(pcfg.full_height() + EPSILON);
40 
41     pad_blueprint(support_mesh, sup_contours, grid(zstart, zend, 0.1f), thr);
42     create_pad(sup_contours, model_contours, tmesh, pcfg);
43 
44     tmesh.translate(0, 0, float(zlevel));
45     if (!tmesh.empty()) tmesh.require_shared_vertices();
46 }
47 
add_pad(const ExPolygons & modelbase,const PadConfig & cfg)48 const TriangleMesh &SupportTreeBuilder::add_pad(const ExPolygons &modelbase,
49                                                 const PadConfig & cfg)
50 {
51     m_pad = Pad{merged_mesh(), modelbase, ground_level, cfg, ctl().cancelfn};
52     return m_pad.tmesh;
53 }
54 
SupportTreeBuilder(SupportTreeBuilder && o)55 SupportTreeBuilder::SupportTreeBuilder(SupportTreeBuilder &&o)
56     : m_heads(std::move(o.m_heads))
57     , m_head_indices{std::move(o.m_head_indices)}
58     , m_pillars{std::move(o.m_pillars)}
59     , m_bridges{std::move(o.m_bridges)}
60     , m_crossbridges{std::move(o.m_crossbridges)}
61     , m_pad{std::move(o.m_pad)}
62     , m_meshcache{std::move(o.m_meshcache)}
63     , m_meshcache_valid{o.m_meshcache_valid}
64     , m_model_height{o.m_model_height}
65     , ground_level{o.ground_level}
66 {}
67 
SupportTreeBuilder(const SupportTreeBuilder & o)68 SupportTreeBuilder::SupportTreeBuilder(const SupportTreeBuilder &o)
69     : m_heads(o.m_heads)
70     , m_head_indices{o.m_head_indices}
71     , m_pillars{o.m_pillars}
72     , m_bridges{o.m_bridges}
73     , m_crossbridges{o.m_crossbridges}
74     , m_pad{o.m_pad}
75     , m_meshcache{o.m_meshcache}
76     , m_meshcache_valid{o.m_meshcache_valid}
77     , m_model_height{o.m_model_height}
78     , ground_level{o.ground_level}
79 {}
80 
operator =(SupportTreeBuilder && o)81 SupportTreeBuilder &SupportTreeBuilder::operator=(SupportTreeBuilder &&o)
82 {
83     m_heads = std::move(o.m_heads);
84     m_head_indices = std::move(o.m_head_indices);
85     m_pillars = std::move(o.m_pillars);
86     m_bridges = std::move(o.m_bridges);
87     m_crossbridges = std::move(o.m_crossbridges);
88     m_pad = std::move(o.m_pad);
89     m_meshcache = std::move(o.m_meshcache);
90     m_meshcache_valid = o.m_meshcache_valid;
91     m_model_height = o.m_model_height;
92     ground_level = o.ground_level;
93     return *this;
94 }
95 
operator =(const SupportTreeBuilder & o)96 SupportTreeBuilder &SupportTreeBuilder::operator=(const SupportTreeBuilder &o)
97 {
98     m_heads = o.m_heads;
99     m_head_indices = o.m_head_indices;
100     m_pillars = o.m_pillars;
101     m_bridges = o.m_bridges;
102     m_crossbridges = o.m_crossbridges;
103     m_pad = o.m_pad;
104     m_meshcache = o.m_meshcache;
105     m_meshcache_valid = o.m_meshcache_valid;
106     m_model_height = o.m_model_height;
107     ground_level = o.ground_level;
108     return *this;
109 }
110 
add_pillar_base(long pid,double baseheight,double radius)111 void SupportTreeBuilder::add_pillar_base(long pid, double baseheight, double radius)
112 {
113     std::lock_guard<Mutex> lk(m_mutex);
114     assert(pid >= 0 && size_t(pid) < m_pillars.size());
115     Pillar& pll = m_pillars[size_t(pid)];
116     m_pedestals.emplace_back(pll.endpt, std::min(baseheight, pll.height),
117                              std::max(radius, pll.r), pll.r);
118 
119     m_pedestals.back().id = m_pedestals.size() - 1;
120     m_meshcache_valid = false;
121 }
122 
merged_mesh(size_t steps) const123 const TriangleMesh &SupportTreeBuilder::merged_mesh(size_t steps) const
124 {
125     if (m_meshcache_valid) return m_meshcache;
126 
127     Contour3D merged;
128 
129     for (auto &head : m_heads) {
130         if (ctl().stopcondition()) break;
131         if (head.is_valid()) merged.merge(get_mesh(head, steps));
132     }
133 
134     for (auto &pill : m_pillars) {
135         if (ctl().stopcondition()) break;
136         merged.merge(get_mesh(pill, steps));
137     }
138 
139     for (auto &pedest : m_pedestals) {
140         if (ctl().stopcondition()) break;
141         merged.merge(get_mesh(pedest, steps));
142     }
143 
144     for (auto &j : m_junctions) {
145         if (ctl().stopcondition()) break;
146         merged.merge(get_mesh(j, steps));
147     }
148 
149     for (auto &bs : m_bridges) {
150         if (ctl().stopcondition()) break;
151         merged.merge(get_mesh(bs, steps));
152     }
153 
154     for (auto &bs : m_crossbridges) {
155         if (ctl().stopcondition()) break;
156         merged.merge(get_mesh(bs, steps));
157     }
158 
159     for (auto &bs : m_diffbridges) {
160         if (ctl().stopcondition()) break;
161         merged.merge(get_mesh(bs, steps));
162     }
163 
164     for (auto &anch : m_anchors) {
165         if (ctl().stopcondition()) break;
166         merged.merge(get_mesh(anch, steps));
167     }
168 
169     if (ctl().stopcondition()) {
170         // In case of failure we have to return an empty mesh
171         m_meshcache = TriangleMesh();
172         return m_meshcache;
173     }
174 
175     m_meshcache = to_triangle_mesh(merged);
176 
177     // The mesh will be passed by const-pointer to TriangleMeshSlicer,
178     // which will need this.
179     if (!m_meshcache.empty()) m_meshcache.require_shared_vertices();
180 
181     BoundingBoxf3 &&bb = m_meshcache.bounding_box();
182     m_model_height       = bb.max(Z) - bb.min(Z);
183 
184     m_meshcache_valid = true;
185     return m_meshcache;
186 }
187 
full_height() const188 double SupportTreeBuilder::full_height() const
189 {
190     if (merged_mesh().empty() && !pad().empty())
191         return pad().cfg.full_height();
192 
193     double h = mesh_height();
194     if (!pad().empty()) h += pad().cfg.required_elevation();
195     return h;
196 }
197 
merge_and_cleanup()198 const TriangleMesh &SupportTreeBuilder::merge_and_cleanup()
199 {
200     // in case the mesh is not generated, it should be...
201     auto &ret = merged_mesh();
202 
203     // Doing clear() does not garantee to release the memory.
204     m_heads = {};
205     m_head_indices = {};
206     m_pillars = {};
207     m_junctions = {};
208     m_bridges = {};
209 
210     return ret;
211 }
212 
retrieve_mesh(MeshType meshtype) const213 const TriangleMesh &SupportTreeBuilder::retrieve_mesh(MeshType meshtype) const
214 {
215     switch(meshtype) {
216     case MeshType::Support: return merged_mesh();
217     case MeshType::Pad:     return pad().tmesh;
218     }
219 
220     return m_meshcache;
221 }
222 
223 }} // namespace Slic3r::sla
224