OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::sla Namespace Reference

Namespaces

namespace  anonymous_namespace{Clustering.cpp}
namespace  anonymous_namespace{Pad.cpp}
namespace  anonymous_namespace{Rotfinder.cpp}

Classes

struct  Colors
class  AGGRaster
class  RasterGrayscaleAA
class  RasterGrayscaleAAGammaPower
class  ConcaveHull
 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...). More...
struct  _ccr
struct  _ccr< true >
struct  _ccr< false >
struct  Interior
struct  TriangleBubble
struct  DivFace
struct  HollowingConfig
struct  InteriorDeleter
struct  DrainHole
class  IndexedMesh
 An index-triangle structure for libIGL functions. Also serves as an alternative (raw) input format for the SLASupportTree. More...
struct  JobController
 A Control structure for the support calculation. Consists of the status indicator callback and the stop condition predicate. More...
struct  PadConfig
class  EncodedRaster
struct  Resolution
 Type that represents a resolution in pixels. More...
struct  PixelDim
 Types that represents the dimension of a pixel in millimeters. More...
class  RasterBase
struct  PNGRasterEncoder
struct  PPMRasterEncoder
struct  RotfinderBoilerplate
class  RotOptimizeParams
class  PointIndex
class  BoxIndex
struct  SupportPoint
class  SupportPointGenerator
struct  SupportTreeConfig
struct  SupportableMesh
class  SupportTree
 The class containing mesh data for the generated supports. More...
struct  SupportTreeNode
struct  Head
struct  Junction
struct  Pillar
struct  Pedestal
struct  Anchor
struct  Bridge
struct  DiffBridge
struct  Pad
class  SupportTreeBuilder
class  PointRing
class  PillarIndex
class  SupportTreeBuildsteps
class  StopCriteria
class  Optimizer

Typedefs

using _RasterGrayscaleAA
using Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> >
using ClusterEl = std::vector<unsigned>
using ClusteredPoints = std::vector<ClusterEl>
using ThrowOnCancel = std::function<void()>
using ccr = _ccr<USE_FULL_CONCURRENCY>
using ccr_seq = _ccr<false>
using ccr_par = _ccr<true>
using InteriorPtr = std::unique_ptr<Interior, InteriorDeleter>
using DrainHoles = std::vector<DrainHole>
using PointSet = Eigen::MatrixXd
using RasterEncoder
using RotOptimizeStatusCB = std::function<bool(int)>
typedef Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
using PointIndexEl = std::pair<Vec3d, unsigned>
using BoxIndexEl = std::pair<Slic3r::BoundingBox, unsigned>
using SupportPoints = std::vector<SupportPoint>
using Portion = std::tuple<double, double>
using AlgNLoptSubplex
using AlgNLoptGenetic

Enumerations

enum  { NEW_FACE = -1 }
enum  HollowingFlags { hfRemoveInsideTriangles = 0x1 }
enum class  PointsStatus { NoPoints , Generating , AutoGenerated , UserModified }
enum class  PillarConnectionMode { zigzag , cross , dynamic }
enum class  MeshType { Support , Pad }
enum  { X , Y , Z }

Functions

ClusteredPoints cluster (const std::vector< unsigned > &indices, std::function< Vec3d(unsigned)> pointfn, double dist, unsigned max_points)
ClusteredPoints cluster (const std::vector< unsigned > &indices, std::function< Vec3d(unsigned)> pointfn, std::function< bool(const PointIndexEl &, const PointIndexEl &)> predicate, unsigned max_points)
ClusteredPoints cluster (const Eigen::MatrixXd &pts, double dist, unsigned max_points)
template<class DistFn, class PointFn>
long cluster_centroid (const ClusterEl &clust, PointFn pointfn, DistFn df)
Vec3d to_vec3 (const Vec2crd &v2)
Vec3d to_vec3 (const Vec2d &v2)
Vec2crd to_vec2 (const Vec3d &v3)
ExPolygons offset_waffle_style_ex (const ConcaveHull &hull, coord_t delta)
Polygons offset_waffle_style (const ConcaveHull &hull, coord_t delta)
Polygons get_contours (const ExPolygons &poly)
indexed_triangle_set & get_mesh (Interior &interior)
const indexed_triangle_set & get_mesh (const Interior &interior)
static InteriorPtr generate_interior_verbose (const TriangleMesh &mesh, const JobController &ctl, double min_thickness, double voxel_scale, double closing_dist)
InteriorPtr generate_interior (const TriangleMesh &mesh, const HollowingConfig &hc, const JobController &ctl)
void cut_drainholes (std::vector< ExPolygons > &obj_slices, const std::vector< float > &slicegrid, float closing_radius, const sla::DrainHoles &holes, std::function< void(void)> thr)
void hollow_mesh (TriangleMesh &mesh, const HollowingConfig &cfg, int flags)
void hollow_mesh (TriangleMesh &mesh, const Interior &interior, int flags)
static double get_distance_raw (const Vec3f &p, const Interior &interior)
static double get_distance (const TriangleBubble &b, const Interior &interior)
double get_distance (const Vec3f &p, const Interior &interior)
template<class Fn>
void divide_triangle (const DivFace &face, Fn &&visitor)
void remove_inside_triangles (TriangleMesh &mesh, const Interior &interior, const std::vector< bool > &exclude_mask)
template<class T>
FloatingOnly< T > get_distance (const Vec< 3, T > &p, const Interior &interior)
void swap_normals (indexed_triangle_set &its)
static bool point_on_edge (const Vec3d &p, const Vec3d &e1, const Vec3d &e2, double eps=0.05)
PointSet normals (const PointSet &points, const IndexedMesh &mesh, double eps, std::function< void()> thr, const std::vector< unsigned > &pt_indices)
void pad_blueprint (const indexed_triangle_set &mesh, ExPolygons &output, const std::vector< float > &, ThrowOnCancel thrfn=[] {})
 Calculate the polygon representing the silhouette.
