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