Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libslic3r/SLA/SupportTreeBuilder.cpp')
-rw-r--r--src/libslic3r/SLA/SupportTreeBuilder.cpp387
1 files changed, 42 insertions, 345 deletions
diff --git a/src/libslic3r/SLA/SupportTreeBuilder.cpp b/src/libslic3r/SLA/SupportTreeBuilder.cpp
index d385e98a2..daa01ef24 100644
--- a/src/libslic3r/SLA/SupportTreeBuilder.cpp
+++ b/src/libslic3r/SLA/SupportTreeBuilder.cpp
@@ -1,338 +1,26 @@
+#define NOMINMAX
+
#include <libslic3r/SLA/SupportTreeBuilder.hpp>
#include <libslic3r/SLA/SupportTreeBuildsteps.hpp>
+#include <libslic3r/SLA/SupportTreeMesher.hpp>
#include <libslic3r/SLA/Contour3D.hpp>
namespace Slic3r {
namespace sla {
-Contour3D sphere(double rho, Portion portion, double fa) {
-
- Contour3D ret;
-
- // prohibit close to zero radius
- if(rho <= 1e-6 && rho >= -1e-6) return ret;
-
- auto& vertices = ret.points;
- auto& facets = ret.faces3;
-
- // Algorithm:
- // Add points one-by-one to the sphere grid and form facets using relative
- // coordinates. Sphere is composed effectively of a mesh of stacked circles.
-
- // adjust via rounding to get an even multiple for any provided angle.
- double angle = (2*PI / floor(2*PI / fa));
-
- // Ring to be scaled to generate the steps of the sphere
- std::vector<double> ring;
-
- for (double i = 0; i < 2*PI; i+=angle) ring.emplace_back(i);
-
- const auto sbegin = size_t(2*std::get<0>(portion)/angle);
- const auto send = size_t(2*std::get<1>(portion)/angle);
-
- const size_t steps = ring.size();
- const double increment = 1.0 / double(steps);
-
- // special case: first ring connects to 0,0,0
- // insert and form facets.
- if(sbegin == 0)
- vertices.emplace_back(Vec3d(0.0, 0.0, -rho + increment*sbegin*2.0*rho));
-
- auto id = coord_t(vertices.size());
- for (size_t i = 0; i < ring.size(); i++) {
- // Fixed scaling
- const double z = -rho + increment*rho*2.0 * (sbegin + 1.0);
- // radius of the circle for this step.
- const double r = std::sqrt(std::abs(rho*rho - z*z));
- Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
- vertices.emplace_back(Vec3d(b(0), b(1), z));
-
- if (sbegin == 0)
- facets.emplace_back((i == 0) ?
- Vec3crd(coord_t(ring.size()), 0, 1) :
- Vec3crd(id - 1, 0, id));
- ++id;
- }
-
- // General case: insert and form facets for each step,
- // joining it to the ring below it.
- for (size_t s = sbegin + 2; s < send - 1; s++) {
- const double z = -rho + increment*double(s*2.0*rho);
- const double r = std::sqrt(std::abs(rho*rho - z*z));
-
- for (size_t i = 0; i < ring.size(); i++) {
- Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
- vertices.emplace_back(Vec3d(b(0), b(1), z));
- auto id_ringsize = coord_t(id - int(ring.size()));
- if (i == 0) {
- // wrap around
- facets.emplace_back(Vec3crd(id - 1, id,
- id + coord_t(ring.size() - 1)));
- facets.emplace_back(Vec3crd(id - 1, id_ringsize, id));
- } else {
- facets.emplace_back(Vec3crd(id_ringsize - 1, id_ringsize, id));
- facets.emplace_back(Vec3crd(id - 1, id_ringsize - 1, id));
- }
- id++;
- }
- }
-
- // special case: last ring connects to 0,0,rho*2.0
- // only form facets.
- if(send >= size_t(2*PI / angle)) {
- vertices.emplace_back(Vec3d(0.0, 0.0, -rho + increment*send*2.0*rho));
- for (size_t i = 0; i < ring.size(); i++) {
- auto id_ringsize = coord_t(id - int(ring.size()));
- if (i == 0) {
- // third vertex is on the other side of the ring.
- facets.emplace_back(Vec3crd(id - 1, id_ringsize, id));
- } else {
- auto ci = coord_t(id_ringsize + coord_t(i));
- facets.emplace_back(Vec3crd(ci - 1, ci, id));
- }
- }
- }
- id++;
-
- return ret;
-}
-
-Contour3D cylinder(double r, double h, size_t ssteps, const Vec3d &sp)
-{
- Contour3D ret;
-
- auto steps = int(ssteps);
- auto& points = ret.points;
- auto& indices = ret.faces3;
- points.reserve(2*ssteps);
- double a = 2*PI/steps;
-
- Vec3d jp = sp;
- Vec3d endp = {sp(X), sp(Y), sp(Z) + h};
-
- // Upper circle points
- for(int i = 0; i < steps; ++i) {
- double phi = i*a;
- double ex = endp(X) + r*std::cos(phi);
- double ey = endp(Y) + r*std::sin(phi);
- points.emplace_back(ex, ey, endp(Z));
- }
-
- // Lower circle points
- for(int i = 0; i < steps; ++i) {
- double phi = i*a;
- double x = jp(X) + r*std::cos(phi);
- double y = jp(Y) + r*std::sin(phi);
- points.emplace_back(x, y, jp(Z));
- }
-
- // Now create long triangles connecting upper and lower circles
- indices.reserve(2*ssteps);
- auto offs = 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);
- }
-
- // Last triangle connecting the first and last vertices
- auto last = steps - 1;
- indices.emplace_back(0, last, offs);
- indices.emplace_back(last, offs + last, offs);
-
- // According to the slicing algorithms, we need to aid them with generating
- // a watertight body. So we create a triangle fan for the upper and lower
- // ending of the cylinder to close the geometry.
- points.emplace_back(jp); int ci = int(points.size() - 1);
- for(int i = 0; i < steps - 1; ++i)
- indices.emplace_back(i + offs + 1, i + offs, ci);
-
- indices.emplace_back(offs, steps + offs - 1, ci);
-
- points.emplace_back(endp); ci = int(points.size() - 1);
- for(int i = 0; i < steps - 1; ++i)
- indices.emplace_back(ci, i, i + 1);
-
- indices.emplace_back(steps - 1, 0, ci);
-
- return ret;
-}
-
Head::Head(double r_big_mm,
double r_small_mm,
double length_mm,
double penetration,
const Vec3d &direction,
- const Vec3d &offset,
- const size_t circlesteps)
- : steps(circlesteps)
- , dir(direction)
- , tr(offset)
+ const Vec3d &offset)
+ : dir(direction)
+ , pos(offset)
, r_back_mm(r_big_mm)
, r_pin_mm(r_small_mm)
, width_mm(length_mm)
, penetration_mm(penetration)
{
- assert(width_mm > 0.);
- assert(r_back_mm > 0.);
- assert(r_pin_mm > 0.);
-
- // We create two spheres which will be connected with a robe that fits
- // both circles perfectly.
-
- // Set up the model detail level
- const double detail = 2*PI/steps;
-
- // We don't generate whole circles. Instead, we generate only the
- // portions which are visible (not covered by the robe) To know the
- // exact portion of the bottom and top circles we need to use some
- // rules of tangent circles from which we can derive (using simple
- // triangles the following relations:
-
- // The height of the whole mesh
- const double h = r_big_mm + r_small_mm + width_mm;
- double phi = PI/2 - std::acos( (r_big_mm - r_small_mm) / h );
-
- // To generate a whole circle we would pass a portion of (0, Pi)
- // To generate only a half horizontal circle we can pass (0, Pi/2)
- // The calculated phi is an offset to the half circles needed to smooth
- // the transition from the circle to the robe geometry
-
- auto&& s1 = sphere(r_big_mm, make_portion(0, PI/2 + phi), detail);
- auto&& s2 = sphere(r_small_mm, make_portion(PI/2 + phi, PI), detail);
-
- for(auto& p : s2.points) p.z() += h;
-
- mesh.merge(s1);
- mesh.merge(s2);
-
- for(size_t idx1 = s1.points.size() - steps, idx2 = s1.points.size();
- idx1 < s1.points.size() - 1;
- idx1++, idx2++)
- {
- coord_t i1s1 = coord_t(idx1), i1s2 = coord_t(idx2);
- coord_t i2s1 = i1s1 + 1, i2s2 = i1s2 + 1;
-
- mesh.faces3.emplace_back(i1s1, i2s1, i2s2);
- mesh.faces3.emplace_back(i1s1, i2s2, i1s2);
- }
-
- 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()) + coord_t(steps) - 1;
-
- mesh.faces3.emplace_back(i2s2, i2s1, i1s1);
- mesh.faces3.emplace_back(i1s2, i2s2, i1s1);
-
- // To simplify further processing, we translate the mesh so that the
- // last vertex of the pointing sphere (the pinpoint) will be at (0,0,0)
- for(auto& p : mesh.points) p.z() -= (h + r_small_mm - penetration_mm);
-}
-
-Pillar::Pillar(const Vec3d &jp, const Vec3d &endp, double radius, size_t st):
- r(radius), steps(st), endpt(endp), starts_from_head(false)
-{
- assert(steps > 0);
-
- height = jp(Z) - endp(Z);
- if(height > EPSILON) { // Endpoint is below the starting point
-
- // We just create a bridge geometry with the pillar parameters and
- // move the data.
- Contour3D body = cylinder(radius, height, st, endp);
- mesh.points.swap(body.points);
- mesh.faces3.swap(body.faces3);
- }
-}
-
-Pillar &Pillar::add_base(double baseheight, double radius)
-{
- if(baseheight <= 0) return *this;
- if(baseheight > height) baseheight = height;
-
- assert(steps >= 0);
- auto last = int(steps - 1);
-
- if(radius < r ) radius = r;
-
- double a = 2*PI/steps;
- double z = endpt(Z) + baseheight;
-
- for(size_t i = 0; i < steps; ++i) {
- double phi = i*a;
- double x = endpt(X) + r*std::cos(phi);
- double y = endpt(Y) + r*std::sin(phi);
- base.points.emplace_back(x, y, z);
- }
-
- for(size_t i = 0; i < steps; ++i) {
- double phi = i*a;
- double x = endpt(X) + radius*std::cos(phi);
- double y = endpt(Y) + radius*std::sin(phi);
- base.points.emplace_back(x, y, z - baseheight);
- }
-
- auto ep = endpt; ep(Z) += baseheight;
- base.points.emplace_back(endpt);
- base.points.emplace_back(ep);
-
- auto& indices = base.faces3;
- auto hcenter = int(base.points.size() - 1);
- auto lcenter = int(base.points.size() - 2);
- auto offs = int(steps);
- for(int i = 0; i < last; ++i) {
- indices.emplace_back(i, i + offs, offs + i + 1);
- indices.emplace_back(i, offs + i + 1, i + 1);
- indices.emplace_back(i, i + 1, hcenter);
- indices.emplace_back(lcenter, offs + i + 1, offs + i);
- }
-
- indices.emplace_back(0, last, offs);
- indices.emplace_back(last, offs + last, offs);
- indices.emplace_back(hcenter, last, 0);
- indices.emplace_back(offs, offs + last, lcenter);
- return *this;
-}
-
-Bridge::Bridge(const Vec3d &j1, const Vec3d &j2, double r_mm, size_t steps):
- r(r_mm), startp(j1), endp(j2)
-{
- using Quaternion = Eigen::Quaternion<double>;
- Vec3d dir = (j2 - j1).normalized();
- double d = distance(j2, j1);
-
- mesh = cylinder(r, d, steps);
-
- auto quater = Quaternion::FromTwoVectors(Vec3d{0,0,1}, dir);
- for(auto& p : mesh.points) p = quater * p + j1;
-}
-
-CompactBridge::CompactBridge(const Vec3d &sp,
- const Vec3d &ep,
- const Vec3d &n,
- double r,
- bool endball,
- size_t steps)
-{
- Vec3d startp = sp + r * n;
- Vec3d dir = (ep - startp).normalized();
- Vec3d endp = ep - r * dir;
-
- Bridge br(startp, endp, r, steps);
- mesh.merge(br.mesh);
-
- // now add the pins
- double fa = 2*PI/steps;
- auto upperball = sphere(r, Portion{PI / 2 - fa, PI}, fa);
- for(auto& p : upperball.points) p += startp;
-
- if(endball) {
- auto lowerball = sphere(r, Portion{0, PI/2 + 2*fa}, fa);
- for(auto& p : lowerball.points) p += endp;
- mesh.merge(lowerball);
- }
-
- mesh.merge(upperball);
}
Pad::Pad(const TriangleMesh &support_mesh,
@@ -370,7 +58,6 @@ SupportTreeBuilder::SupportTreeBuilder(SupportTreeBuilder &&o)
, m_pillars{std::move(o.m_pillars)}
, m_bridges{std::move(o.m_bridges)}
, m_crossbridges{std::move(o.m_crossbridges)}
- , m_compact_bridges{std::move(o.m_compact_bridges)}
, m_pad{std::move(o.m_pad)}
, m_meshcache{std::move(o.m_meshcache)}
, m_meshcache_valid{o.m_meshcache_valid}
@@ -384,7 +71,6 @@ SupportTreeBuilder::SupportTreeBuilder(const SupportTreeBuilder &o)
, m_pillars{o.m_pillars}
, m_bridges{o.m_bridges}
, m_crossbridges{o.m_crossbridges}
- , m_compact_bridges{o.m_compact_bridges}
, m_pad{o.m_pad}
, m_meshcache{o.m_meshcache}
, m_meshcache_valid{o.m_meshcache_valid}
@@ -399,7 +85,6 @@ SupportTreeBuilder &SupportTreeBuilder::operator=(SupportTreeBuilder &&o)
m_pillars = std::move(o.m_pillars);
m_bridges = std::move(o.m_bridges);
m_crossbridges = std::move(o.m_crossbridges);
- m_compact_bridges = std::move(o.m_compact_bridges);
m_pad = std::move(o.m_pad);
m_meshcache = std::move(o.m_meshcache);
m_meshcache_valid = o.m_meshcache_valid;
@@ -415,7 +100,6 @@ SupportTreeBuilder &SupportTreeBuilder::operator=(const SupportTreeBuilder &o)
m_pillars = o.m_pillars;
m_bridges = o.m_bridges;
m_crossbridges = o.m_crossbridges;
- m_compact_bridges = o.m_compact_bridges;
m_pad = o.m_pad;
m_meshcache = o.m_meshcache;
m_meshcache_valid = o.m_meshcache_valid;
@@ -424,7 +108,19 @@ SupportTreeBuilder &SupportTreeBuilder::operator=(const SupportTreeBuilder &o)
return *this;
}
-const TriangleMesh &SupportTreeBuilder::merged_mesh() const
+void SupportTreeBuilder::add_pillar_base(long pid, double baseheight, double radius)
+{
+ std::lock_guard<Mutex> lk(m_mutex);
+ assert(pid >= 0 && size_t(pid) < m_pillars.size());
+ Pillar& pll = m_pillars[size_t(pid)];
+ m_pedestals.emplace_back(pll.endpt, std::min(baseheight, pll.height),
+ std::max(radius, pll.r), pll.r);
+
+ m_pedestals.back().id = m_pedestals.size() - 1;
+ m_meshcache_valid = false;
+}
+
+const TriangleMesh &SupportTreeBuilder::merged_mesh(size_t steps) const
{
if (m_meshcache_valid) return m_meshcache;
@@ -432,35 +128,44 @@ const TriangleMesh &SupportTreeBuilder::merged_mesh() const
for (auto &head : m_heads) {
if (ctl().stopcondition()) break;
- if (head.is_valid()) merged.merge(head.mesh);
+ if (head.is_valid()) merged.merge(get_mesh(head, steps));
}
- for (auto &stick : m_pillars) {
+ for (auto &pill : m_pillars) {
if (ctl().stopcondition()) break;
- merged.merge(stick.mesh);
- merged.merge(stick.base);
+ merged.merge(get_mesh(pill, steps));
}
-
- for (auto &j : m_junctions) {
+
+ for (auto &pedest : m_pedestals) {
if (ctl().stopcondition()) break;
- merged.merge(j.mesh);
+ merged.merge(get_mesh(pedest, steps));
}
- for (auto &cb : m_compact_bridges) {
+ for (auto &j : m_junctions) {
if (ctl().stopcondition()) break;
- merged.merge(cb.mesh);
+ merged.merge(get_mesh(j, steps));
}
-
+
for (auto &bs : m_bridges) {
if (ctl().stopcondition()) break;
- merged.merge(bs.mesh);
+ merged.merge(get_mesh(bs, steps));
}
for (auto &bs : m_crossbridges) {
if (ctl().stopcondition()) break;
- merged.merge(bs.mesh);
+ merged.merge(get_mesh(bs, steps));
}
-
+
+ for (auto &bs : m_diffbridges) {
+ if (ctl().stopcondition()) break;
+ merged.merge(get_mesh(bs, steps));
+ }
+
+ for (auto &anch : m_anchors) {
+ if (ctl().stopcondition()) break;
+ merged.merge(get_mesh(anch, steps));
+ }
+
if (ctl().stopcondition()) {
// In case of failure we have to return an empty mesh
m_meshcache = TriangleMesh();
@@ -501,7 +206,6 @@ const TriangleMesh &SupportTreeBuilder::merge_and_cleanup()
m_pillars = {};
m_junctions = {};
m_bridges = {};
- m_compact_bridges = {};
return ret;
}
@@ -516,11 +220,4 @@ const TriangleMesh &SupportTreeBuilder::retrieve_mesh(MeshType meshtype) const
return m_meshcache;
}
-bool SupportTreeBuilder::build(const SupportableMesh &sm)
-{
- ground_level = sm.emesh.ground_level() - sm.cfg.object_elevation_mm;
- return SupportTreeBuildsteps::execute(*this, sm);
-}
-
-}
-}
+}} // namespace Slic3r::sla