void pad_blueprint (const indexed_triangle_set &mesh, ExPolygons &output, float h, float layerh, ThrowOnCancel thrfn)
void create_pad (const ExPolygons &sup_blueprint, const ExPolygons &model_blueprint, indexed_triangle_set &out, const PadConfig &cfg, ThrowOnCancel thr)
std::ostream & operator<< (std::ostream &stream, const EncodedRaster &bytes)
std::unique_ptr< RasterBase > create_raster_grayscale_aa (const Resolution &res, const PixelDim &pxdim, double gamma, const RasterBase::Trafo &tr)
template<class Fn>
void foreach_vertex (ExPolygon &poly, Fn &&fn)
ExPolygons raster_to_polygons (const RasterGrayscaleAA &rst, Vec2i32 windowsize)
template<class Pt>
Vec3d pos (const Pt &p)
template<class Pt>
void pos (Pt &p, const Vec3d &pp)
template<class PointType>
void reproject_support_points (const IndexedMesh &mesh, std::vector< PointType > &pts)
void reproject_points_and_holes (ModelObject *object)
Vec2d find_best_misalignment_rotation (const ModelObject &mo, const RotOptimizeParams &params)
Vec2d find_least_supports_rotation (const ModelObject &mo, const RotOptimizeParams &params)
BoundingBoxf3 bounding_box_with_tr (const indexed_triangle_set &its, const Transform3f &tr)
Vec2d find_min_z_height_rotation (const ModelObject &mo, const RotOptimizeParams &params)
static std::vector< SupportPointGenerator::MyLayer > make_layers (const std::vector< ExPolygons > &slices, const std::vector< float > &heights, std::function< void(void)> throw_on_cancel)
std::vector< Vec2f > sample_expolygon (const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
std::vector< Vec2f > sample_expolygon (const ExPolygons &expolys, float samples_per_mm2, std::mt19937 &rng)
void sample_expolygon_boundary (const ExPolygon &expoly, float samples_per_mm, std::vector< Vec2f > &out, std::mt19937 &)
std::vector< Vec2f > sample_expolygon_with_boundary (const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
std::vector< Vec2f > sample_expolygon_with_boundary (const ExPolygons &expolys, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
template<typename REFUSE_FUNCTION>
static std::vector< Vec2f > poisson_disk_from_samples (const std::vector< Vec2f > &raw_samples, float radius, REFUSE_FUNCTION refuse_function)
void remove_bottom_points (std::vector< SupportPoint > &pts, float lvl)
template<class Vec>
double distance (const Vec &p)
template<class Vec>
double distance (const Vec &pp1, const Vec &pp2)
StopCriteria get_criteria (const SupportTreeConfig &cfg)
template<class C, class Hit = IndexedMesh::hit_result>
static Hit min_hit (const C &hits)
std::pair< double, double > dir_to_spheric (const Vec3d &n, double norm=1.)
Vec3d spheric_to_dir (double polar, double azimuth)
Vec3d spheric_to_dir (const std::tuple< double, double > &v)
Vec3d spheric_to_dir (const std::pair< double, double > &v)
Vec3d spheric_to_dir (const std::array< double, 2 > &v)
Vec3d dirv (const Vec3d &startp, const Vec3d &endp)
template<class I, class DoubleI = IntegerOnly<I>>
IntegerOnly< DoubleI > pairhash (I a, I b)
indexed_triangle_set sphere (double rho, Portion portion, double fa)
indexed_triangle_set cylinder (double r, double h, size_t ssteps, const Vec3d &sp)
indexed_triangle_set pinhead (double r_pin, double r_back, double length, size_t steps)
indexed_triangle_set halfcone (double baseheight, double r_bottom, double r_top, const Vec3d &pos, size_t steps)
Portion make_portion (double a, double b)
indexed_triangle_set get_mesh (const Head &h, size_t steps)
indexed_triangle_set get_mesh (const Pillar &p, size_t steps)
indexed_triangle_set get_mesh (const Pedestal &p, size_t steps)
indexed_triangle_set get_mesh (const Junction &j, size_t steps)
indexed_triangle_set get_mesh (const Bridge &br, size_t steps)
indexed_triangle_set get_mesh (const DiffBridge &br, size_t steps)
template<size_t N>
Input< N > initvals (const double(&a)[N])
template<size_t N>
Bounds< N > bounds (const Bound(&b)[N])

Variables

template<class Color>
const Color Colors< Color >::White = Color{255}
template<class Color>
const Color Colors< Color >::Black = Color{0}
const constexpr bool USE_FULL_CONCURRENCY = true
constexpr float HoleStickOutLength = 1.f
const Vec3d DOWN = {0.0, 0.0, -1.0}
const double D_SP = 0.1

Class Documentation

◆ Slic3r::sla::_ccr

struct Slic3r::sla::_ccr
template<bool>
struct Slic3r::sla::_ccr< bool >
Inheritance diagram for Slic3r::sla::_ccr< bool >:

◆ Slic3r::sla::TriangleBubble

struct Slic3r::sla::TriangleBubble
Class Members
Vec3f center
double R

◆ Slic3r::sla::DivFace

struct Slic3r::sla::DivFace
Collaboration diagram for Slic3r::sla::DivFace:
Class Members
long faceid = NEW_FACE
Vec3i32 indx
long parent = NEW_FACE
array< Vec3f, 3 > verts

◆ Slic3r::sla::HollowingConfig

struct Slic3r::sla::HollowingConfig
Class Members
double closing_distance = 0.5
bool enabled = true
double min_thickness = 2.
double quality = 0.5

◆ Slic3r::sla::JobController

struct Slic3r::sla::JobController

A Control structure for the support calculation. Consists of the status indicator callback and the stop condition predicate.

Class Members
typedef function< void(void)> CancelFn std::function<void(void)>
typedef function< void(unsigned, const string &)> StatusFn std::function<void(unsigned, const std::string&)>
typedef function< bool(void)> StopCond std::function<bool(void)>
Class Members
CancelFn cancelfn = [](){}
StatusFn statuscb = [](unsigned, const std::string&){}
StopCond stopcondition = [](){ return false; }

Typedef Documentation

◆ _RasterGrayscaleAA

◆ AlgNLoptGenetic

◆ AlgNLoptSubplex

◆ BoxIndexEl

using Slic3r::sla::BoxIndexEl = std::pair<Slic3r::BoundingBox, unsigned>

◆ ccr

◆ ccr_par

using Slic3r::sla::ccr_par = _ccr<true>

◆ ccr_seq

using Slic3r::sla::ccr_seq = _ccr<false>

◆ ClusteredPoints

◆ ClusterEl

using Slic3r::sla::ClusterEl = std::vector<unsigned>

◆ DrainHoles

using Slic3r::sla::DrainHoles = std::vector<DrainHole>

◆ Index3D

using Slic3r::sla::Index3D = bgi::rtree< PointIndexEl, bgi::rstar<16, 4> >

◆ InteriorPtr

◆ PointIndexEl

using Slic3r::sla::PointIndexEl = std::pair<Vec3d, unsigned>

◆ PointSet

using Slic3r::sla::PointSet = Eigen::MatrixXd

◆ Portion

using Slic3r::sla::Portion = std::tuple<double, double>

◆ RasterEncoder

Initial value:
std::function<EncodedRaster(const void *ptr, size_t w, size_t h, size_t num_components)>
Definition RasterBase.hpp:23

◆ RotOptimizeStatusCB

using Slic3r::sla::RotOptimizeStatusCB = std::function<bool(int)>

◆ SupportPoints

◆ ThrowOnCancel

typedef std::function< void(void)> Slic3r::sla::ThrowOnCancel = std::function<void()>

◆ Vec3d

typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Slic3r::sla::Vec3d

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
NEW_FACE 
385{ NEW_FACE = -1};
@ NEW_FACE
Definition Hollowing.cpp:385

◆ anonymous enum

anonymous enum
Enumerator
X 
Y 
Z 
36 { // For indexing Eigen vectors as v(X), v(Y), v(Z) instead of numbers
37 X, Y, Z
38};
@ Y
Definition SupportTreeBuildsteps.hpp:37
@ X
Definition SupportTreeBuildsteps.hpp:37
@ Z
Definition SupportTreeBuildsteps.hpp:37

◆ HollowingFlags

Enumerator
hfRemoveInsideTriangles 
@ hfRemoveInsideTriangles
Definition Hollowing.hpp:28

◆ MeshType

enum class Slic3r::sla::MeshType
strong
Enumerator
Support 
Pad 
117{ Support, Pad };
@ Support
Definition SupportTree.hpp:117
@ Pad
Definition SupportTree.hpp:117

◆ PillarConnectionMode

Enumerator
zigzag 
cross 
dynamic 
27{
28 zigzag,
29 cross,
31};
@ dynamic
Definition SupportTree.hpp:30
@ zigzag
Definition SupportTree.hpp:28
T cross(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:168

◆ PointsStatus

enum class Slic3r::sla::PointsStatus
strong
Enumerator
NoPoints 
Generating 
AutoGenerated 
UserModified 
13 {
14 NoPoints, // No points were generated so far.
15 Generating, // The autogeneration algorithm triggered, but not yet finished.
16 AutoGenerated, // Points were autogenerated (i.e. copied from the backend).
17 UserModified // User has done some edits.
18};
@ NoPoints
Definition BrimEarsPoint.hpp:14
@ Generating
Definition BrimEarsPoint.hpp:15
@ UserModified
Definition BrimEarsPoint.hpp:17
@ AutoGenerated
Definition BrimEarsPoint.hpp:16

Function Documentation

◆ bounding_box_with_tr()

BoundingBoxf3 Slic3r::sla::bounding_box_with_tr ( const indexed_triangle_set & its,
const Transform3f & tr )
inline
431{
432 if (its.vertices.empty())
433 return {};
434
435 Vec3f bmin = tr * its.vertices.front(), bmax = tr * its.vertices.front();
436
437 for (const Vec3f &p : its.vertices) {
438 Vec3f pp = tr * p;
439 bmin = pp.cwiseMin(bmin);
440 bmax = pp.cwiseMax(bmax);
441 }
442
443 return {bmin.cast<double>(), bmax.cast<double>()};
444}
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65

Referenced by find_min_z_height_rotation().

Here is the caller graph for this function:

◆ bounds()

template<size_t N>
Bounds< N > Slic3r::opt::bounds ( const Bound(&) b[N])
175{ return detail::to_arr(b); }

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_ground(), Slic3r::sla::SupportTreeBuildsteps::filter(), find_best_misalignment_rotation(), find_least_supports_rotation(), and Slic3r::sla::SupportTreeBuildsteps::search_widening_path().

Here is the caller graph for this function:

◆ cluster() [1/3]

ClusteredPoints Slic3r::sla::cluster ( const Eigen::MatrixXd & pts,
double dist,
unsigned max_points )
145{
146 // A spatial index for querying the nearest points
147 Index3D sindex;
148
149 // Build the index
150 for(Eigen::Index i = 0; i < pts.rows(); i++)
151 sindex.insert(std::make_pair(Vec3d(pts.row(i)), unsigned(i)));
152
153 return cluster(sindex, max_points,
154 [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
155 {
156 return distance_queryfn(sidx, p, dist, max_points);
157 });
158}
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298
ClusteredPoints cluster(const std::vector< unsigned > &indices, std::function< Vec3d(unsigned)> pointfn, double dist, unsigned max_points)
Definition Clustering.cpp:101
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition SpatIndex.hpp:18
bgi::rtree< PointIndexEl, bgi::rstar< 16, 4 > > Index3D
Definition Clustering.cpp:18
std::pair< Vec3d, unsigned > PointIndexEl
Definition SpatIndex.hpp:19

References cluster(), and Slic3r::Geometry::dist().

Here is the call graph for this function:

◆ cluster() [2/3]

ClusteredPoints Slic3r::sla::cluster ( const std::vector< unsigned > & indices,
std::function< Vec3d(unsigned)> pointfn,
double dist,
unsigned max_points )
106{
107 // A spatial index for querying the nearest points
108 Index3D sindex;
109
110 // Build the index
111 for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
112
113 return cluster(sindex, max_points,
114 [dist, max_points](const Index3D& sidx, const PointIndexEl& p)
115 {
116 return distance_queryfn(sidx, p, dist, max_points);
117 });
118}

References cluster(), and Slic3r::Geometry::dist().

Referenced by Slic3r::sla::SupportTreeBuildsteps::classify(), cluster(), cluster(), cluster(), and Slic3r::sla::SupportTreeBuildsteps::filter().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cluster() [3/3]

ClusteredPoints Slic3r::sla::cluster ( const std::vector< unsigned > & indices,
std::function< Vec3d(unsigned)> pointfn,
std::function< bool(const PointIndexEl &, const PointIndexEl &)> predicate,
unsigned max_points )
126{
127 // A spatial index for querying the nearest points
128 Index3D sindex;
129
130 // Build the index
131 for(auto idx : indices) sindex.insert( std::make_pair(pointfn(idx), idx));
132
133 return cluster(sindex, max_points,
134 [max_points, predicate](const Index3D& sidx, const PointIndexEl& p)
135 {
136 std::vector<PointIndexEl> tmp; tmp.reserve(max_points);
137 sidx.query(bgi::satisfies([p, predicate](const PointIndexEl& e){
138 return predicate(p, e);
139 }), std::back_inserter(tmp));
140 return tmp;
141 });
142}

References cluster().

Here is the call graph for this function:

◆ cluster_centroid()

template<class DistFn, class PointFn>
long Slic3r::sla::cluster_centroid ( const ClusterEl & clust,
PointFn pointfn,
DistFn df )
38{
39 switch(clust.size()) {
40 case 0: /* empty cluster */ return -1;
41 case 1: /* only one element */ return 0;
42 case 2: /* if two elements, there is no center */ return 0;
43 default: ;
44 }
45
46 // The function works by calculating for each point the average distance
47 // from all the other points in the cluster. We create a selector bitmask of
48 // the same size as the cluster. The bitmask will have two true bits and
49 // false bits for the rest of items and we will loop through all the
50 // permutations of the bitmask (combinations of two points). Get the
51 // distance for the two points and add the distance to the averages.
52 // The point with the smallest average than wins.
53
54 // The complexity should be O(n^2) but we will mostly apply this function
55 // for small clusters only (cca 3 elements)
56
57 std::vector<bool> sel(clust.size(), false); // create full zero bitmask
58 std::fill(sel.end() - 2, sel.end(), true); // insert the two ones
59 std::vector<double> avgs(clust.size(), 0.0); // store the average distances
60
61 do {
62 std::array<size_t, 2> idx;
63 for(size_t i = 0, j = 0; i < clust.size(); i++)
64 if(sel[i]) idx[j++] = i;
65
66 double d = df(pointfn(clust[idx[0]]),
67 pointfn(clust[idx[1]]));
68
69 // add the distance to the sums for both associated points
70 for(auto i : idx) avgs[i] += d;
71
72 // now continue with the next permutation of the bitmask with two 1s
73 } while(std::next_permutation(sel.begin(), sel.end()));
74
75 // Divide by point size in the cluster to get the average (may be redundant)
76 for(auto& a : avgs) a /= clust.size();
77
78 // get the lowest average distance and return the index
79 auto minit = std::min_element(avgs.begin(), avgs.end());
80 return long(minit - avgs.begin());
81}

Referenced by Slic3r::sla::SupportTreeBuildsteps::routing_to_ground().

Here is the caller graph for this function:

◆ create_pad()

void Slic3r::sla::create_pad ( const ExPolygons & sup_blueprint,
const ExPolygons & model_blueprint,
indexed_triangle_set & out,
const PadConfig & cfg,
ThrowOnCancel thr )
515{
516 auto t = create_pad_geometry(sup_blueprint, model_blueprint, cfg, thr);
517 its_merge(out, t);
518}
void its_merge(indexed_triangle_set &A, const indexed_triangle_set &B)
Definition TriangleMesh.cpp:1448

References Slic3r::its_merge().

Referenced by Slic3r::sla::Pad::Pad().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_raster_grayscale_aa()

std::unique_ptr< RasterBase > Slic3r::sla::create_raster_grayscale_aa ( const Resolution & res,
const PixelDim & pxdim,
double gamma,
const RasterBase::Trafo & tr )
82{
83 std::unique_ptr<RasterBase> rst;
84
85 if (gamma > 0)
86 rst = std::make_unique<RasterGrayscaleAAGammaPower>(res, pxdim, tr, gamma);
87 else if (std::abs(gamma - 1.) < 1e-6)
88 rst = std::make_unique<RasterGrayscaleAA>(res, pxdim, tr, agg::gamma_none());
89 else
90 rst = std::make_unique<RasterGrayscaleAA>(res, pxdim, tr, agg::gamma_threshold(.5));
91
92 return rst;
93}

Referenced by Slic3r::SL1Archive::create_raster(), Slic3r::GUI::CreateFontImageJob::process(), and Slic3r::GUI::Emboss::CreateFontStyleImagesJob::process().

Here is the caller graph for this function:

◆ cut_drainholes()

void Slic3r::sla::cut_drainholes ( std::vector< ExPolygons > & obj_slices,
const std::vector< float > & slicegrid,
float closing_radius,
const sla::DrainHoles & holes,
std::function< void(void)> thr )
304{
305 TriangleMesh mesh;
306 for (const sla::DrainHole &holept : holes)
307 mesh.merge(TriangleMesh{holept.to_mesh()});
308
309 if (mesh.empty()) return;
310
311 std::vector<ExPolygons> hole_slices = slice_mesh_ex(mesh.its, slicegrid, closing_radius, thr);
312
313 if (obj_slices.size() != hole_slices.size())
314 BOOST_LOG_TRIVIAL(warning)
315 << "Sliced object and drain-holes layer count does not match!";
316
317 size_t until = std::min(obj_slices.size(), hole_slices.size());
318
319 for (size_t i = 0; i < until; ++i)
320 obj_slices[i] = diff_ex(obj_slices[i], hole_slices[i]);
321}
Definition TriangleMesh.hpp:94
bool empty() const
Definition TriangleMesh.hpp:146
indexed_triangle_set its
Definition TriangleMesh.hpp:164
void merge(const TriangleMesh &mesh)
Definition TriangleMesh.cpp:422
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:31
std::vector< ExPolygons > slice_mesh_ex(const indexed_triangle_set &mesh, const std::vector< float > &zs, const MeshSlicingParamsEx &params, std::function< void()> throw_on_cancel)
Definition TriangleMeshSlicer.cpp:2142
Definition Hollowing.hpp:40

References Slic3r::diff_ex(), Slic3r::TriangleMesh::empty(), Slic3r::holes(), Slic3r::TriangleMesh::its, Slic3r::TriangleMesh::merge(), and Slic3r::slice_mesh_ex().

Here is the call graph for this function:

◆ cylinder()

indexed_triangle_set Slic3r::sla::cylinder ( double r,
double h,
size_t ssteps,
const Vec3d & sp )
106{
107 assert(ssteps > 0);
108
109 indexed_triangle_set ret;
110
111 auto steps = int(ssteps);
112 auto& points = ret.vertices;
113 auto& indices = ret.indices;
114 points.reserve(2*ssteps);
115 double a = 2*PI/steps;
116
117 Vec3d jp = sp;
118 Vec3d endp = {sp(X), sp(Y), sp(Z) + h};
119
120 // Upper circle points
121 for(int i = 0; i < steps; ++i) {
122 double phi = i*a;
123 auto ex = float(endp(X) + r*std::cos(phi));
124 auto ey = float(endp(Y) + r*std::sin(phi));
125 points.emplace_back(ex, ey, float(endp(Z)));
126 }
127
128 // Lower circle points
129 for(int i = 0; i < steps; ++i) {
130 double phi = i*a;
131 auto x = float(jp(X) + r*std::cos(phi));
132 auto y = float(jp(Y) + r*std::sin(phi));
133 points.emplace_back(x, y, float(jp(Z)));
134 }
135
136 // Now create long triangles connecting upper and lower circles
137 indices.reserve(2*ssteps);
138 auto offs = steps;
139 for(int i = 0; i < steps - 1; ++i) {
140 indices.emplace_back(i, i + offs, offs + i + 1);
141 indices.emplace_back(i, offs + i + 1, i + 1);
142 }
143
144 // Last triangle connecting the first and last vertices
145 auto last = steps - 1;
146 indices.emplace_back(0, last, offs);
147 indices.emplace_back(last, offs + last, offs);
148
149 // According to the slicing algorithms, we need to aid them with generating
150 // a watertight body. So we create a triangle fan for the upper and lower
151 // ending of the cylinder to close the geometry.
152 points.emplace_back(jp.cast<float>()); int ci = int(points.size() - 1);
153 for(int i = 0; i < steps - 1; ++i)
154 indices.emplace_back(i + offs + 1, i + offs, ci);
155
156 indices.emplace_back(offs, steps + offs - 1, ci);
157
158 points.emplace_back(endp.cast<float>()); ci = int(points.size() - 1);
159 for(int i = 0; i < steps - 1; ++i)
160 indices.emplace_back(ci, i, i + 1);
161
162 indices.emplace_back(steps - 1, 0, ci);
163
164 return ret;
165}
static constexpr double PI
Definition libslic3r.h:81
@ Y
Definition libslic3r.h:142
@ Z
Definition libslic3r.h:143
@ X
Definition libslic3r.h:141

References PI, X, Y, and Z.

Referenced by get_mesh(), get_mesh(), and Slic3r::sla::DrainHole::to_mesh().

Here is the caller graph for this function:

◆ dir_to_spheric()

std::pair< double, double > Slic3r::sla::dir_to_spheric ( const Vec3d & n,
double norm = 1. )
inline
43{
44 double z = n.z();
45 double r = norm;
46 double polar = std::acos(z / r);
47 double azimuth = std::atan2(n(1), n(0));
48 return {polar, azimuth};
49}

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_ground(), Slic3r::sla::SupportTreeBuildsteps::create_ground_pillar(), Slic3r::sla::SupportTreeBuildsteps::filter(), and Slic3r::sla::SupportTreeBuildsteps::search_widening_path().

Here is the caller graph for this function:

◆ dirv()

Vec3d Slic3r::sla::dirv ( const Vec3d & startp,
const Vec3d & endp )
inline
134 {
135 return (endp - startp).normalized();
136}

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_nearpillar(), Slic3r::sla::SupportTreeBuildsteps::interconnect(), and Slic3r::sla::SupportTreeBuildsteps::interconnect_pillars().

Here is the caller graph for this function:

◆ distance() [1/2]

template<class Vec>
double Slic3r::sla::distance ( const Vec & p)

Terminology:

Support point: The point on the model surface that needs support.

Pillar: A thick column that spans from a support point to the ground and has a thick cone shaped base where it touches the ground.

Ground facing support point: A support point that can be directly connected with the ground with a pillar that does not collide or cut through the model.

Non ground facing support point: A support point that cannot be directly connected with the ground (only with the model surface).

Head: The pinhead that connects to the model surface with the sharp end end to a pillar or bridge stick with the dull end.

Headless support point: A support point on the model surface for which there is not enough place for the head. It is either in a hole or there is some barrier that would collide with the head geometry. The headless support point can be ground facing and non ground facing as well.

Bridge: A stick that connects two pillars or a head with a pillar.

Junction: A small ball in the intersection of two or more sticks (pillar, bridge, ...)

CompactBridge: A bridge that connects a headless support point with the model surface or a nearby pillar.

59 {
60 return std::sqrt(p.transpose() * p);
61}

Referenced by Slic3r::sla::SupportTreeBuildsteps::classify(), Slic3r::sla::SupportTreeBuildsteps::connect_to_nearpillar(), distance(), Slic3r::sla::SupportTreeBuildsteps::interconnect(), Slic3r::sla::SupportTreeBuildsteps::interconnect_pillars(), and Slic3r::sla::SupportTreeBuildsteps::routing_to_ground().

Here is the caller graph for this function:

◆ distance() [2/2]

template<class Vec>
double Slic3r::sla::distance ( const Vec & pp1,
const Vec & pp2 )
63 {
64 auto p = pp2 - pp1;
65 return distance(p);
66}
double distance(const Vec &p)
Definition SupportTreeBuilder.hpp:59

References distance().

Here is the call graph for this function:

◆ divide_triangle()

template<class Fn>
void Slic3r::sla::divide_triangle ( const DivFace & face,
Fn && visitor )
396{
397 std::array<Vec3f, 3> edges = {(face.verts[0] - face.verts[1]),
398 (face.verts[1] - face.verts[2]),
399 (face.verts[2] - face.verts[0])};
400
401 std::array<size_t, 3> edgeidx = {0, 1, 2};
402
403 std::sort(edgeidx.begin(), edgeidx.end(), [&edges](size_t e1, size_t e2) {
404 return edges[e1].squaredNorm() > edges[e2].squaredNorm();
405 });
406
407 DivFace child1, child2;
408
409 child1.parent = face.faceid == NEW_FACE ? face.parent : face.faceid;
410 child1.indx(0) = -1;
411 child1.indx(1) = face.indx(edgeidx[1]);
412 child1.indx(2) = face.indx((edgeidx[1] + 1) % 3);
413 child1.verts[0] = (face.verts[edgeidx[0]] + face.verts[(edgeidx[0] + 1) % 3]) / 2.;
414 child1.verts[1] = face.verts[edgeidx[1]];
415 child1.verts[2] = face.verts[(edgeidx[1] + 1) % 3];
416
417 if (visitor(child1))
418 divide_triangle(child1, std::forward<Fn>(visitor));
419
420 child2.parent = face.faceid == NEW_FACE ? face.parent : face.faceid;
421 child2.indx(0) = -1;
422 child2.indx(1) = face.indx(edgeidx[2]);
423 child2.indx(2) = face.indx((edgeidx[2] + 1) % 3);
424 child2.verts[0] = child1.verts[0];
425 child2.verts[1] = face.verts[edgeidx[2]];
426 child2.verts[2] = face.verts[(edgeidx[2] + 1) % 3];
427
428 if (visitor(child2))
429 divide_triangle(child2, std::forward<Fn>(visitor));
430}
void divide_triangle(const DivFace &face, Fn &&visitor)
Definition Hollowing.cpp:395
long parent
Definition Hollowing.cpp:390
std::array< Vec3f, 3 > verts
Definition Hollowing.cpp:388
long faceid
Definition Hollowing.cpp:389
Vec3i32 indx
Definition Hollowing.cpp:387

References divide_triangle(), Slic3r::sla::DivFace::faceid, Slic3r::sla::DivFace::indx, NEW_FACE, Slic3r::sla::DivFace::parent, and Slic3r::sla::DivFace::verts.

Referenced by divide_triangle(), and remove_inside_triangles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_best_misalignment_rotation()

Vec2d Slic3r::sla::find_best_misalignment_rotation ( const ModelObject & modelobj,
const RotOptimizeParams & = {} )

The function should find the best rotation for SLA upside down printing.

Parameters
modelobjThe model object representing the 3d mesh.
accuracyThe optimization accuracy from 0.0f to 1.0f. Currently, the nlopt genetic optimizer is used and the number of iterations is accuracy * 100000. This can change in the future.
statuscbA status indicator callback called with the int argument spanning from 0 to 100. May not reach 100 if the optimization finds an optimum before max iterations are reached. It should return a boolean signaling if the operation may continue (true) or not (false). A status value lower than 0 shall not update the status but still return a valid continuation indicator.
Returns
Returns the rotations around each axis (x, y, z)
343{
344 RotfinderBoilerplate<1000> bp{mo, params};
345
346 // Preparing the optimizer.
347 size_t gridsize = std::sqrt(bp.max_tries);
350 .stop_condition([&bp] { return bp.stopcond(); }),
351 gridsize
352 );
353
354 // We are searching rotations around only two axes x, y. Thus the
355 // problem becomes a 2 dimensional optimization task.
356 // We can specify the bounds for a dimension in the following way:
357 auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
358
359 auto result = solver.to_max().optimize(
360 [&bp] (const XYRotation &rot)
361 {
362 bp.statusfn();
364 }, opt::initvals({0., 0.}), bounds);
365
366 return {result.optimum[0], result.optimum[1]};
367}
Definition Optimizer.hpp:112
Definition Optimizer.hpp:42
StopCriteria & stop_condition(Fn &&cond)
Definition Optimizer.hpp:90
StopCriteria & max_iterations(double val)
Definition Optimizer.hpp:83
Bounds< N > bounds(const Bound(&b)[N])
Definition Optimizer.hpp:175
Input< N > initvals(const double(&a)[N])
Definition Optimizer.hpp:176
Transform3f to_transform3f(const XYRotation &rot)
Definition Rotfinder.cpp:195
double get_misalginment_score(const TriangleMesh &mesh, const Transform3f &tr)
Definition Rotfinder.cpp:91
Bounds< N > bounds(const Bound(&b)[N])
Definition Optimizer.hpp:175
Definition Rotfinder.cpp:302
TriangleMesh mesh
Definition Rotfinder.cpp:306
void statusfn()
Definition Rotfinder.cpp:337
unsigned max_tries
Definition Rotfinder.cpp:307

References Slic3r::opt::bounds(), bounds(), Slic3r::opt::initvals(), Slic3r::opt::StopCriteria::max_iterations(), Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::max_tries, Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::mesh, Slic3r::opt::Optimizer< Method, Enable >::optimize(), PI, Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::statusfn(), Slic3r::opt::StopCriteria::stop_condition(), and Slic3r::opt::Optimizer< Method, Enable >::to_max().

Here is the call graph for this function:

◆ find_least_supports_rotation()

Vec2d Slic3r::sla::find_least_supports_rotation ( const ModelObject & mo,
const RotOptimizeParams & params )
371{
372 RotfinderBoilerplate<1000> bp{mo, params};
373
374 SLAPrintObjectConfig pocfg;
375 if (params.print_config())
376 pocfg.apply(*params.print_config(), true);
377
378 pocfg.apply(mo.config.get());
379
380 XYRotation rot;
381
382 // Different search methods have to be used depending on the model elevation
383 if (is_on_floor(pocfg)) {
384
385 std::vector<XYRotation> inputs = get_chull_rotations(bp.mesh, bp.max_tries);
386 bp.max_tries = inputs.size();
387
388 // If the model can be placed on the bed directly, we only need to
389 // check the 3D convex hull face rotations.
390
391 auto objfn = [&bp](const XYRotation &rot) {
392 bp.statusfn();
393 Transform3f tr = to_transform3f(rot);
394 return get_supportedness_onfloor_score(bp.mesh, tr);
395 };
396
397 rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
398 return bp.stopcond();
399 });
400
401 } else {
402 // Preparing the optimizer.
403 size_t gridsize = std::sqrt(bp.max_tries); // 2D grid has gridsize^2 calls
404 opt::Optimizer<opt::AlgBruteForce> solver(
405 opt::StopCriteria{}.max_iterations(bp.max_tries)
406 .stop_condition([&bp] { return bp.stopcond(); }),
407 gridsize
408 );
409
410 // We are searching rotations around only two axes x, y. Thus the
411 // problem becomes a 2 dimensional optimization task.
412 // We can specify the bounds for a dimension in the following way:
413 auto bounds = opt::bounds({ {-PI, PI}, {-PI, PI} });
414
415 auto result = solver.to_min().optimize(
416 [&bp] (const XYRotation &rot)
417 {
418 bp.statusfn();
420 }, opt::initvals({0., 0.}), bounds);
421
422 // Save the result
423 rot = result.optimum;
424 }
425
426 return {rot[0], rot[1]};
427}
const DynamicPrintConfig & get() const
Definition PrintConfig.hpp:2645
ModelConfigObject config
Definition Model.hpp:395
RotOptimizeParams & print_config(const DynamicPrintConfig *c)
Definition Rotfinder.hpp:29
double get_supportedness_score(const Facestats &fc)
Definition Rotfinder.cpp:115
Eigen::Transform< float, 3, Eigen::Affine, Eigen::DontAlign > Transform3f
Definition Point.hpp:95

References Slic3r::opt::bounds(), bounds(), Slic3r::ModelObject::config, Slic3r::ModelConfig::get(), Slic3r::opt::initvals(), Slic3r::opt::StopCriteria::max_iterations(), Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::max_tries, Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::mesh, Slic3r::opt::Optimizer< Method, Enable >::optimize(), PI, Slic3r::sla::RotOptimizeParams::print_config(), Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::statusfn(), Slic3r::opt::StopCriteria::stop_condition(), and Slic3r::opt::Optimizer< Method, Enable >::to_min().

Here is the call graph for this function:

◆ find_min_z_height_rotation()

Vec2d Slic3r::sla::find_min_z_height_rotation ( const ModelObject & mo,
const RotOptimizeParams & params )
448{
449 RotfinderBoilerplate<1000> bp{mo, params};
450
451 TriangleMesh chull = bp.mesh.convex_hull_3d();
452 auto inputs = reserve_vector<XYRotation>(chull.its.indices.size());
453 auto rotcmp = [](const XYRotation &r1, const XYRotation &r2) {
454 double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y];
455 return std::abs(xdiff) < EPSILON ? ydiff < 0. : xdiff < 0.;
456 };
457 auto eqcmp = [](const XYRotation &r1, const XYRotation &r2) {
458 double xdiff = r1[X] - r2[X], ydiff = r1[Y] - r2[Y];
459 return std::abs(xdiff) < EPSILON && std::abs(ydiff) < EPSILON;
460 };
461
462 for (size_t fi = 0; fi < chull.its.indices.size(); ++fi) {
463 Facestats fc{get_triangle_vertices(chull, fi)};
464
465 auto q = Eigen::Quaternionf{}.FromTwoVectors(fc.normal, DOWN);
466 XYRotation rot = from_transform3f(Transform3f::Identity() * q);
467
468 auto it = std::lower_bound(inputs.begin(), inputs.end(), rot, rotcmp);
469
470 if (it == inputs.end() || !eqcmp(*it, rot))
471 inputs.insert(it, rot);
472 }
473
474 inputs.shrink_to_fit();
475 bp.max_tries = inputs.size();
476
477 auto objfn = [&bp, &chull](const XYRotation &rot) {
478 bp.statusfn();
479 Transform3f tr = to_transform3f(rot);
480 return bounding_box_with_tr(chull.its, tr).size().z();
481 };
482
483 XYRotation rot = find_min_score<2>(objfn, inputs.begin(), inputs.end(), [&bp] {
484 return bp.stopcond();
485 });
486
487 return {rot[0], rot[1]};
488}
#define EPSILON
Definition ColorUtils.cpp:64
PointType size() const
Definition BoundingBox.cpp:187
TriangleMesh convex_hull_3d() const
Definition TriangleMesh.cpp:515
XYRotation from_transform3f(const Transform3f &tr)
Definition Rotfinder.cpp:204
std::array< Vec3f, 3 > get_triangle_vertices(const TriangleMesh &mesh, size_t faceidx)
Definition Rotfinder.cpp:40
std::array< double, 2 > XYRotation
Definition Rotfinder.cpp:192
BoundingBoxf3 bounding_box_with_tr(const indexed_triangle_set &its, const Transform3f &tr)
Definition Rotfinder.cpp:429
const Vec3d DOWN
Definition SupportTreeBuilder.hpp:68
IntegerOnly< I, std::vector< T, Args... > > reserve_vector(I capacity)
Definition libslic3r.h:370

References bounding_box_with_tr(), Slic3r::TriangleMesh::convex_hull_3d(), DOWN, EPSILON, Slic3r::TriangleMesh::its, Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::max_tries, Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::mesh, Slic3r::reserve_vector(), Slic3r::BoundingBox3Base< PointType >::size(), Slic3r::sla::RotfinderBoilerplate< MAX_ITER >::statusfn(), X, and Y.

Here is the call graph for this function:

◆ foreach_vertex()

template<class Fn>
void Slic3r::sla::foreach_vertex ( ExPolygon & poly,
Fn && fn )
39{
40 for (auto &p : poly.contour.points) fn(p);
41 for (auto &h : poly.holes)
42 for (auto &p : h.points) fn(p);
43}

Referenced by raster_to_polygons().

Here is the caller graph for this function:

◆ generate_interior()

InteriorPtr Slic3r::sla::generate_interior ( const TriangleMesh & mesh,
const HollowingConfig & hc,
const JobController & ctl )
133{
134 static const double MIN_OVERSAMPL = 3.5;
135 static const double MAX_OVERSAMPL = 8.;
136
137 // I can't figure out how to increase the grid resolution through openvdb
138 // API so the model will be scaled up before conversion and the result
139 // scaled down. Voxels have a unit size. If I set voxelSize smaller, it
140 // scales the whole geometry down, and doesn't increase the number of
141 // voxels.
142 //
143 // max 8x upscale, min is native voxel size
144 auto voxel_scale = MIN_OVERSAMPL + (MAX_OVERSAMPL - MIN_OVERSAMPL) * hc.quality;
145
146 InteriorPtr interior =
147 generate_interior_verbose(mesh, ctl, hc.min_thickness, voxel_scale,
149
150 if (interior && !interior->mesh.empty()) {
151
152 // flip normals back...
153 swap_normals(interior->mesh);
154
155 // simplify mesh lossless
156 float loss_less_max_error = 2*std::numeric_limits<float>::epsilon();
157 its_quadric_edge_collapse(interior->mesh, 0U, &loss_less_max_error);
158
159 its_compactify_vertices(interior->mesh);
160 its_merge_vertices(interior->mesh);
161
162 // flip normals back...
163 swap_normals(interior->mesh);
164 }
165
166 return interior;
167}
double closing_distance
Definition Hollowing.hpp:24
void swap_normals(indexed_triangle_set &its)
Definition Hollowing.hpp:105
double quality
Definition Hollowing.hpp:23
double min_thickness
Definition Hollowing.hpp:22
std::unique_ptr< Interior, InteriorDeleter > InteriorPtr
Definition Hollowing.hpp:34
static InteriorPtr generate_interior_verbose(const TriangleMesh &mesh, const JobController &ctl, double min_thickness, double voxel_scale, double closing_dist)
Definition Hollowing.cpp:79
int its_merge_vertices(indexed_triangle_set &its, bool shrink_to_fit)
Definition TriangleMesh.cpp:690
void its_quadric_edge_collapse(indexed_triangle_set &its, uint32_t triangle_count=0, float *max_error=nullptr, std::function< void(void)> throw_on_cancel=nullptr, std::function< void(int)> statusfn=nullptr)
Simplify mesh by Quadric metric.
Definition QuadricEdgeCollapse.cpp:174
int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit)
Definition TriangleMesh.cpp:773
indexed_triangle_set mesh
Definition Hollowing.cpp:45

References Slic3r::sla::HollowingConfig::closing_distance, generate_interior_verbose(), Slic3r::its_compactify_vertices(), Slic3r::its_merge_vertices(), Slic3r::its_quadric_edge_collapse(), Slic3r::sla::Interior::mesh, Slic3r::sla::HollowingConfig::min_thickness, Slic3r::sla::HollowingConfig::quality, and swap_normals().

Referenced by hollow_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generate_interior_verbose()

InteriorPtr Slic3r::sla::generate_interior_verbose ( const TriangleMesh & mesh,
const JobController & ctl,
double min_thickness,
double voxel_scale,
double closing_dist )
static
84{
85 double offset = voxel_scale * min_thickness;
86 double D = voxel_scale * closing_dist;
87 float out_range = 0.1f * float(offset);
88 float in_range = 1.1f * float(offset + D);
89
90 if (ctl.stopcondition()) return {};
91 else ctl.statuscb(0, L("Hollowing"));
92
93 auto gridptr = mesh_to_grid(mesh.its, {}, voxel_scale, out_range, in_range);
94
95 assert(gridptr);
96
97 if (!gridptr) {
98 BOOST_LOG_TRIVIAL(error) << "Returned OpenVDB grid is NULL";
99 return {};
100 }
101
102 if (ctl.stopcondition()) return {};
103 else ctl.statuscb(30, L("Hollowing"));
104
105 double iso_surface = D;
106 auto narrowb = double(in_range);
107 gridptr = redistance_grid(*gridptr, -(offset + D), narrowb, narrowb);
108
109 if (ctl.stopcondition()) return {};
110 else ctl.statuscb(70, L("Hollowing"));
111
112 double adaptivity = 0.;
113 InteriorPtr interior = InteriorPtr{new Interior{}};
114
115 interior->mesh = grid_to_mesh(*gridptr, iso_surface, adaptivity);
116 interior->gridptr = gridptr;
117
118 if (ctl.stopcondition()) return {};
119 else ctl.statuscb(100, L("Hollowing"));
120
121 interior->closing_distance = D;
122 interior->thickness = offset;
123 interior->voxel_scale = voxel_scale;
124 interior->nb_in = narrowb;
125 interior->nb_out = narrowb;
126
127 return interior;
128}
#define L(s)
Definition ExtrusionEntity.cpp:25
StopCond stopcondition
Definition JobController.hpp:21
StatusFn statuscb
Definition JobController.hpp:18
openvdb::FloatGrid::Ptr redistance_grid(const openvdb::FloatGrid &grid, double iso, double er, double ir)
Definition OpenVDBUtils.cpp:137
openvdb::FloatGrid::Ptr mesh_to_grid(const indexed_triangle_set &mesh, const openvdb::math::Transform &tr, float voxel_scale, float exteriorBandWidth, float interiorBandWidth, int flags)
Definition OpenVDBUtils.cpp:63
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
indexed_triangle_set grid_to_mesh(const openvdb::FloatGrid &grid, double isovalue, double adaptivity, bool relaxDisorientedTriangles)
Definition OpenVDBUtils.cpp:104
Definition Hollowing.cpp:44

References Slic3r::sla::Interior::closing_distance, Slic3r::grid_to_mesh(), Slic3r::sla::Interior::gridptr, Slic3r::TriangleMesh::its, L, Slic3r::sla::Interior::mesh, Slic3r::mesh_to_grid(), Slic3r::sla::Interior::nb_in, Slic3r::sla::Interior::nb_out, Slic3r::offset(), Slic3r::redistance_grid(), Slic3r::sla::JobController::statuscb, Slic3r::sla::JobController::stopcondition, Slic3r::sla::Interior::thickness, and Slic3r::sla::Interior::voxel_scale.

Referenced by generate_interior().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_contours()

Polygons Slic3r::sla::get_contours ( const ExPolygons & poly)
inline
14{
15 Polygons ret; ret.reserve(poly.size());
16 for (const ExPolygon &p : poly) ret.emplace_back(p.contour);
17
18 return ret;
19}
Definition ExPolygon.hpp:23
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22

Referenced by Slic3r::sla::ConcaveHull::merge_polygons().

Here is the caller graph for this function:

◆ get_criteria()

StopCriteria Slic3r::sla::get_criteria ( const SupportTreeConfig & cfg)
41{
42 return StopCriteria{}
45}
StopCriteria & rel_score_diff(double val)
Definition Optimizer.hpp:69
static const double constexpr optimizer_rel_score_diff
Definition SupportTree.hpp:105
static const unsigned constexpr optimizer_max_iterations
Definition SupportTree.hpp:106

References Slic3r::opt::StopCriteria::max_iterations(), Slic3r::sla::SupportTreeConfig::optimizer_max_iterations, Slic3r::sla::SupportTreeConfig::optimizer_rel_score_diff, and Slic3r::opt::StopCriteria::rel_score_diff().

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_ground(), Slic3r::sla::SupportTreeBuildsteps::filter(), and Slic3r::sla::SupportTreeBuildsteps::search_widening_path().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_distance() [1/3]

double Slic3r::sla::get_distance ( const TriangleBubble & b,
const Interior & interior )
static
362{
363 double R = b.R * interior.voxel_scale;
364 double D = get_distance_raw(b.center, interior);
365
366 return (D > 0. && R >= interior.nb_out) ||
367 (D < 0. && R >= interior.nb_in) ||
368 ((D - R) < 0. && 2 * R > interior.thickness) ?
369 std::nan("") :
370 // FIXME: Adding interior.voxel_scale is a compromise supposed
371 // to prevent the deletion of the triangles forming the interior
372 // itself. This has a side effect that a small portion of the
373 // bad triangles will still be visible.
374 D - interior.closing_distance /*+ 2 * interior.voxel_scale*/;
375}
Vec3f center
Definition Hollowing.cpp:357
static double get_distance_raw(const Vec3f &p, const Interior &interior)
Definition Hollowing.cpp:344
double R
Definition Hollowing.cpp:357
double nb_in
Definition Hollowing.cpp:52
double thickness
Definition Hollowing.cpp:50
double nb_out
Definition Hollowing.cpp:53
double voxel_scale
Definition Hollowing.cpp:51

References Slic3r::sla::TriangleBubble::center, Slic3r::sla::Interior::closing_distance, get_distance_raw(), Slic3r::sla::Interior::nb_in, Slic3r::sla::Interior::nb_out, Slic3r::sla::TriangleBubble::R, Slic3r::sla::Interior::thickness, and Slic3r::sla::Interior::voxel_scale.

Referenced by Slic3r::create_exclude_mask(), get_distance(), and remove_inside_triangles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_distance() [2/3]

double Slic3r::sla::get_distance ( const Vec3f & p,
const Interior & interior )
378{
379 double d = get_distance_raw(p, interior) - interior.closing_distance;
380 return d / interior.voxel_scale;
381}
double closing_distance
Definition Hollowing.cpp:49

References Slic3r::sla::Interior::closing_distance, get_distance_raw(), and Slic3r::sla::Interior::voxel_scale.

Here is the call graph for this function:

◆ get_distance() [3/3]

template<class T>
FloatingOnly< T > Slic3r::sla::get_distance ( const Vec< 3, T > & p,
const Interior & interior )
95{
96 return get_distance(Vec3f(p.template cast<float>()), interior);
97}
static double get_distance(const TriangleBubble &b, const Interior &interior)
Definition Hollowing.cpp:361
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299

References Slic3r::cast(), and get_distance().

Here is the call graph for this function:

◆ get_distance_raw()

double Slic3r::sla::get_distance_raw ( const Vec3f & p,
const Interior & interior )
static
345{
346 assert(interior.gridptr);
347
348 if (!interior.accessor) interior.reset_accessor();
349
350 auto v = (p * interior.voxel_scale).cast<double>();
351 auto grididx = interior.gridptr->transform().worldToIndexCellCentered(
352 {v.x(), v.y(), v.z()});
353
354 return interior.accessor->getValue(grididx) ;
355}
std::optional< openvdb::FloatGrid::ConstAccessor > accessor
Definition Hollowing.cpp:47
void reset_accessor() const
Definition Hollowing.cpp:56
openvdb::FloatGrid::Ptr gridptr
Definition Hollowing.cpp:46

References Slic3r::sla::Interior::accessor, Slic3r::cast(), Slic3r::sla::Interior::gridptr, Slic3r::sla::Interior::reset_accessor(), and Slic3r::sla::Interior::voxel_scale.

Referenced by get_distance(), and get_distance().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_mesh() [1/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Bridge & br,
size_t steps )
inline
94{
95 using Quaternion = Eigen::Quaternion<float>;
96 Vec3d v = (br.endp - br.startp);
97 Vec3d dir = v.normalized();
98 double d = v.norm();
99
100 indexed_triangle_set mesh = cylinder(br.r, d, steps);
101
102 auto quater = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, 1.f},
103 dir.cast<float>());
104
105 Vec3f startp = br.startp.cast<float>();
106 for(auto& p : mesh.vertices) p = quater * p + startp;
107
108 return mesh;
109}
indexed_triangle_set cylinder(double r, double h, size_t ssteps, const Vec3d &sp)
Definition SupportTreeMesher.cpp:105
Vec3d endp
Definition SupportTreeBuilder.hpp:176
Vec3d startp
Definition SupportTreeBuilder.hpp:176
double r
Definition SupportTreeBuilder.hpp:175

References cylinder(), Slic3r::sla::Bridge::endp, Slic3r::sla::Bridge::r, and Slic3r::sla::Bridge::startp.

Here is the call graph for this function:

◆ get_mesh() [2/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const DiffBridge & br,
size_t steps )
inline
112{
113 double h = br.get_length();
114 indexed_triangle_set mesh = halfcone(h, br.r, br.end_r, Vec3d::Zero(), steps);
115
116 using Quaternion = Eigen::Quaternion<float>;
117
118 // We rotate the head to the specified direction. The head's pointing
119 // side is facing upwards so this means that it would hold a support
120 // point with a normal pointing straight down. This is the reason of
121 // the -1 z coordinate
122 auto quatern = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, 1.f},
123 br.get_dir().cast<float>());
124
125 Vec3f startp = br.startp.cast<float>();
126 for(auto& p : mesh.vertices) p = quatern * p + startp;
127
128 return mesh;
129}
indexed_triangle_set halfcone(double baseheight, double r_bottom, double r_top, const Vec3d &pos, size_t steps)
Definition SupportTreeMesher.cpp:228
Vec3d get_dir() const
Definition SupportTreeBuilder.hpp:184
double get_length() const
Definition SupportTreeBuilder.hpp:183
double end_r
Definition SupportTreeBuilder.hpp:188

References Slic3r::cast(), Slic3r::sla::DiffBridge::end_r, Slic3r::sla::Bridge::get_dir(), Slic3r::sla::Bridge::get_length(), halfcone(), Slic3r::sla::Bridge::r, and Slic3r::sla::Bridge::startp.

Here is the call graph for this function:

◆ get_mesh() [3/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Head & h,
size_t steps )
inline
49{
50 indexed_triangle_set mesh = pinhead(h.r_pin_mm, h.r_back_mm, h.width_mm, steps);
51
52 for (auto& p : mesh.vertices) p.z() -= (h.fullwidth() - h.r_back_mm);
53
54 using Quaternion = Eigen::Quaternion<float>;
55
56 // We rotate the head to the specified direction. The head's pointing
57 // side is facing upwards so this means that it would hold a support
58 // point with a normal pointing straight down. This is the reason of
59 // the -1 z coordinate
60 auto quatern = Quaternion::FromTwoVectors(Vec3f{0.f, 0.f, -1.f},
61 h.dir.cast<float>());
62
63 Vec3f pos = h.pos.cast<float>();
64 for (auto& p : mesh.vertices) p = quatern * p + pos;
65
66 return mesh;
67}
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
indexed_triangle_set pinhead(double r_pin, double r_back, double length, size_t steps)
Definition SupportTreeMesher.cpp:167
Vec3d pos
Definition SupportTreeBuilder.hpp:80
double r_pin_mm
Definition SupportTreeBuilder.hpp:83
double fullwidth() const
Definition SupportTreeBuilder.hpp:109
double r_back_mm
Definition SupportTreeBuilder.hpp:82
Vec3d dir
Definition SupportTreeBuilder.hpp:79
double width_mm
Definition SupportTreeBuilder.hpp:84

References Slic3r::sla::Head::dir, Slic3r::sla::Head::fullwidth(), pinhead(), Slic3r::sla::Head::pos, pos(), Slic3r::sla::Head::r_back_mm, Slic3r::sla::Head::r_pin_mm, and Slic3r::sla::Head::width_mm.

Here is the call graph for this function:

◆ get_mesh() [4/8]

const indexed_triangle_set & Slic3r::sla::get_mesh ( const Interior & interior)
75{
76 return interior.mesh;
77}

References Slic3r::sla::Interior::mesh.

◆ get_mesh() [5/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Junction & j,
size_t steps )
inline
86{
87 indexed_triangle_set mesh = sphere(j.r, make_portion(0, PI), 2 *PI / steps);
88 Vec3f pos = j.pos.cast<float>();
89 for(auto& p : mesh.vertices) p += pos;
90 return mesh;
91}
indexed_triangle_set sphere(double rho, Portion portion, double fa)
Definition SupportTreeMesher.cpp:14
Portion make_portion(double a, double b)
Definition SupportTreeMesher.hpp:18
Vec3d pos
Definition SupportTreeBuilder.hpp:129
double r
Definition SupportTreeBuilder.hpp:128

References make_portion(), PI, Slic3r::sla::Junction::pos, pos(), Slic3r::sla::Junction::r, and sphere().

Here is the call graph for this function:

◆ get_mesh() [6/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Pedestal & p,
size_t steps )
inline
81{
82 return halfcone(p.height, p.r_bottom, p.r_top, p.pos, steps);
83}
double height
Definition SupportTreeBuilder.hpp:162
Vec3d pos
Definition SupportTreeBuilder.hpp:161
double r_top
Definition SupportTreeBuilder.hpp:162
double r_bottom
Definition SupportTreeBuilder.hpp:162

References halfcone(), Slic3r::sla::Pedestal::height, Slic3r::sla::Pedestal::pos, Slic3r::sla::Pedestal::r_bottom, and Slic3r::sla::Pedestal::r_top.

Here is the call graph for this function:

◆ get_mesh() [7/8]

indexed_triangle_set Slic3r::sla::get_mesh ( const Pillar & p,
size_t steps )
inline
70{
71 if(p.height > EPSILON) { // Endpoint is below the starting point
72 // We just create a bridge geometry with the pillar parameters and
73 // move the data.
74 return cylinder(p.r, p.height, steps, p.endpoint());
75 }
76
77 return {};
78}
double height
Definition SupportTreeBuilder.hpp:135
double r
Definition SupportTreeBuilder.hpp:135
const Vec3d & endpoint() const
Definition SupportTreeBuilder.hpp:156

References cylinder(), Slic3r::sla::Pillar::endpoint(), EPSILON, Slic3r::sla::Pillar::height, and Slic3r::sla::Pillar::r.

Here is the call graph for this function:

◆ get_mesh() [8/8]

indexed_triangle_set & Slic3r::sla::get_mesh ( Interior & interior)
70{
71 return interior.mesh;
72}

References Slic3r::sla::Interior::mesh.

Referenced by Slic3r::create_exclude_mask(), Slic3r::SLAPrint::Steps::hollow_model(), Slic3r::SLAPrintObject::hollowed_interior_mesh(), Slic3r::sla::SupportTreeBuilder::merged_mesh(), and Slic3r::SLAPrint::Steps::slice_model().

Here is the caller graph for this function:

◆ halfcone()

indexed_triangle_set Slic3r::sla::halfcone ( double baseheight,
double r_bottom,
double r_top,
const Vec3d & pos,
size_t steps )
233{
234 assert(steps > 0);
235
236 if (baseheight <= 0 || steps <= 0) return {};
237
238 indexed_triangle_set base;
239
240 double a = 2 * PI / steps;
241 auto last = int(steps - 1);
242 Vec3d ep{pos.x(), pos.y(), pos.z() + baseheight};
243 for (size_t i = 0; i < steps; ++i) {
244 double phi = i * a;
245 auto x = float(pos.x() + r_top * std::cos(phi));
246 auto y = float(pos.y() + r_top * std::sin(phi));
247 base.vertices.emplace_back(x, y, float(ep.z()));
248 }
249
250 for (size_t i = 0; i < steps; ++i) {
251 double phi = i * a;
252 auto x = float(pos.x() + r_bottom * std::cos(phi));
253 auto y = float(pos.y() + r_bottom * std::sin(phi));
254 base.vertices.emplace_back(x, y, float(pos.z()));
255 }
256
257 base.vertices.emplace_back(pos.cast<float>());
258 base.vertices.emplace_back(ep.cast<float>());
259
260 auto &indices = base.indices;
261 auto hcenter = int(base.vertices.size() - 1);
262 auto lcenter = int(base.vertices.size() - 2);
263 auto offs = int(steps);
264 for (int i = 0; i < last; ++i) {
265 indices.emplace_back(i, i + offs, offs + i + 1);
266 indices.emplace_back(i, offs + i + 1, i + 1);
267 indices.emplace_back(i, i + 1, hcenter);
268 indices.emplace_back(lcenter, offs + i + 1, offs + i);
269 }
270
271 indices.emplace_back(0, last, offs);
272 indices.emplace_back(last, offs + last, offs);
273 indices.emplace_back(hcenter, last, 0);
274 indices.emplace_back(offs, offs + last, lcenter);
275
276 return base;
277}
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68

References PI, and pos().

Referenced by get_mesh(), and get_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hollow_mesh() [1/2]

void Slic3r::sla::hollow_mesh ( TriangleMesh & mesh,
const HollowingConfig & cfg,
int flags )
324{
325 InteriorPtr interior = generate_interior(mesh, cfg, JobController{});
326 if (!interior) return;
327
328 hollow_mesh(mesh, *interior, flags);
329}
InteriorPtr generate_interior(const TriangleMesh &mesh, const HollowingConfig &hc, const JobController &ctl)
Definition Hollowing.cpp:130
void hollow_mesh(TriangleMesh &mesh, const HollowingConfig &cfg, int flags)
Definition Hollowing.cpp:323
A Control structure for the support calculation. Consists of the status indicator callback and the st...
Definition JobController.hpp:12

References generate_interior(), and hollow_mesh().

Referenced by hollow_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hollow_mesh() [2/2]

void Slic3r::sla::hollow_mesh ( TriangleMesh & mesh,
const Interior & interior,
int flags )
332{
333 if (mesh.empty() || interior.mesh.empty()) return;
334
335 if (flags & hfRemoveInsideTriangles && interior.gridptr)
336 remove_inside_triangles(mesh, interior);
337
338 mesh.merge(TriangleMesh{interior.mesh});
339}
void remove_inside_triangles(TriangleMesh &mesh, const Interior &interior, const std::vector< bool > &exclude_mask)
Definition Hollowing.cpp:432

References Slic3r::TriangleMesh::empty(), Slic3r::sla::Interior::gridptr, hfRemoveInsideTriangles, Slic3r::TriangleMesh::merge(), Slic3r::sla::Interior::mesh, and remove_inside_triangles().

Here is the call graph for this function:

◆ initvals()

template<size_t N>
Input< N > Slic3r::opt::initvals ( const double(&) a[N])
176{ return detail::to_arr(a); }

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_ground(), Slic3r::sla::SupportTreeBuildsteps::filter(), and Slic3r::sla::SupportTreeBuildsteps::search_widening_path().

Here is the caller graph for this function:

◆ make_layers()

std::vector< SupportPointGenerator::MyLayer > Slic3r::sla::make_layers ( const std::vector< ExPolygons > & slices,
const std::vector< float > & heights,
std::function< void(void)> throw_on_cancel )
static
134{
135 assert(slices.size() == heights.size());
136
137 // Allocate empty layers.
138 std::vector<SupportPointGenerator::MyLayer> layers;
139 layers.reserve(slices.size());
140 for (size_t i = 0; i < slices.size(); ++ i)
141 layers.emplace_back(i, heights[i]);
142
143 // FIXME: calculate actual pixel area from printer config:
144 //const float pixel_area = pow(wxGetApp().preset_bundle->project_config.option<ConfigOptionFloat>("display_width") / wxGetApp().preset_bundle->project_config.option<ConfigOptionInt>("display_pixels_x"), 2.f); //
145 const float pixel_area = pow(0.047f, 2.f);
146
147 ccr_par::for_each(size_t(0), layers.size(),
148 [&layers, &slices, &heights, pixel_area, throw_on_cancel](size_t layer_id)
149 {
150 if ((layer_id % 8) == 0)
151 // Don't call the following function too often as it flushes
152 // CPU write caches due to synchronization primitves.
153 throw_on_cancel();
154
155 SupportPointGenerator::MyLayer &layer = layers[layer_id];
156 const ExPolygons & islands = slices[layer_id];
157 // FIXME WTF?
158 const float height = (layer_id > 2 ?
159 heights[layer_id - 3] :
160 heights[0] - (heights[1] - heights[0]));
161 layer.islands.reserve(islands.size());
162 for (const ExPolygon &island : islands) {
163 float area = float(island.area() * SCALING_FACTOR * SCALING_FACTOR);
164 if (area >= pixel_area)
165 // FIXME this is not a correct centroid of a polygon with holes.
166 layer.islands.emplace_back(layer, island, get_extents(island.contour),
167 unscaled<float>(island.contour.centroid()), area, height);
168 }
169 }, 32 /*gransize*/);
170
171 // Calculate overlap of successive layers. Link overlapping islands.
172 ccr_par::for_each(size_t(1), layers.size(),
173 [&layers, &heights, throw_on_cancel] (size_t layer_id)
174 {
175 if ((layer_id % 2) == 0)
176 // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
177 throw_on_cancel();
178 SupportPointGenerator::MyLayer &layer_above = layers[layer_id];
179 SupportPointGenerator::MyLayer &layer_below = layers[layer_id - 1];
180 //FIXME WTF?
181 const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]);
182 const float safe_angle = 35.f * (float(M_PI)/180.f); // smaller number - less supports
183 const float between_layers_offset = scaled<float>(layer_height * std::tan(safe_angle));
184 const float slope_angle = 75.f * (float(M_PI)/180.f); // smaller number - less supports
185 const float slope_offset = scaled<float>(layer_height * std::tan(slope_angle));
186 //FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands.
187 for (SupportPointGenerator::Structure &top : layer_above.islands) {
188 for (SupportPointGenerator::Structure &bottom : layer_below.islands) {
189 float overlap_area = top.overlap_area(bottom);
190 if (overlap_area > 0) {
191 top.islands_below.emplace_back(&bottom, overlap_area);
192 bottom.islands_above.emplace_back(&top, overlap_area);
193 }
194 }
195 if (! top.islands_below.empty()) {
196 Polygons bottom_polygons = top.polygons_below();
197 top.overhangs = diff_ex(*top.polygon, bottom_polygons);
198 if (! top.overhangs.empty()) {
199
200 // Produce 2 bands around the island, a safe band for dangling overhangs
201 // and an unsafe band for sloped overhangs.
202 // These masks include the original island
203 auto dangl_mask = expand(bottom_polygons, between_layers_offset, jtSquare);
204 auto overh_mask = expand(bottom_polygons, slope_offset, jtSquare);
205
206 // Absolutely hopeless overhangs are those outside the unsafe band
207 top.overhangs = diff_ex(*top.polygon, overh_mask);
208
209 // Now cut out the supported core from the safe band
210 // and cut the safe band from the unsafe band to get distinct
211 // zones.
212 overh_mask = diff(overh_mask, dangl_mask);
213 dangl_mask = diff(dangl_mask, bottom_polygons);
214
215 top.dangling_areas = intersection_ex(*top.polygon, dangl_mask);
216 top.overhangs_slopes = intersection_ex(*top.polygon, overh_mask);
217
218 top.overhangs_area = 0.f;
219 std::vector<std::pair<ExPolygon*, float>> expolys_with_areas;
220 for (ExPolygon &ex : top.overhangs) {
221 float area = float(ex.area());
222 expolys_with_areas.emplace_back(&ex, area);
223 top.overhangs_area += area;
224 }
225 std::sort(expolys_with_areas.begin(), expolys_with_areas.end(),
226 [](const std::pair<ExPolygon*, float> &p1, const std::pair<ExPolygon*, float> &p2)
227 { return p1.second > p2.second; });
228 ExPolygons overhangs_sorted;
229 for (auto &p : expolys_with_areas)
230 overhangs_sorted.emplace_back(std::move(*p.first));
231 top.overhangs = std::move(overhangs_sorted);
232 top.overhangs_area *= float(SCALING_FACTOR * SCALING_FACTOR);
233 }
234 }
235 }
236 }, 8 /* gransize */);
237
238 return layers;
239}
static void for_each(It from, It to, Fn &&fn, size_t granularity=1)
Definition Concurrency.hpp:26

References Slic3r::sla::_ccr< true >::for_each().

Referenced by Slic3r::sla::SupportPointGenerator::process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_portion()

Portion Slic3r::sla::make_portion ( double a,
double b )
inline
19{
20 return std::make_tuple(a, b);
21}

Referenced by get_mesh(), and pinhead().

Here is the caller graph for this function:

◆ min_hit()

template<class C, class Hit = IndexedMesh::hit_result>
Hit Slic3r::sla::min_hit ( const C & hits)
static
49{
50 auto mit = std::min_element(hits.begin(), hits.end(),
51 [](const Hit &h1, const Hit &h2) {
52 return h1.distance() < h2.distance();
53 });
54
55 return *mit;
56}

◆ normals()

PointSet Slic3r::sla::normals ( const PointSet & points,
const IndexedMesh & mesh,
double eps,
std::function< void()> thr,
const std::vector< unsigned > & pt_indices )
347{
348 if (points.rows() == 0 || mesh.vertices().empty() || mesh.indices().empty())
349 return {};
350
351 std::vector<unsigned> range = pt_indices;
352 if (range.empty()) {
353 range.resize(size_t(points.rows()), 0);
354 std::iota(range.begin(), range.end(), 0);
355 }
356
357 PointSet ret(range.size(), 3);
358
359 // for (size_t ridx = 0; ridx < range.size(); ++ridx)
360 ccr::for_each(size_t(0), range.size(),
361 [&ret, &mesh, &points, thr, eps, &range](size_t ridx) {
362 thr();
363 unsigned el = range[ridx];
364 auto eidx = Eigen::Index(el);
365 int faceid = 0;
366 Vec3d p;
367
368 mesh.squared_distance(points.row(eidx), faceid, p);
369
370 auto trindex = mesh.indices(faceid);
371
372 const Vec3d &p1 = mesh.vertices(trindex(0)).cast<double>();
373 const Vec3d &p2 = mesh.vertices(trindex(1)).cast<double>();
374 const Vec3d &p3 = mesh.vertices(trindex(2)).cast<double>();
375
376 // We should check if the point lies on an edge of the hosting
377 // triangle. If it does then all the other triangles using the
378 // same two points have to be searched and the final normal should
379 // be some kind of aggregation of the participating triangle
380 // normals. We should also consider the cases where the support
381 // point lies right on a vertex of its triangle. The procedure is
382 // the same, get the neighbor triangles and calculate an average
383 // normal.
384
385 // mark the vertex indices of the edge. ia and ib marks and edge
386 // ic will mark a single vertex.
387 int ia = -1, ib = -1, ic = -1;
388
389 if (std::abs((p - p1).norm()) < eps) {
390 ic = trindex(0);
391 } else if (std::abs((p - p2).norm()) < eps) {
392 ic = trindex(1);
393 } else if (std::abs((p - p3).norm()) < eps) {
394 ic = trindex(2);
395 } else if (point_on_edge(p, p1, p2, eps)) {
396 ia = trindex(0);
397 ib = trindex(1);
398 } else if (point_on_edge(p, p2, p3, eps)) {
399 ia = trindex(1);
400 ib = trindex(2);
401 } else if (point_on_edge(p, p1, p3, eps)) {
402 ia = trindex(0);
403 ib = trindex(2);
404 }
405
406 // vector for the neigboring triangles including the detected one.
407 std::vector<size_t> neigh;
408 if (ic >= 0) { // The point is right on a vertex of the triangle
409 for (size_t n = 0; n < mesh.indices().size(); ++n) {
410 thr();
411 Vec3i32 ni = mesh.indices(n);
412 if ((ni(X) == ic || ni(Y) == ic || ni(Z) == ic))
413 neigh.emplace_back(n);
414 }
415 } else if (ia >= 0 && ib >= 0) { // the point is on and edge
416 // now get all the neigboring triangles
417 for (size_t n = 0; n < mesh.indices().size(); ++n) {
418 thr();
419 Vec3i32 ni = mesh.indices(n);
420 if ((ni(X) == ia || ni(Y) == ia || ni(Z) == ia) &&
421 (ni(X) == ib || ni(Y) == ib || ni(Z) == ib))
422 neigh.emplace_back(n);
423 }
424 }
425
426 // Calculate the normals for the neighboring triangles
427 std::vector<Vec3d> neighnorms;
428 neighnorms.reserve(neigh.size());
429 for (size_t &tri_id : neigh)
430 neighnorms.emplace_back(mesh.normal_by_face_id(tri_id));
431
432 // Throw out duplicates. They would cause trouble with summing. We
433 // will use std::unique which works on sorted ranges. We will sort
434 // by the coefficient-wise sum of the normals. It should force the
435 // same elements to be consecutive.
436 std::sort(neighnorms.begin(), neighnorms.end(),
437 [](const Vec3d &v1, const Vec3d &v2) {
438 return v1.sum() < v2.sum();
439 });
440
441 auto lend = std::unique(neighnorms.begin(), neighnorms.end(),
442 [](const Vec3d &n1, const Vec3d &n2) {
443 // Compare normals for equivalence.
444 // This is controvers stuff.
445 auto deq = [](double a, double b) {
446 return std::abs(a - b) < 1e-3;
447 };
448 return deq(n1(X), n2(X)) &&
449 deq(n1(Y), n2(Y)) &&
450 deq(n1(Z), n2(Z));
451 });
452
453 if (!neighnorms.empty()) { // there were neighbors to count with
454 // sum up the normals and then normalize the result again.
455 // This unification seems to be enough.
456 Vec3d sumnorm(0, 0, 0);
457 sumnorm = std::accumulate(neighnorms.begin(), lend, sumnorm);
458 sumnorm.normalize();
459 ret.row(long(ridx)) = sumnorm;
460 } else { // point lies safely within its triangle
461 Eigen::Vector3d U = p2 - p1;
462 Eigen::Vector3d V = p3 - p1;
463 ret.row(long(ridx)) = U.cross(V).normalized();
464 }
465 });
466
467 return ret;
468}
const std::vector< Vec3i32 > & indices() const
Definition IndexedMesh.cpp:133
const std::vector< Vec3f > & vertices() const
Definition IndexedMesh.cpp:126
Vec3d normal_by_face_id(int face_id) const
Definition IndexedMesh.cpp:153
Eigen::MatrixXd PointSet
Definition IndexedMesh.hpp:32
static bool point_on_edge(const Vec3d &p, const Vec3d &e1, const Vec3d &e2, double eps=0.05)
Definition IndexedMesh.cpp:332
auto range(Cont &&cont)
Definition libslic3r.h:405
Eigen::Matrix< int32_t, 3, 1, Eigen::DontAlign > Vec3i32
Definition Point.hpp:59

References Slic3r::sla::IndexedMesh::indices(), Slic3r::sla::IndexedMesh::normal_by_face_id(), point_on_edge(), Slic3r::range(), Slic3r::sla::IndexedMesh::vertices(), X, Y, and Z.

Referenced by Slic3r::sla::SupportTreeBuildsteps::filter().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ offset_waffle_style()

Polygons Slic3r::sla::offset_waffle_style ( const ConcaveHull & hull,
coord_t delta )
145{
146 auto arc_tolerance = scaled<double>(0.01);
147 Polygons res = closing(hull.polygons(), 2 * delta, delta, jtRound, arc_tolerance);
148
149 auto it = std::remove_if(res.begin(), res.end(), [](Polygon &p) { return p.is_clockwise(); });
150 res.erase(it, res.end());
151
152 return res;
153}
Definition Polygon.hpp:31
const Polygons & polygons() const
Definition ConcaveHull.hpp:48
@ jtRound
Definition ClipperUtils.hpp:21
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
Slic3r::Polygons closing(const Slic3r::Polygons &polygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:670

References Slic3r::closing(), Slic3r::jtRound, Slic3r::sla::ConcaveHull::polygons(), and Slic3r::scaled().

Referenced by offset_waffle_style_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ offset_waffle_style_ex()

ExPolygons Slic3r::sla::offset_waffle_style_ex ( const ConcaveHull & hull,
coord_t delta )
140{
141 return to_expolygons(offset_waffle_style(hull, delta));
142}
Polygons offset_waffle_style(const ConcaveHull &hull, coord_t delta)
Definition ConcaveHull.cpp:144
ExPolygons to_expolygons(const Polygons &polys)
Definition ExPolygon.hpp:373

References offset_waffle_style(), and Slic3r::to_expolygons().

Referenced by Slic3r::sla::anonymous_namespace{Pad.cpp}::BelowPadSkeleton::BelowPadSkeleton(), and Slic3r::sla::anonymous_namespace{Pad.cpp}::_AroundPadSkeleton< Intersector >::wafflized_concave_hull().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator<<()

std::ostream & Slic3r::sla::operator<< ( std::ostream & stream,
const EncodedRaster & bytes )
49{
50 stream.write(reinterpret_cast<const char *>(bytes.data()),
51 std::streamsize(bytes.size()));
52
53 return stream;
54}
const void * data() const
Definition RasterBase.hpp:34
size_t size() const
Definition RasterBase.hpp:33

References Slic3r::sla::EncodedRaster::data(), and Slic3r::sla::EncodedRaster::size().

Here is the call graph for this function:

◆ pad_blueprint() [1/2]

void Slic3r::sla::pad_blueprint ( const indexed_triangle_set & mesh,
ExPolygons & output,
const std::vector< float > & heights,
ThrowOnCancel thrfn )

Calculate the polygon representing the silhouette.

474{
475 if (mesh.empty()) return;
476
477 std::vector<ExPolygons> out = slice_mesh_ex(mesh, heights, thrfn);
478
479 size_t count = 0;
480 for(auto& o : out) count += o.size();
481
482 // Unification is expensive, a simplify also speeds up the pad generation
484 for(ExPolygons& o : out)
485 for(ExPolygon& e : o) {
486 auto&& exss = e.simplify(scaled<double>(0.1));
487 for(ExPolygon& ep : exss) tmp.emplace_back(std::move(ep));
488 }
489
490 ExPolygons utmp = union_ex(tmp);
491
492 for(auto& o : utmp) {
493 auto&& smp = o.simplify(scaled<double>(0.1));
494 output.insert(output.end(), smp.begin(), smp.end());
495 }
496}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011

References count, Slic3r::reserve_vector(), Slic3r::scaled(), Slic3r::slice_mesh_ex(), and Slic3r::union_ex().

Referenced by Slic3r::sla::Pad::Pad(), Slic3r::SLAPrint::Steps::generate_pad(), and pad_blueprint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pad_blueprint() [2/2]

void Slic3r::sla::pad_blueprint ( const indexed_triangle_set & mesh,
ExPolygons & output,
float h,
float layerh,
ThrowOnCancel thrfn )
503{
504 float gnd = float(bounding_box(mesh).min(Z));
505
506 std::vector<float> slicegrid = grid(gnd, gnd + h, layerh);
507 pad_blueprint(mesh, output, slicegrid, thrfn);
508}
void pad_blueprint(const indexed_triangle_set &mesh, ExPolygons &output, const std::vector< float > &heights, ThrowOnCancel thrfn)
Calculate the polygon representing the silhouette.
Definition Pad.cpp:470
BoundingBoxf3 bounding_box(const TriangleMesh &m)
Definition TriangleMesh.hpp:391
std::vector< ArithmeticOnly< T > > grid(const T &start, const T &stop, const T &stride)
A set of equidistant values starting from 'start' (inclusive), ending in the closest multiple of 'str...
Definition MTUtils.hpp:127

References Slic3r::bounding_box(), Slic3r::grid(), pad_blueprint(), and Z.

Here is the call graph for this function:

◆ pairhash()

template<class I, class DoubleI = IntegerOnly<I>>
IntegerOnly< DoubleI > Slic3r::sla::pairhash ( I a,
I b )
192{
193 using std::ceil; using std::log2; using std::max; using std::min;
194 static const auto constexpr Ibits = int(sizeof(I) * CHAR_BIT);
195 static const auto constexpr DoubleIbits = int(sizeof(DoubleI) * CHAR_BIT);
196 static const auto constexpr shift = DoubleIbits / 2 < Ibits ? Ibits / 2 : Ibits;
197
198 I g = min(a, b), l = max(a, b);
199
200 // Assume the hash will fit into the output variable
201 assert((g ? (ceil(log2(g))) : 0) <= shift);
202 assert((l ? (ceil(log2(l))) : 0) <= shift);
203
204 return (DoubleI(g) << shift) + l;
205}
@ I
Definition libslic3r.h:147

References Slic3r::I.

Referenced by Slic3r::sla::SupportTreeBuildsteps::interconnect_pillars().

Here is the caller graph for this function:

◆ pinhead()

indexed_triangle_set Slic3r::sla::pinhead ( double r_pin,
double r_back,
double length,
size_t steps )
171{
172 assert(steps > 0);
173 assert(length >= 0.);
174 assert(r_back > 0.);
175 assert(r_pin > 0.);
176
177 indexed_triangle_set mesh;
178
179 // We create two spheres which will be connected with a robe that fits
180 // both circles perfectly.
181
182 // Set up the model detail level
183 const double detail = 2 * PI / steps;
184
185 // We don't generate whole circles. Instead, we generate only the
186 // portions which are visible (not covered by the robe) To know the
187 // exact portion of the bottom and top circles we need to use some
188 // rules of tangent circles from which we can derive (using simple
189 // triangles the following relations:
190
191 // The height of the whole mesh
192 const double h = r_back + r_pin + length;
193 double phi = PI / 2. - std::acos((r_back - r_pin) / h);
194
195 // To generate a whole circle we would pass a portion of (0, Pi)
196 // To generate only a half horizontal circle we can pass (0, Pi/2)
197 // The calculated phi is an offset to the half circles needed to smooth
198 // the transition from the circle to the robe geometry
199
200 auto &&s1 = sphere(r_back, make_portion(0, PI / 2 + phi), detail);
201 auto &&s2 = sphere(r_pin, make_portion(PI / 2 + phi, PI), detail);
202
203 for (auto &p : s2.vertices) p.z() += h;
204
205 its_merge(mesh, s1);
206 its_merge(mesh, s2);
207
208 for (size_t idx1 = s1.vertices.size() - steps, idx2 = s1.vertices.size();
209 idx1 < s1.vertices.size() - 1; idx1++, idx2++) {
210 coord_t i1s1 = coord_t(idx1), i1s2 = coord_t(idx2);
211 coord_t i2s1 = i1s1 + 1, i2s2 = i1s2 + 1;
212
213 mesh.indices.emplace_back(i1s1, i2s1, i2s2);
214 mesh.indices.emplace_back(i1s1, i2s2, i1s2);
215 }
216
217 auto i1s1 = coord_t(s1.vertices.size()) - coord_t(steps);
218 auto i2s1 = coord_t(s1.vertices.size()) - 1;
219 auto i1s2 = coord_t(s1.vertices.size());
220 auto i2s2 = coord_t(s1.vertices.size()) + coord_t(steps) - 1;
221
222 mesh.indices.emplace_back(i2s2, i2s1, i1s1);
223 mesh.indices.emplace_back(i1s2, i2s2, i1s1);
224
225 return mesh;
226}
int64_t coord_t
Definition libslic3r.h:48
Definition LifecycleEvents.hpp:174
double length(const Points &pts)
Definition MultiPoint.hpp:181

References Slic3r::its_merge(), Slic3r::length(), make_portion(), PI, and sphere().

Referenced by get_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ point_on_edge()

bool Slic3r::sla::point_on_edge ( const Vec3d & p,
const Vec3d & e1,
const Vec3d & e2,
double eps = 0.05 )
static
334{
335 using Line3D = Eigen::ParametrizedLine<double, 3>;
336
337 auto line = Line3D::Through(e1, e2);
338 double d = line.distance(p);
339 return std::abs(d) < eps;
340}

Referenced by normals().

Here is the caller graph for this function:

◆ poisson_disk_from_samples()

template<typename REFUSE_FUNCTION>
std::vector< Vec2f > Slic3r::sla::poisson_disk_from_samples ( const std::vector< Vec2f > & raw_samples,
float radius,
REFUSE_FUNCTION refuse_function )
inlinestatic
445{
446 Vec2f corner_min(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
447 for (const Vec2f &pt : raw_samples) {
448 corner_min.x() = std::min(corner_min.x(), pt.x());
449 corner_min.y() = std::min(corner_min.y(), pt.y());
450 }
451
452 // Assign the raw samples to grid cells, sort the grid cells lexicographically.
453 struct RawSample
454 {
455 Vec2f coord;
456 Vec2i32 cell_id;
457 RawSample(const Vec2f &crd = {}, const Vec2i32 &id = {}): coord{crd}, cell_id{id} {}
458 };
459
460 auto raw_samples_sorted = reserve_vector<RawSample>(raw_samples.size());
461 for (const Vec2f &pt : raw_samples)
462 raw_samples_sorted.emplace_back(pt, ((pt - corner_min) / radius).cast<int>());
463
464 std::sort(raw_samples_sorted.begin(), raw_samples_sorted.end(), [](const RawSample &lhs, const RawSample &rhs)
465 { return lhs.cell_id.x() < rhs.cell_id.x() || (lhs.cell_id.x() == rhs.cell_id.x() && lhs.cell_id.y() < rhs.cell_id.y()); });
466
467 struct PoissonDiskGridEntry {
468 // Resulting output sample points for this cell:
469 enum {
470 max_positions = 4
471 };
472 Vec2f poisson_samples[max_positions];
473 int num_poisson_samples = 0;
474
475 // Index into raw_samples:
476 int first_sample_idx;
477 int sample_cnt;
478 };
479
480 struct CellIDHash {
481 std::size_t operator()(const Vec2i32 &cell_id) const {
482 return std::hash<int>()(cell_id.x()) ^ std::hash<int>()(cell_id.y() * 593);
483 }
484 };
485
486 // Map from cell IDs to hash_data. Each hash_data points to the range in raw_samples corresponding to that cell.
487 // (We could just store the samples in hash_data. This implementation is an artifact of the reference paper, which
488 // is optimizing for GPU acceleration that we haven't implemented currently.)
489 typedef std::unordered_map<Vec2i32, PoissonDiskGridEntry, CellIDHash> Cells;
490 Cells cells;
491 {
492 typename Cells::iterator last_cell_id_it;
493 Vec2i32 last_cell_id(-1, -1);
494 for (size_t i = 0; i < raw_samples_sorted.size(); ++ i) {
495 const RawSample &sample = raw_samples_sorted[i];
496 if (sample.cell_id == last_cell_id) {
497 // This sample is in the same cell as the previous, so just increase the count. Cells are
498 // always contiguous, since we've sorted raw_samples_sorted by cell ID.
499 ++ last_cell_id_it->second.sample_cnt;
500 } else {
501 // This is a new cell.
502 PoissonDiskGridEntry data;
503 data.first_sample_idx = int(i);
504 data.sample_cnt = 1;
505 auto result = cells.insert({sample.cell_id, data});
506 last_cell_id = sample.cell_id;
507 last_cell_id_it = result.first;
508 }
509 }
510 }
511
512 const int max_trials = 5;
513 const float radius_squared = radius * radius;
514 for (int trial = 0; trial < max_trials; ++ trial) {
515 // Create sample points for each entry in cells.
516 for (auto &it : cells) {
517 const Vec2i32 &cell_id = it.first;
518 PoissonDiskGridEntry &cell_data = it.second;
519 // This cell's raw sample points start at first_sample_idx. On trial 0, try the first one. On trial 1, try first_sample_idx + 1.
520 int next_sample_idx = cell_data.first_sample_idx + trial;
521 if (trial >= cell_data.sample_cnt)
522 // There are no more points to try for this cell.
523 continue;
524 const RawSample &candidate = raw_samples_sorted[next_sample_idx];
525 // See if this point conflicts with any other points in this cell, or with any points in
526 // neighboring cells. Note that it's possible to have more than one point in the same cell.
527 bool conflict = refuse_function(candidate.coord);
528 for (int i = -1; i < 2 && ! conflict; ++ i) {
529 for (int j = -1; j < 2; ++ j) {
530 const auto &it_neighbor = cells.find(cell_id + Vec2i32(i, j));
531 if (it_neighbor != cells.end()) {
532 const PoissonDiskGridEntry &neighbor = it_neighbor->second;
533 for (int i_sample = 0; i_sample < neighbor.num_poisson_samples; ++ i_sample)
534 if ((neighbor.poisson_samples[i_sample] - candidate.coord).squaredNorm() < radius_squared) {
535 conflict = true;
536 break;
537 }
538 }
539 }
540 }
541 if (! conflict) {
542 // Store the new sample.
543 assert(cell_data.num_poisson_samples < cell_data.max_positions);
544 if (cell_data.num_poisson_samples < cell_data.max_positions)
545 cell_data.poisson_samples[cell_data.num_poisson_samples ++] = candidate.coord;
546 }
547 }
548 }
549
550 // Copy the results to the output.
551 std::vector<Vec2f> out;
552 for (const auto& it : cells)
553 for (int i = 0; i < it.second.num_poisson_samples; ++ i)
554 out.emplace_back(it.second.poisson_samples[i]);
555 return out;
556}
Eigen::Matrix< int32_t, 2, 1, Eigen::DontAlign > Vec2i32
Definition Point.hpp:57
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:64

References Slic3r::cast(), poisson_disk_from_samples(), and Slic3r::reserve_vector().

Referenced by poisson_disk_from_samples(), and Slic3r::sla::SupportPointGenerator::uniformly_cover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pos() [1/2]

template<class Pt>
Vec3d Slic3r::sla::pos ( const Pt & p)
16{ return p.pos.template cast<double>(); }

References Slic3r::cast().

Referenced by Slic3r::sla::SupportPointGenerator::PointGrid3D::cell_id(), Slic3r::sla::SupportPointGenerator::PointGrid3D::collides_with(), Slic3r::sla::SupportPointGenerator::PointGrid3D::collides_with(), get_mesh(), get_mesh(), halfcone(), Slic3r::sla::SupportPointGenerator::PointGrid3D::insert(), and Slic3r::sla::SupportPointGenerator::uniformly_cover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pos() [2/2]

template<class Pt>
void Slic3r::sla::pos ( Pt & p,
const Vec3d & pp )
17{ p.pos = pp.cast<float>(); }

◆ raster_to_polygons()

ExPolygons Slic3r::sla::raster_to_polygons ( const RasterGrayscaleAA & rst,
Vec2i32 windowsize )
46{
47 size_t rows = rst.resolution().height_px, cols = rst.resolution().width_px;
48
49 if (rows < 2 || cols < 2) return {};
50
51 Polygons polys;
52 long w_rows = std::max(1l, long(windowsize.y()));
53 long w_cols = std::max(1l, long(windowsize.x()));
54
55 std::vector<marchsq::Ring> rings =
56 marchsq::execute(rst, 128, {w_rows, w_cols});
57
58 polys.reserve(rings.size());
59
60 auto pxd = rst.pixel_dimensions();
61
62 for (const marchsq::Ring &ring : rings) {
63 Polygon poly; Points &pts = poly.points;
64 pts.reserve(ring.size());
65
66 for (const marchsq::Coord &crd : ring)
67 pts.emplace_back(scaled(crd.c * pxd.w_mm), scaled(crd.r * pxd.h_mm));
68
69 polys.emplace_back(poly);
70 }
71
72 // reverse the raster transformations
73 ExPolygons unioned = union_ex(polys);
74 coord_t width = scaled(cols * pxd.h_mm), height = scaled(rows * pxd.w_mm);
75
76 auto tr = rst.trafo();
77 for (ExPolygon &expoly : unioned) {
78 if (tr.mirror_y)
79 foreach_vertex(expoly, [height](Point &p) {p.y() = height - p.y(); });
80
81 if (tr.mirror_x)
82 foreach_vertex(expoly, [width](Point &p) {p.x() = width - p.x(); });
83
84 expoly.translate(-tr.center_x, -tr.center_y);
85
86 if (tr.flipXY)
87 foreach_vertex(expoly, [](Point &p) { std::swap(p.x(), p.y()); });
88
89 if ((tr.mirror_x + tr.mirror_y + tr.flipXY) % 2) {
90 expoly.contour.reverse();
91 for (auto &h : expoly.holes) h.reverse();
92 }
93 }
94
95 return unioned;
96}
Resolution resolution() const
Definition AGGRaster.hpp:164
PixelDim pixel_dimensions() const
Definition AGGRaster.hpp:165
Trafo trafo() const override
Get the resolution of the raster.
Definition AGGRaster.hpp:163
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:1184
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:1185
void foreach_vertex(ExPolygon &poly, Fn &&fn)
Definition RasterToPolygons.cpp:38
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
std::vector< marchsq::Ring > execute(const Raster &raster, TRasterValue< Raster > isoval, Coord windowsize={})
Definition MarchingSquares.hpp:645
std::vector< Coord > Ring
Definition MarchingSquares.hpp:122
size_t height_px
Definition RasterBase.hpp:41
size_t width_px
Definition RasterBase.hpp:40
Definition MarchingSquares.hpp:95

References marchsq::execute(), foreach_vertex(), Slic3r::sla::Resolution::height_px, Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::pixel_dimensions(), Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::resolution(), Slic3r::scaled(), Slic3r::sla::AGGRaster< PixelRenderer, Renderer, Rasterizer, Scanline >::trafo(), Slic3r::union_ex(), and Slic3r::sla::Resolution::width_px.

Here is the call graph for this function:

◆ remove_bottom_points()

void Slic3r::sla::remove_bottom_points ( std::vector< SupportPoint > & pts,
float lvl )
642{
643 // get iterator to the reorganized vector end
644 auto endit = std::remove_if(pts.begin(), pts.end(), [lvl]
645 (const sla::SupportPoint &sp) {
646 return sp.pos.z() <= lvl;
647 });
648
649 // erase all elements after the new end
650 pts.erase(endit, pts.end());
651}
Definition SupportPoint.hpp:21

References remove_bottom_points().

Referenced by remove_bottom_points().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_inside_triangles()

void Slic3r::sla::remove_inside_triangles ( TriangleMesh & mesh,
const Interior & interior,
const std::vector< bool > & exclude_mask )
434{
435 enum TrPos { posInside, posTouch, posOutside };
436
437 auto &faces = mesh.its.indices;
438 auto &vertices = mesh.its.vertices;
439 auto bb = mesh.bounding_box();
440
441 bool use_exclude_mask = faces.size() == exclude_mask.size();
442 auto is_excluded = [&exclude_mask, use_exclude_mask](size_t face_id) {
443 return use_exclude_mask && exclude_mask[face_id];
444 };
445
446 // TODO: Parallel mode not working yet
447 using exec_policy = ccr_seq;
448
449 // Info about the needed modifications on the input mesh.
450 struct MeshMods {
451
452 // Just a thread safe wrapper for a vector of triangles.
453 struct {
454 std::vector<std::array<Vec3f, 3>> data;
455 exec_policy::SpinningMutex mutex;
456
457 void emplace_back(const std::array<Vec3f, 3> &pts)
458 {
459 std::lock_guard lk{mutex};
460 data.emplace_back(pts);
461 }
462
463 size_t size() const { return data.size(); }
464 const std::array<Vec3f, 3>& operator[](size_t idx) const
465 {
466 return data[idx];
467 }
468
469 } new_triangles;
470
471 // A vector of bool for all faces signaling if it needs to be removed
472 // or not.
473 std::vector<bool> to_remove;
474
475 MeshMods(const TriangleMesh &mesh):
476 to_remove(mesh.its.indices.size(), false) {}
477
478 // Number of triangles that need to be removed.
479 size_t to_remove_cnt() const
480 {
481 return std::accumulate(to_remove.begin(), to_remove.end(), size_t(0));
482 }
483
484 } mesh_mods{mesh};
485
486 // Must return true if further division of the face is needed.
487 auto divfn = [&interior, bb, &mesh_mods](const DivFace &f) {
488 BoundingBoxf3 facebb { f.verts.begin(), f.verts.end() };
489
490 // Face is certainly outside the cavity
491 if (! facebb.intersects(bb) && f.faceid != NEW_FACE) {
492 return false;
493 }
494
495 TriangleBubble bubble{facebb.center().cast<float>(), facebb.radius()};
496
497 double D = get_distance(bubble, interior);
498 double R = bubble.R * interior.voxel_scale;
499
500 if (std::isnan(D)) // The distance cannot be measured, triangle too big
501 return true;
502
503 // Distance of the bubble wall to the interior wall. Negative if the
504 // bubble is overlapping with the interior
505 double bubble_distance = D - R;
506
507 // The face is crossing the interior or inside, it must be removed and
508 // parts of it re-added, that are outside the interior
509 if (bubble_distance < 0.) {
510 if (f.faceid != NEW_FACE)
511 mesh_mods.to_remove[f.faceid] = true;
512
513 if (f.parent != NEW_FACE) // Top parent needs to be removed as well
514 mesh_mods.to_remove[f.parent] = true;
515
516 // If the outside part is between the interior end the exterior
517 // (inside the wall being invisible), no further division is needed.
518 if ((R + D) < interior.thickness)
519 return false;
520
521 return true;
522 } else if (f.faceid == NEW_FACE) {
523 // New face completely outside needs to be re-added.
524 mesh_mods.new_triangles.emplace_back(f.verts);
525 }
526
527 return false;
528 };
529
530 interior.reset_accessor();
531
532 exec_policy::for_each(size_t(0), faces.size(), [&] (size_t face_idx) {
533 const Vec3i32 &face = faces[face_idx];
534
535 // If the triangle is excluded, we need to keep it.
536 if (is_excluded(face_idx))
537 return;
538
539 std::array<Vec3f, 3> pts =
540 { vertices[face(0)], vertices[face(1)], vertices[face(2)] };
541
542 BoundingBoxf3 facebb { pts.begin(), pts.end() };
543
544 // Face is certainly outside the cavity
545 if (! facebb.intersects(bb)) return;
546
547 DivFace df{face, pts, long(face_idx)};
548
549 if (divfn(df))
550 divide_triangle(df, divfn);
551
552 }, exec_policy::max_concurreny());
553
554 auto new_faces = reserve_vector<Vec3i32>(faces.size() +
555 mesh_mods.new_triangles.size());
556
557 for (size_t face_idx = 0; face_idx < faces.size(); ++face_idx) {
558 if (!mesh_mods.to_remove[face_idx])
559 new_faces.emplace_back(faces[face_idx]);
560 }
561
562 for(size_t i = 0; i < mesh_mods.new_triangles.size(); ++i) {
563 size_t o = vertices.size();
564 vertices.emplace_back(mesh_mods.new_triangles[i][0]);
565 vertices.emplace_back(mesh_mods.new_triangles[i][1]);
566 vertices.emplace_back(mesh_mods.new_triangles[i][2]);
567 new_faces.emplace_back(int(o), int(o + 1), int(o + 2));
568 }
569
570 BOOST_LOG_TRIVIAL(info)
571 << "Trimming: " << mesh_mods.to_remove_cnt() << " triangles removed";
572 BOOST_LOG_TRIVIAL(info)
573 << "Trimming: " << mesh_mods.new_triangles.size() << " triangles added";
574
575 faces.swap(new_faces);
576 new_faces = {};
577
578 mesh = TriangleMesh{mesh.its};
579 //FIXME do we want to repair the mesh? Are there duplicate vertices or flipped triangles?
580}
BoundingBoxf3 bounding_box() const
Definition TriangleMesh.cpp:447
_ccr< false > ccr_seq
Definition Concurrency.hpp:67
Definition Hollowing.cpp:357
Definition Hollowing.cpp:386
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124

References Slic3r::TriangleMesh::bounding_box(), Slic3r::BoundingBox3Base< PointType >::center(), divide_triangle(), Slic3r::f(), get_distance(), Slic3r::BoundingBox3Base< PointType >::intersects(), Slic3r::TriangleMesh::its, NEW_FACE, Slic3r::sla::TriangleBubble::R, Slic3r::BoundingBox3Base< PointType >::radius(), Slic3r::sla::Interior::reset_accessor(), Slic3r::BoundingBox3Base< PointType >::size(), Slic3r::sla::Interior::thickness, and Slic3r::sla::Interior::voxel_scale.

Referenced by hollow_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reproject_points_and_holes()

void Slic3r::sla::reproject_points_and_holes ( ModelObject * object)
inline
31{
32 bool has_sppoints = !object->sla_support_points.empty();
33 bool has_holes = !object->sla_drain_holes.empty();
34
35 if (!object || (!has_holes && !has_sppoints)) return;
36
37 TriangleMesh rmsh = object->raw_mesh();
38 IndexedMesh emesh{rmsh};
39
40 if (has_sppoints)
42
43 if (has_holes)
45}
sla::SupportPoints sla_support_points
Definition Model.hpp:410
sla::DrainHoles sla_drain_holes
Definition Model.hpp:416
An index-triangle structure for libIGL functions. Also serves as an alternative (raw) input format fo...
Definition IndexedMesh.hpp:37
void reproject_support_points(const IndexedMesh &mesh, std::vector< PointType > &pts)
Definition ReprojectPointsOnMesh.hpp:20

References reproject_support_points(), Slic3r::ModelObject::sla_drain_holes, and Slic3r::ModelObject::sla_support_points.

Referenced by Slic3r::GUI::Plater::changed_mesh(), Slic3r::GUI::Plater::priv::reload_from_disk(), Slic3r::GUI::Plater::priv::replace_volume_with_stl(), and Slic3r::GUI::Emboss::UpdateJob::update_volume().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reproject_support_points()

template<class PointType>
void Slic3r::sla::reproject_support_points ( const IndexedMesh & mesh,
std::vector< PointType > & pts )
21{
22 tbb::parallel_for(size_t(0), pts.size(), [&mesh, &pts](size_t idx) {
23 int junk;
24 Vec3d new_pos;
25 mesh.squared_distance(pos(pts[idx]), junk, new_pos);
26 pos(pts[idx], new_pos);
27 });
28}

Referenced by reproject_points_and_holes().

Here is the caller graph for this function:

◆ sample_expolygon() [1/2]

std::vector< Vec2f > Slic3r::sla::sample_expolygon ( const ExPolygon & expoly,
float samples_per_mm2,
std::mt19937 & rng )
349{
350 // Triangulate the polygon with holes into triplets of 3D points.
351 std::vector<Vec2f> triangles = Slic3r::triangulate_expolygon_2f(expoly);
352
353 std::vector<Vec2f> out;
354 if (! triangles.empty())
355 {
356 // Calculate area of each triangle.
357 auto areas = reserve_vector<float>(triangles.size() / 3);
358 double aback = 0.;
359 for (size_t i = 0; i < triangles.size(); ) {
360 const Vec2f &a = triangles[i ++];
361 const Vec2f v1 = triangles[i ++] - a;
362 const Vec2f v2 = triangles[i ++] - a;
363
364 // Prefix sum of the areas.
365 areas.emplace_back(aback + 0.5f * std::abs(cross2(v1, v2)));
366 aback = areas.back();
367 }
368
369 size_t num_samples = size_t(ceil(areas.back() * samples_per_mm2));
370 std::uniform_real_distribution<> random_triangle(0., double(areas.back()));
371 std::uniform_real_distribution<> random_float(0., 1.);
372 for (size_t i = 0; i < num_samples; ++ i) {
373 double r = random_triangle(rng);
374 size_t idx_triangle = std::min<size_t>(std::upper_bound(areas.begin(), areas.end(), (float)r) - areas.begin(), areas.size() - 1) * 3;
375 // Select a random point on the triangle.
376 const Vec2f &a = triangles[idx_triangle ++];
377 const Vec2f &b = triangles[idx_triangle++];
378 const Vec2f &c = triangles[idx_triangle];
379#if 1
380 // https://www.cs.princeton.edu/~funk/tog02.pdf
381 // page 814, formula 1.
382 double u = float(std::sqrt(random_float(rng)));
383 double v = float(random_float(rng));
384 out.emplace_back(a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u));
385#else
386 // Greg Turk, Graphics Gems
387 // https://devsplorer.wordpress.com/2019/08/07/find-a-random-point-on-a-plane-using-barycentric-coordinates-in-unity/
388 double u = float(random_float(rng));
389 double v = float(random_float(rng));
390 if (u + v >= 1.f) {
391 u = 1.f - u;
392 v = 1.f - v;
393 }
394 out.emplace_back(a + u * (b - a) + v * (c - a));
395#endif
396 }
397 }
398 return out;
399}
int32_t cross2(const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v1, const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v2)=delete
std::vector< Vec2f > triangulate_expolygon_2f(const ExPolygon &poly, bool flip)
Definition Tesselate.cpp:238

References Slic3r::cross2(), Slic3r::reserve_vector(), sample_expolygon(), and Slic3r::triangulate_expolygon_2f().

Referenced by sample_expolygon(), sample_expolygon(), sample_expolygon_with_boundary(), and Slic3r::sla::SupportPointGenerator::uniformly_cover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sample_expolygon() [2/2]

std::vector< Vec2f > Slic3r::sla::sample_expolygon ( const ExPolygons & expolys,
float samples_per_mm2,
std::mt19937 & rng )
403{
404 std::vector<Vec2f> out;
405 for (const ExPolygon &expoly : expolys)
406 append(out, sample_expolygon(expoly, samples_per_mm2, rng));
407
408 return out;
409}
std::vector< Vec2f > sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
Definition SupportPointGenerator.cpp:348
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157

References Slic3r::append(), and sample_expolygon().

Here is the call graph for this function:

◆ sample_expolygon_boundary()

void Slic3r::sla::sample_expolygon_boundary ( const ExPolygon & expoly,
float samples_per_mm,
std::vector< Vec2f > & out,
std::mt19937 &  )
415{
416 double point_stepping_scaled = scale_(1.f) / samples_per_mm;
417 for (size_t i_contour = 0; i_contour <= expoly.holes.size(); ++ i_contour) {
418 const Polygon &contour = (i_contour == 0) ? expoly.contour :
419 expoly.holes[i_contour - 1];
420
421 const Points pts = contour.equally_spaced_points(point_stepping_scaled);
422 for (size_t i = 0; i < pts.size(); ++ i)
423 out.emplace_back(unscale<float>(pts[i].x()),
424 unscale<float>(pts[i].y()));
425 }
426}
Polygon contour
Definition ExPolygon.hpp:42
Polygons holes
Definition ExPolygon.hpp:43
#define scale_(val)
Definition libslic3r.h:106
T unscale(Q v)
Definition libslic3r.h:138
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30

References Slic3r::contour(), Slic3r::ExPolygon::contour, Slic3r::ExPolygon::holes, sample_expolygon_boundary(), scale_, and Slic3r::unscale().

Referenced by sample_expolygon_boundary(), and sample_expolygon_with_boundary().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sample_expolygon_with_boundary() [1/2]

std::vector< Vec2f > Slic3r::sla::sample_expolygon_with_boundary ( const ExPolygon & expoly,
float samples_per_mm2,
float samples_per_mm_boundary,
std::mt19937 & rng )
429{
430 std::vector<Vec2f> out = sample_expolygon(expoly, samples_per_mm2, rng);
431 sample_expolygon_boundary(expoly, samples_per_mm_boundary, out, rng);
432 return out;
433}
void sample_expolygon_boundary(const ExPolygon &expoly, float samples_per_mm, std::vector< Vec2f > &out, std::mt19937 &)
Definition SupportPointGenerator.cpp:411

References sample_expolygon(), sample_expolygon_boundary(), and sample_expolygon_with_boundary().

Referenced by sample_expolygon_with_boundary(), sample_expolygon_with_boundary(), and Slic3r::sla::SupportPointGenerator::uniformly_cover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sample_expolygon_with_boundary() [2/2]

std::vector< Vec2f > Slic3r::sla::sample_expolygon_with_boundary ( const ExPolygons & expolys,
float samples_per_mm2,
float samples_per_mm_boundary,
std::mt19937 & rng )
436{
437 std::vector<Vec2f> out;
438 for (const ExPolygon &expoly : expolys)
439 append(out, sample_expolygon_with_boundary(expoly, samples_per_mm2, samples_per_mm_boundary, rng));
440 return out;
441}
std::vector< Vec2f > sample_expolygon_with_boundary(const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
Definition SupportPointGenerator.cpp:428

References Slic3r::append(), and sample_expolygon_with_boundary().

Here is the call graph for this function:

◆ sphere()

indexed_triangle_set Slic3r::sla::sphere ( double rho,
Portion portion,
double fa )
14 {
15
16 indexed_triangle_set ret;
17
18 // prohibit close to zero radius
19 if(rho <= 1e-6 && rho >= -1e-6) return ret;
20
21 auto& vertices = ret.vertices;
22 auto& facets = ret.indices;
23
24 // Algorithm:
25 // Add points one-by-one to the sphere grid and form facets using relative
26 // coordinates. Sphere is composed effectively of a mesh of stacked circles.
27
28 // adjust via rounding to get an even multiple for any provided angle.
29 double angle = (2 * PI / floor(2*PI / fa) );
30
31 // Ring to be scaled to generate the steps of the sphere
32 std::vector<double> ring;
33
34 for (double i = 0; i < 2*PI; i+=angle) ring.emplace_back(i);
35
36 const auto sbegin = size_t(2*std::get<0>(portion)/angle);
37 const auto send = size_t(2*std::get<1>(portion)/angle);
38
39 const size_t steps = ring.size();
40 const double increment = 1.0 / double(steps);
41
42 // special case: first ring connects to 0,0,0
43 // insert and form facets.
44 if (sbegin == 0)
45 vertices.emplace_back(
46 Vec3f(0.f, 0.f, float(-rho + increment * sbegin * 2. * rho)));
47
48 auto id = coord_t(vertices.size());
49 for (size_t i = 0; i < ring.size(); i++) {
50 // Fixed scaling
51 const double z = -rho + increment*rho*2.0 * (sbegin + 1.0);
52 // radius of the circle for this step.
53 const double r = std::sqrt(std::abs(rho*rho - z*z));
54 Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
55 vertices.emplace_back(Vec3d(b(0), b(1), z).cast<float>());
56
57 if (sbegin == 0)
58 (i == 0) ? facets.emplace_back(coord_t(ring.size()), 0, 1) :
59 facets.emplace_back(id - 1, 0, id);
60 ++id;
61 }
62
63 // General case: insert and form facets for each step,
64 // joining it to the ring below it.
65 for (size_t s = sbegin + 2; s < send - 1; s++) {
66 const double z = -rho + increment * double(s * 2. * rho);
67 const double r = std::sqrt(std::abs(rho*rho - z*z));
68
69 for (size_t i = 0; i < ring.size(); i++) {
70 Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
71 vertices.emplace_back(Vec3d(b(0), b(1), z).cast<float>());
72 auto id_ringsize = coord_t(id - int(ring.size()));
73 if (i == 0) {
74 // wrap around
75 facets.emplace_back(id - 1, id, id + coord_t(ring.size() - 1) );
76 facets.emplace_back(id - 1, id_ringsize, id);
77 } else {
78 facets.emplace_back(id_ringsize - 1, id_ringsize, id);
79 facets.emplace_back(id - 1, id_ringsize - 1, id);
80 }
81 id++;
82 }
83 }
84
85 // special case: last ring connects to 0,0,rho*2.0
86 // only form facets.
87 if(send >= size_t(2*PI / angle)) {
88 vertices.emplace_back(0.f, 0.f, float(-rho + increment*send*2.0*rho));
89 for (size_t i = 0; i < ring.size(); i++) {
90 auto id_ringsize = coord_t(id - int(ring.size()));
91 if (i == 0) {
92 // third vertex is on the other side of the ring.
93 facets.emplace_back(id - 1, id_ringsize, id);
94 } else {
95 auto ci = coord_t(id_ringsize + coord_t(i));
96 facets.emplace_back(ci - 1, ci, id);
97 }
98 }
99 }
100 id++;
101
102 return ret;
103}
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67

References Slic3r::angle(), Slic3r::cast(), and PI.

Referenced by get_mesh(), and pinhead().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ spheric_to_dir() [1/4]

Vec3d Slic3r::sla::spheric_to_dir ( const std::array< double, 2 > & v)
inline
69{
70 return spheric_to_dir(v[0], v[1]);
71}
Vec3d spheric_to_dir(double polar, double azimuth)
Definition SupportTreeBuildsteps.hpp:51

References spheric_to_dir().

Here is the call graph for this function:

◆ spheric_to_dir() [2/4]

Vec3d Slic3r::sla::spheric_to_dir ( const std::pair< double, double > & v)
inline
64{
65 return spheric_to_dir(v.first, v.second);
66}

References spheric_to_dir().

Here is the call graph for this function:

◆ spheric_to_dir() [3/4]

Vec3d Slic3r::sla::spheric_to_dir ( const std::tuple< double, double > & v)
inline
58{
59 auto [plr, azm] = v;
60 return spheric_to_dir(plr, azm);
61}

References spheric_to_dir().

Here is the call graph for this function:

◆ spheric_to_dir() [4/4]

Vec3d Slic3r::sla::spheric_to_dir ( double polar,
double azimuth )
inline
52{
53 return {std::cos(azimuth) * std::sin(polar),
54 std::sin(azimuth) * std::sin(polar), std::cos(polar)};
55}

Referenced by Slic3r::sla::SupportTreeBuildsteps::connect_to_ground(), Slic3r::sla::SupportTreeBuildsteps::create_ground_pillar(), Slic3r::sla::SupportTreeBuildsteps::filter(), Slic3r::sla::SupportTreeBuildsteps::search_widening_path(), spheric_to_dir(), spheric_to_dir(), and spheric_to_dir().

Here is the caller graph for this function:

◆ swap_normals()

void Slic3r::sla::swap_normals ( indexed_triangle_set & its)
inline
106{
107 for (auto &face : its.indices)
108 std::swap(face(0), face(2));
109}

Referenced by generate_interior(), and Slic3r::SLAPrint::Steps::slice_model().

Here is the caller graph for this function:

◆ to_vec2()

Vec2d Slic3r::sla::to_vec2 ( const Vec3d & v3)
inline
23{ return {coord_t(v3(X)), coord_t(v3(Y))}; }

References X, and Y.

Referenced by Slic3r::sla::ConcaveHull::add_connector_rectangles().

Here is the caller graph for this function:

◆ to_vec3() [1/2]

Vec3d Slic3r::sla::to_vec3 ( const Vec2crd & v2)
inline
21{ return {double(v2(X)), double(v2(Y)), 0.}; }

References X, and Y.

Referenced by Slic3r::sla::ConcaveHull::add_connector_rectangles().

Here is the caller graph for this function:

◆ to_vec3() [2/2]

Vec3d Slic3r::sla::to_vec3 ( const Vec2d & v2)
inline
22{ return {v2(X), v2(Y), 0.}; }

References X, and Y.

Variable Documentation

◆ Colors< Color >::Black

template<class Color>
const Color Slic3r::sla::Colors< Color >::Black = Color{0}

◆ Colors< Color >::White

template<class Color>
const Color Slic3r::sla::Colors< Color >::White = Color{255}

◆ D_SP

const double Slic3r::sla::D_SP = 0.1

◆ DOWN

◆ HoleStickOutLength

float Slic3r::sla::HoleStickOutLength = 1.f
constexpr

◆ USE_FULL_CONCURRENCY

const constexpr bool Slic3r::sla::USE_FULL_CONCURRENCY = true
constexpr